Compare commits
	
		
			45 Commits 
		
	
	
		
			dependabot
			...
			master
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								 | 
						e12779d654 | 3 years ago | 
| 
							
							
								 | 
						ac590563a7 | 3 years ago | 
| 
							
							
								 | 
						8fc1d353c9 | 3 years ago | 
| 
							
							
								 | 
						35b64d74de | 3 years ago | 
| 
							
							
								 | 
						a064988f56 | 3 years ago | 
| 
							
							
								 | 
						adff361c11 | 3 years ago | 
| 
							
							
								 | 
						419e39eaaa | 3 years ago | 
| 
							
							
								 | 
						9d9cb3f2cb | 3 years ago | 
| 
							
							
								 | 
						dd802dccbb | 3 years ago | 
| 
							
							
								 | 
						1262bff671 | 3 years ago | 
| 
							
							
								 | 
						289737ed00 | 3 years ago | 
| 
							
							
								 | 
						dc7b491534 | 3 years ago | 
| 
							
							
								 | 
						eed0f5194c | 3 years ago | 
| 
							
							
								 | 
						e0599585be | 3 years ago | 
| 
							
							
								 | 
						42451f2cb0 | 3 years ago | 
| 
							
							
								 | 
						646162593e | 3 years ago | 
| 
							
							
								 | 
						200494fcf3 | 3 years ago | 
| 
							
							
								 | 
						fe5a7605f0 | 3 years ago | 
| 
							
							
								 | 
						f70351d8e5 | 3 years ago | 
| 
							
							
								 | 
						9e2f40383a | 3 years ago | 
| 
							
							
								 | 
						debe95791e | 3 years ago | 
| 
							
							
								 | 
						a3887825c9 | 3 years ago | 
| 
							
							
								 | 
						8a8f9ef7fe | 3 years ago | 
| 
							
							
								 | 
						8e325e6cde | 3 years ago | 
| 
							
							
								 | 
						92961cfa61 | 3 years ago | 
| 
							
							
								 | 
						8c25aab63c | 3 years ago | 
| 
							
							
								 | 
						0cc5084390 | 3 years ago | 
| 
							
							
								 | 
						4d98981485 | 3 years ago | 
| 
							
							
								 | 
						a7a1472533 | 3 years ago | 
| 
							
							
								 | 
						332d12bddf | 3 years ago | 
| 
							
							
								 | 
						6439824468 | 3 years ago | 
| 
							
							
								 | 
						42478f21d9 | 3 years ago | 
| 
							
							
								 | 
						2c67305f8a | 3 years ago | 
| 
							
							
								 | 
						79037d5248 | 3 years ago | 
| 
							
							
								 | 
						525ec097d7 | 3 years ago | 
| 
							
							
								 | 
						a35ca0b087 | 3 years ago | 
| 
							
							
								 | 
						d9ac93ccc1 | 3 years ago | 
| 
							
							
								 | 
						1ff3da6896 | 3 years ago | 
| 
							
							
								 | 
						cbad06e95d | 3 years ago | 
| 
							
							
								 | 
						b093d7133b | 3 years ago | 
| 
							
							
								 | 
						7aa0471ba9 | 3 years ago | 
| 
							
							
								 | 
						2224ce27c7 | 3 years ago | 
| 
							
							
								 | 
						d8b124c1a7 | 3 years ago | 
| 
							
							
								 | 
						d1a5d69ac8 | 3 years ago | 
| 
							
							
								 | 
						8a8d2f2400 | 3 years ago | 
@ -1,100 +1,63 @@ | 
				
			||||
##### 从git上面下载源码 | 
				
			||||
```shell | 
				
			||||
cd /data/ | 
				
			||||
git clone https://github.com/nineaiyu/FlyApps | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
 | 
				
			||||
### FlyApp 服务器搭建 [python3 环境] | 
				
			||||
 | 
				
			||||
##### 搭建python env 环境 | 
				
			||||
```shell | 
				
			||||
yum install python36 python36-devel  redis mariadb-server  mariadb-devel -y | 
				
			||||
python3 -m venv py3 | 
				
			||||
source py3/bin/activate | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
###### 安装pip包 | 
				
			||||
```shell | 
				
			||||
cd  fir_ser/ | 
				
			||||
pip install -U setuptools pip | 
				
			||||
pip install -r requirements.txt | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
###### 配置数据库 | 
				
			||||
``` | 
				
			||||
在 config.py 配置redis 和 mysql 数据库 | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
###### 迁移数据库 | 
				
			||||
```shell | 
				
			||||
#如果是mysql,需要做一下配置,如果是sqlite,需要升级sqlite | 
				
			||||
#记得根据配置创建数据库 | 
				
			||||
#create database flyapp default character set utf8 COLLATE utf8_general_ci; | 
				
			||||
#grant all on flyapp.* to flyuser@'127.0.0.1' identified by 'flypwd00oo.1'; | 
				
			||||
 | 
				
			||||
python manage.py makemigrations | 
				
			||||
python manage.py migrate | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
### FlyApp  zsign ipa重签名工具安装 | 
				
			||||
```shell | 
				
			||||
yum install openssl-devel -y | 
				
			||||
yum install gcc-c++ gcc -y | 
				
			||||
wget https://github.com/nineaiyu/zsign/archive/refs/tags/v1.1.2.tar.gz | 
				
			||||
tar xvf v1.1.2.tar.gz | 
				
			||||
cd zsign-1.1.2/ | 
				
			||||
g++ *.cpp common/*.cpp -lcrypto -O3 -std=c++11 -o zsign | 
				
			||||
cp zsign /usr/bin/ | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
### FlyApp web端搭建 | 
				
			||||
###### npm编译环境 | 
				
			||||
```shell | 
				
			||||
yum install npm | 
				
			||||
npm install -g n | 
				
			||||
n 12.13      # 安装12版本的node ,最新版本会有问题 | 
				
			||||
npm install -g yarn | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
###### 编译web端和下载页 | 
				
			||||
```shell | 
				
			||||
cd FlyApps/fir_client/ | 
				
			||||
vim  vue.config.js  #修改api接口地址 | 
				
			||||
# pro_base_env 正式环境信息 | 
				
			||||
# dev_base_env 开发环境信息 | 
				
			||||
 | 
				
			||||
yarn install | 
				
			||||
yarn build index  # web打包 | 
				
			||||
yarn build short  # 下载也打包 | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
 | 
				
			||||
###### web目录操作 | 
				
			||||
```shell | 
				
			||||
# web目录: /www/wwwroot/fly.dvcloud.xin/ | 
				
			||||
 | 
				
			||||
cd  /www/wwwroot/fly.dvcloud.xin/ | 
				
			||||
cp -a /data/FlyApps/fir_client/dist/*   . | 
				
			||||
cp -a /data/FlyApps/fir_download/dist/*  . | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
##### 更新sqllite | 
				
			||||
```shell | 
				
			||||
tar xvf sqlite-autoconf-3310100.tar.gz  | 
				
			||||
cd sqlite-autoconf-3310100 | 
				
			||||
 | 
				
			||||
./configure --prefix=/usr/local/sqlite | 
				
			||||
make -j4 | 
				
			||||
 | 
				
			||||
make install | 
				
			||||
rm -rf /usr/bin/sqlite3 | 
				
			||||
 | 
				
			||||
ln -s /usr/local/sqlite/bin/sqlite3   /usr/bin/sqlite3 | 
				
			||||
ll /usr/bin/sqlite3 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
echo "/usr/local/sqlite/lib" > /etc/ld.so.conf.d/sqlite3.conf | 
				
			||||
ldconfig  | 
				
			||||
 | 
				
			||||
``` | 
				
			||||
### 用与应用分发,苹果超级签名 | 
				
			||||
#### 部署前准备 | 
				
			||||
- 备案域名【至少需要一个域名,以下可通过子域名部署】 | 
				
			||||
  - API域名 | 
				
			||||
  - 前端web域名 | 
				
			||||
  - 下载页域名 | 
				
			||||
    - 下载页域名可配置多个 | 
				
			||||
  - 存储域名(使用阿里云oss存储) | 
				
			||||
- ssl证书 | 
				
			||||
    - API域名证书 | 
				
			||||
    - 存储域名证书(使用阿里云oss存储) | 
				
			||||
    - 前端web域名证书(可选) | 
				
			||||
- Centos8Stream 服务器 | 
				
			||||
    - 如果使用oss存储,则带宽为1M,若使用本地存储,则带宽越大越好 | 
				
			||||
    - 如果使用超级签,最低配置为2cpu 4G内存,若干不使用签名,则1cpu2G就行 | 
				
			||||
- 阿里云短信或极光短信服务【可选一个,主要用与注册,重置密码】 | 
				
			||||
  - 阿里云短信 | 
				
			||||
  - 极光短信 | 
				
			||||
- 邮箱服务【可选,用与注册,重置密码,通知信息】 | 
				
			||||
- 阿里云OSS存储【可选】 | 
				
			||||
    - [sts授权配置](https://help.aliyun.com/document_detail/100624.html) | 
				
			||||
- 阿里云CDN【可选,用与加速访问】 | 
				
			||||
- 极验验证【可选,滑动验证服务】 | 
				
			||||
- 微信公众号【可选,用与微信扫描登录】 | 
				
			||||
- 阿里云支付【可选,用与购买下载次数】 | 
				
			||||
- 微信支付【可选,用与购买下载次数】 | 
				
			||||
 | 
				
			||||
#### 自用搭建建议 | 
				
			||||
- 阿里云服务器需要1cpu 2G内存,无需系统盘,如果使用超级签,可以适当增加配置 | 
				
			||||
- 需要阿里云OSS存储和阿里云CDN,并且OSS存储和阿里云服务器部署同一个地区 | 
				
			||||
- 可以申请一个极验进行滑动验证,或者开启验证码验证 | 
				
			||||
- 阿里云备案域名:api和前端可以使用一个域名,下载页单独域名 | 
				
			||||
 | 
				
			||||
#### 部署必备资料 | 
				
			||||
- 域名证书 | 
				
			||||
  - web域名和证书 | 
				
			||||
  - api域名和证书 | 
				
			||||
  - 下载页域名(可配置证书) | 
				
			||||
  - 存储域名和证书 | 
				
			||||
    - 本地存储,则该域名和证书可以和api域名证书一致 | 
				
			||||
    - 阿里云oss存储 | 
				
			||||
      - 开启cdn,需要新域名和证书 | 
				
			||||
      - 不开启,无需域名和证书 | 
				
			||||
- Centos8Stream 服务器 | 
				
			||||
 | 
				
			||||
## 部署方式 | 
				
			||||
 | 
				
			||||
### 1.[Docker 部署](./doc/docker.md) 【推荐】 | 
				
			||||
 | 
				
			||||
### 2.[本地部署](./doc/local.md) | 
				
			||||
 | 
				
			||||
### 功能预览 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
@ -1,12 +0,0 @@ | 
				
			||||
#!/bin/bash | 
				
			||||
# | 
				
			||||
# | 
				
			||||
# shellcheck disable=SC2006 | 
				
			||||
s_path=`pwd` | 
				
			||||
 | 
				
			||||
#first build fir_client | 
				
			||||
docker pull node:14.17.3 | 
				
			||||
\cp -a build_client.sh fir_client/ | 
				
			||||
docker run --rm -v "${s_path}"/fir_client:/fir_client -it node:14.17.3  sh /fir_client/build_client.sh | 
				
			||||
 | 
				
			||||
cd "${s_path}"/fir_ser/ && docker build . -t flyapps | 
				
			||||
@ -1,7 +0,0 @@ | 
				
			||||
#!/bin/bash | 
				
			||||
# | 
				
			||||
# | 
				
			||||
 | 
				
			||||
cd /fir_client/ && yarn config set registry https://registry.npm.taobao.org && yarn install && yarn build | 
				
			||||
 | 
				
			||||
 | 
				
			||||
@ -0,0 +1,102 @@ | 
				
			||||
### Docker最小化部署前准备,如果使用超级签和云存储,需要使用阿里云的服务器 | 
				
			||||
系统|Centos 8 Stream 纯净系统 [2cpu 4G内存] | 
				
			||||
----|---- | 
				
			||||
域名|```app.hehelucky.cn``` | 
				
			||||
域名SSL证书| nginx 格式证书 [阿里云和腾讯云都可以申请免费ssl证书] | 
				
			||||
数据路径| ```/data``` | 
				
			||||
 | 
				
			||||
 | 
				
			||||
### 开始部署 | 
				
			||||
##### 1.从git上面下载源码 | 
				
			||||
``` | 
				
			||||
cd /data/ | 
				
			||||
dnf install git -y | 
				
			||||
git clone https://github.com/nineaiyu/flyapps | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
## 注意,下面展示的相对路径,都是以```/data/flyapps```为相对目录 | 
				
			||||
 | 
				
			||||
#### 2.docker环境安装 | 
				
			||||
``` | 
				
			||||
cd /data/flyapps/docker/init | 
				
			||||
sh init.sh | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
#### 3.配置域名和证书,如果有cdn或者oss,也要进行配置 | 
				
			||||
a.将域名证书通过```sftp软件```或者```rz命令```复制到```/data/flyapps/nginx.conf.d```目录中 | 
				
			||||
 | 
				
			||||
b.将域名证书分别重命名为 ```域名.pem``` 和 ```域名.key``` .本次使用的域名是 ```app.hehelucky.cn``` ,因此,证书名称类似如下 | 
				
			||||
```shell script | 
				
			||||
nginx.conf.d/app.hehelucky.cn.key | 
				
			||||
nginx.conf.d/app.hehelucky.cn.pem | 
				
			||||
``` | 
				
			||||
c.修改NGINX配置文件```nginx.conf.d/flyapps-vhost.conf```,将```server_name```字段修改为域名,将```ssl_certificate```和 | 
				
			||||
```ssl_certificate_key```修改为对应证书路径,修改之后,对应字段如下 | 
				
			||||
```shell | 
				
			||||
server_name     app.hehelucky.cn; | 
				
			||||
ssl_certificate        /etc/nginx/conf.d/app.hehelucky.cn.pem; | 
				
			||||
ssl_certificate_key    /etc/nginx/conf.d/app.hehelucky.cn.key; | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
####  4.配置api服务需要修改api和web域名,如果有需求,还可以配置 短信,邮箱,geetest,存储等信息 | 
				
			||||
##### fir_ser配置文件 ```fir_ser/config.py``` | 
				
			||||
```python | 
				
			||||
class DOMAINCONF(object): | 
				
			||||
    API_DOMAIN = "https://app.hehelucky.cn"  # 用与开启本地存储,上传应用配置 | 
				
			||||
    WEB_DOMAIN = "https://app.hehelucky.cn"  # 用于超级签跳转配置,该域名一般为前端页面域名 | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
##### fir_client配置文件 ```fir_client/vue.confjg.js``` | 
				
			||||
```javascript | 
				
			||||
const pro_base_env = { | 
				
			||||
    baseUrl: '/',       //该选项可以填写web-api的域名,类似 https://api.xxx.com/ | 
				
			||||
    index_static: '/',  //若配置cdn等加速,可以填写cdn加速域名 | 
				
			||||
    baseShortUrl: '/',  //该选项可以填写short-api的域名,也可以和web-api域名一样,类似 https://api.xxx.com/ | 
				
			||||
    short_static: '/short/',  //若配置cdn等加速,可以填写cdn加速域名 | 
				
			||||
    version: version, | 
				
			||||
}; | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
#####  构建静态资源 | 
				
			||||
``` | 
				
			||||
cd /data/flyapps/docker/scripts | 
				
			||||
sh build.sh | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
#####  启动所有服务 | 
				
			||||
``` | 
				
			||||
cd /data/flyapps/docker/scripts | 
				
			||||
sh start_all.sh | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
#####  关闭所有服务 | 
				
			||||
``` | 
				
			||||
cd /data/flyapps/docker/scripts | 
				
			||||
sh stop_all.sh | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
##### 根据提示创建默认管理用户,用与访问管理后台 | 
				
			||||
```shell | 
				
			||||
docker exec -it flyapps python manage.py createsuperuser | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
##### 测试访问 | 
				
			||||
- 在浏览器输入自己配置的域名 https://app.hehelucky.cn/ 进行访问 | 
				
			||||
- 管理后台访问 https://app.hehelucky.cn:3448/ 进行访问 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
##### 如果要使用本地的数据库和redis,api服务使用容器,需要修改文件```/data/flyapps/docker/flyapps/docker-compose.yml``` | 
				
			||||
```shell | 
				
			||||
    external_links: | 
				
			||||
        - mariadb:mariadb | 
				
			||||
        - redis:redis | 
				
			||||
``` | 
				
			||||
修改为 | 
				
			||||
```shell | 
				
			||||
    extra_hosts: | 
				
			||||
      - "mariadb:172.31.31.1" | 
				
			||||
      - "redis:172.31.31.1" | 
				
			||||
``` | 
				
			||||
并将```nginx:```下面的配置注释掉 | 
				
			||||
 | 
				
			||||
同时还需要修改mariadb和redis授权 | 
				
			||||
| 
		 After Width: | Height: | Size: 77 KiB  | 
| 
		 After Width: | Height: | Size: 77 KiB  | 
| 
		 After Width: | Height: | Size: 53 KiB  | 
| 
		 After Width: | Height: | Size: 54 KiB  | 
| 
		 After Width: | Height: | Size: 51 KiB  | 
| 
		 After Width: | Height: | Size: 52 KiB  | 
| 
		 After Width: | Height: | Size: 29 KiB  | 
| 
		 After Width: | Height: | Size: 70 KiB  | 
| 
		 After Width: | Height: | Size: 44 KiB  | 
| 
		 After Width: | Height: | Size: 57 KiB  | 
| 
		 After Width: | Height: | Size: 56 KiB  | 
@ -0,0 +1,166 @@ | 
				
			||||
### 本地部署前准备 | 
				
			||||
系统 | Centos 8 Stream [2cpu 4G内存] | 
				
			||||
----|---- | 
				
			||||
域名|```app.hehelucky.cn``` | 
				
			||||
域名SSL证书| nginx 格式证书 [阿里云和腾讯云都可以申请免费ssl证书] | 
				
			||||
数据路径| ```/data``` | 
				
			||||
 | 
				
			||||
 | 
				
			||||
##### 从git上面下载源码 | 
				
			||||
```shell | 
				
			||||
cd /data/ | 
				
			||||
dnf install git gcc zip unzip -y | 
				
			||||
git clone https://github.com/nineaiyu/flyapps | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
 | 
				
			||||
### flyapps 本地部署 [python3 环境] | 
				
			||||
 | 
				
			||||
##### 搭建python env 环境 | 
				
			||||
```shell | 
				
			||||
dnf install python39 python39-devel  redis mariadb-server  mariadb-devel -y | 
				
			||||
python3.9 -m venv py39 | 
				
			||||
source py39/bin/activate | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
###### 安装pip包 | 
				
			||||
```shell | 
				
			||||
cd /data/flyapps/fir_ser/ | 
				
			||||
pip install -U setuptools pip -i https://pypi.tuna.tsinghua.edu.cn/simple/ | 
				
			||||
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
#### 配置数据库 | 
				
			||||
##### 启动mariadb数据库 | 
				
			||||
```shell | 
				
			||||
systemctl restart mariadb | 
				
			||||
systemctl enable mariadb | 
				
			||||
``` | 
				
			||||
##### 创建mysql数据库 | 
				
			||||
```shell | 
				
			||||
mysql | 
				
			||||
``` | 
				
			||||
执行下面mysql命令 | 
				
			||||
```mariadb | 
				
			||||
create database flyapps default character set utf8 COLLATE utf8_general_ci; | 
				
			||||
grant all on flyapps.* to flyuser@'127.0.0.1' identified by 'KGzKjZpWBp4R4RSa'; | 
				
			||||
``` | 
				
			||||
##### 启动redis数据库 | 
				
			||||
```shell | 
				
			||||
echo 'requirepass nineven' >> /etc/redis.conf  # 配置授权密码 | 
				
			||||
systemctl restart redis | 
				
			||||
systemctl enable redis | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
### flyapps  zsign ipa重签名工具安装 | 
				
			||||
```shell | 
				
			||||
dnf install openssl-devel -y | 
				
			||||
dnf install gcc-c++ gcc -y | 
				
			||||
cd /data/flyapps/fir_ser/ | 
				
			||||
tar xvf zsign-1.1.2.tar.gz | 
				
			||||
cd zsign-1.1.2/ | 
				
			||||
g++ *.cpp common/*.cpp -lcrypto -O3 -std=c++11 -o /usr/bin/zsign | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
 | 
				
			||||
####  配置api服务需要修改api和web域名,如果有需求,还可以配置 短信,邮箱,geetest,存储等信息 | 
				
			||||
##### fir_ser配置文件 ```fir_ser/config.py``` | 
				
			||||
```python | 
				
			||||
class DOMAINCONF(object): | 
				
			||||
    API_DOMAIN = "https://app.hehelucky.cn"  # 用与开启本地存储,上传应用配置 | 
				
			||||
    WEB_DOMAIN = "https://app.hehelucky.cn"  # 用于超级签跳转配置,该域名一般为前端页面域名 | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
##### fir_client配置文件 ```fir_client/vue.confjg.js``` | 
				
			||||
```javascript | 
				
			||||
const pro_base_env = { | 
				
			||||
    baseUrl: '/',       //该选项可以填写web-api的域名,类似 https://api.xxx.com/ | 
				
			||||
    index_static: '/',  //若配置cdn等加速,可以填写cdn加速域名 | 
				
			||||
    baseShortUrl: '/',  //该选项可以填写short-api的域名,也可以和web-api域名一样,类似 https://api.xxx.com/ | 
				
			||||
    short_static: '/short/',  //若配置cdn等加速,可以填写cdn加速域名 | 
				
			||||
    version: version, | 
				
			||||
}; | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
### flyapps web端搭建 | 
				
			||||
###### npm编译环境 | 
				
			||||
```shell | 
				
			||||
dnf install npm -y | 
				
			||||
npm install -g n | 
				
			||||
n 12.13      # 安装12版本的node或者14版本 ,最新版本会有问题 | 
				
			||||
npm install -g yarn | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
###### 编译web端和下载页 | 
				
			||||
```shell | 
				
			||||
cd /data/flyapps/fir_client/ | 
				
			||||
vim  vue.config.js  #修改api接口地址 | 
				
			||||
# pro_base_env 正式环境信息 | 
				
			||||
# dev_base_env 开发环境信息 | 
				
			||||
 | 
				
			||||
yarn install | 
				
			||||
yarn build index  # 前端打包,输出目录 dist_index | 
				
			||||
yarn build short  # 下载页打包,输出目录 dist_short | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
###### 编译web管理后台 | 
				
			||||
```shell | 
				
			||||
cd /data/flyapps/fir_admin/ | 
				
			||||
yarn install | 
				
			||||
yarn build:prod  # 下载页打包,输出目录 dist | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
### nginx配置 | 
				
			||||
##### 安装nginx | 
				
			||||
```shell | 
				
			||||
dnf install nginx -y | 
				
			||||
``` | 
				
			||||
##### 将域名ssl证书解压到```/etc/nginx/conf.d/``` 目录中,并重命名为```域名.pem```,```域名.key```格式 | 
				
			||||
##### 拷贝虚拟主机配置文件 | 
				
			||||
```shell | 
				
			||||
cp /data/flyapps/nginx.conf.d/flyapps-vhost.conf /etc/nginx/conf.d/ | 
				
			||||
``` | 
				
			||||
1.创建web目录,并将打包好的web复制该目录 | 
				
			||||
```shell | 
				
			||||
mkdir -pv /data/{fir_client/short,fir_admin} | 
				
			||||
cp -a /data/flyapps/fir_client/dist_index/*  /data/fir_client/ | 
				
			||||
cp -a /data/flyapps/fir_client/dist_short/*  /data/fir_client/short/ | 
				
			||||
cp -a /data/flyapps/fir_admin/dist/* /data/fir_admin/ | 
				
			||||
chown nginx.nginx -R /data/{fir_client,fir_admin} | 
				
			||||
``` | 
				
			||||
2.启动nginx服务 | 
				
			||||
```shell | 
				
			||||
nginx -t | 
				
			||||
systemctl restart nginx | 
				
			||||
systemctl enable nginx | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
##### 添加redis和mariadb uwsgi本地解析 | 
				
			||||
```shell | 
				
			||||
echo '127.0.0.1 mariadb redis flyapps' >> /etc/hosts | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
###### 迁移数据库 | 
				
			||||
```shell | 
				
			||||
cd /data/flyapps/fir_ser/ | 
				
			||||
python manage.py makemigrations | 
				
			||||
python manage.py migrate | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
#### 启动api服务 | 
				
			||||
```shell | 
				
			||||
echo 'net.core.somaxconn=1024' >> /etc/sysctl.conf | 
				
			||||
sysctl -p | 
				
			||||
cd /data/flyapps/fir_ser/ | 
				
			||||
python manage.py start all -u nginx -usm 1 -d | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
##### 根据提示创建默认管理用户,用与访问管理后台 | 
				
			||||
```shell | 
				
			||||
python manage.py createsuperuser | 
				
			||||
``` | 
				
			||||
- 需要输入用户名,邮箱和密码 | 
				
			||||
- 用户名和密码用与登录管理后台 | 
				
			||||
- 邮箱和密码用与登录前端web | 
				
			||||
@ -1,51 +0,0 @@ | 
				
			||||
##### 从git上面下载源码 | 
				
			||||
``` | 
				
			||||
cd /data/ | 
				
			||||
git clone https://github.com/nineaiyu/FlyApps | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
#### docker环境安装 [centos7] | 
				
			||||
``` | 
				
			||||
yum install epel-release -y | 
				
			||||
yum clean all && yum makecache | 
				
			||||
yum install docker -y | 
				
			||||
 | 
				
			||||
``` | 
				
			||||
#### 配置域名和证书,如果有cdn或者oss,也要进行配置 | 
				
			||||
```shell script | 
				
			||||
nginx.conf.d/app.hehelucky.cn.key | 
				
			||||
nginx.conf.d/app.hehelucky.cn.pem | 
				
			||||
nginx.conf.d/flyapps-vhost.conf | 
				
			||||
``` | 
				
			||||
### api服务需要修改api和web域名,短信,邮箱,geetest,存储等信息 | 
				
			||||
```shell script | 
				
			||||
vim fir_ser/config.py | 
				
			||||
 | 
				
			||||
API_DOMAIN = "https://app.hehelucky.cn" | 
				
			||||
WEB_DOMAIN = "https://app.hehelucky.cn" | 
				
			||||
MOBILEPROVISION = "https://ali-static.jappstore.com/embedded.mobileprovision" | 
				
			||||
 | 
				
			||||
``` | 
				
			||||
### web页面需要修改指定api域名 | 
				
			||||
```vuejs | 
				
			||||
vim fir_client/vue.config.js | 
				
			||||
 | 
				
			||||
const pro_base_env = { | 
				
			||||
    baseUrl: 'https://flyapps.cn', | 
				
			||||
    index_static: 'https://static.flyapps.cn/index/', | 
				
			||||
    baseShortUrl: 'https://flyapps.top', | 
				
			||||
    short_static: 'https://static.flyapps.top/short/', | 
				
			||||
}; | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
#####  构建静态资源和api服务 | 
				
			||||
``` | 
				
			||||
sh build.sh | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#####  启动所有服务 | 
				
			||||
``` | 
				
			||||
sh start.sh | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
@ -0,0 +1,67 @@ | 
				
			||||
version: '3.2' | 
				
			||||
 | 
				
			||||
services: | 
				
			||||
  buildflyapps: | 
				
			||||
    image: 'flyapps' | 
				
			||||
    build: | 
				
			||||
      context: ../../fir_ser | 
				
			||||
      dockerfile: Dockerfile | 
				
			||||
    command: | 
				
			||||
        - echo | 
				
			||||
        - success | 
				
			||||
 | 
				
			||||
  buildclient: | 
				
			||||
    container_name: buildclient | 
				
			||||
    image: 'node:14.17.3' | 
				
			||||
    working_dir: /fir_client | 
				
			||||
    volumes: | 
				
			||||
      - /etc/localtime:/etc/localtime:ro | 
				
			||||
      - ../../fir_client:/fir_client | 
				
			||||
      - ../../data/web/:/web | 
				
			||||
    command: | 
				
			||||
        - bash | 
				
			||||
        - -c | 
				
			||||
        - yarn config set registry https://registry.npm.taobao.org && yarn install && yarn build index && yarn build short && ([ ! -e /web/fir_client ] && \cp -a dist_index /web/fir_client || \cp -a dist_index/* /web/fir_client/) && ([ ! -e /web/fir_client/short ] && \cp -a dist_short /web/fir_client/short || \cp -a dist_short/* /web/fir_client/short/)  && echo build success | 
				
			||||
 | 
				
			||||
  buildindex: | 
				
			||||
    container_name: buildindex | 
				
			||||
    image: 'node:14.17.3' | 
				
			||||
    working_dir: /fir_client | 
				
			||||
    volumes: | 
				
			||||
      - /etc/localtime:/etc/localtime:ro | 
				
			||||
      - ../../fir_client:/fir_client | 
				
			||||
      - ../../data/web/:/web | 
				
			||||
    command: | 
				
			||||
        - bash | 
				
			||||
        - -c | 
				
			||||
        - yarn config set registry https://registry.npm.taobao.org && yarn install && yarn build index && ([ ! -e /web/fir_index ] && \cp -a dist_index /web/fir_index || \cp -a dist_index/* /web/fir_index/) && echo build success | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
  buildshort: | 
				
			||||
    container_name: buildshort | 
				
			||||
    image: 'node:14.17.3' | 
				
			||||
    working_dir: /fir_client | 
				
			||||
    volumes: | 
				
			||||
      - /etc/localtime:/etc/localtime:ro | 
				
			||||
      - ../../fir_client:/fir_client | 
				
			||||
      - ../../data/web/:/web | 
				
			||||
    command: | 
				
			||||
        - sh | 
				
			||||
        - -c | 
				
			||||
        - yarn config set registry https://registry.npm.taobao.org && yarn install && yarn build short && ([ ! -e /web/fir_short ] && \cp -a dist_short /web/fir_short || \cp -a dist_short/* /web/fir_short/) && echo build success | 
				
			||||
 | 
				
			||||
 | 
				
			||||
  buildadmin: | 
				
			||||
    container_name: buildadmin | 
				
			||||
    image: 'node:14.17.3' | 
				
			||||
    working_dir: /fir_admin | 
				
			||||
    volumes: | 
				
			||||
      - /etc/localtime:/etc/localtime:ro | 
				
			||||
      - ../../fir_admin:/fir_admin | 
				
			||||
      - ../../data/web/:/web | 
				
			||||
    command: | 
				
			||||
        - sh | 
				
			||||
        - -c | 
				
			||||
        - yarn config set registry https://registry.npm.taobao.org && yarn install && yarn build:prod && ([ ! -e /web/fir_admin ] && \cp -a dist /web/fir_admin || \cp -a dist/* /web/fir_admin/) && echo build success | 
				
			||||
 | 
				
			||||
@ -0,0 +1,31 @@ | 
				
			||||
version: '3' | 
				
			||||
 | 
				
			||||
networks: | 
				
			||||
    flyapps: | 
				
			||||
        external: true | 
				
			||||
        name: flyapps | 
				
			||||
 | 
				
			||||
services: | 
				
			||||
  flyapps: | 
				
			||||
    container_name: flyapps | 
				
			||||
    restart: always | 
				
			||||
    image: 'nineven/flyapps' | 
				
			||||
    working_dir: /data/fir_ser | 
				
			||||
    volumes: | 
				
			||||
      - /etc/localtime:/etc/localtime:ro | 
				
			||||
      - ../../fir_ser:/data/fir_ser | 
				
			||||
      - ../../data/flyapps/files:/data/fir_ser/files | 
				
			||||
      - ../../data/logs/flyapps/:/data/fir_ser/logs | 
				
			||||
      - ../../data/flyapps/supersign/:/data/fir_ser/supersign | 
				
			||||
      - ../../nginx.conf.d:/data/cert | 
				
			||||
    networks: | 
				
			||||
         flyapps: | 
				
			||||
           ipv4_address: 172.31.31.100 | 
				
			||||
    external_links: | 
				
			||||
        - mariadb:mariadb  | 
				
			||||
        - redis:redis | 
				
			||||
    sysctls: | 
				
			||||
        - net.core.somaxconn=4096 | 
				
			||||
    extra_hosts: | 
				
			||||
      - "mariadb:172.31.31.1" | 
				
			||||
      - "redis:172.31.31.1" | 
				
			||||
@ -0,0 +1,48 @@ | 
				
			||||
version: '3' | 
				
			||||
 | 
				
			||||
networks: | 
				
			||||
    flyapps: | 
				
			||||
        external: true | 
				
			||||
        name: flyapps | 
				
			||||
 | 
				
			||||
services: | 
				
			||||
  flyapps: | 
				
			||||
    container_name: flyapps | 
				
			||||
    restart: always | 
				
			||||
    image: 'nineven/flyapps' | 
				
			||||
    working_dir: /data/fir_ser | 
				
			||||
    volumes: | 
				
			||||
      - /etc/localtime:/etc/localtime:ro | 
				
			||||
      - ../../fir_ser:/data/fir_ser | 
				
			||||
      - ../../data/flyapps/files:/data/fir_ser/files | 
				
			||||
      - ../../data/logs/flyapps/:/data/fir_ser/logs | 
				
			||||
      - ../../data/flyapps/supersign/:/data/fir_ser/supersign | 
				
			||||
      - ../../nginx.conf.d:/data/cert | 
				
			||||
    networks: | 
				
			||||
         flyapps: | 
				
			||||
           ipv4_address: 172.31.31.100 | 
				
			||||
    external_links: | 
				
			||||
        - mariadb:mariadb  | 
				
			||||
        - redis:redis | 
				
			||||
    sysctls: | 
				
			||||
        - net.core.somaxconn=4096 | 
				
			||||
  nginx: | 
				
			||||
    container_name: nginx | 
				
			||||
    restart: always | 
				
			||||
    image: 'nginx:1.21.3' | 
				
			||||
    volumes: | 
				
			||||
      - /etc/localtime:/etc/localtime:ro | 
				
			||||
      - ../../data/web:/data | 
				
			||||
      - ../../nginx.conf.d:/etc/nginx/conf.d | 
				
			||||
      - ../../data/logs/nginx:/var/log/nginx | 
				
			||||
    networks: | 
				
			||||
         flyapps: | 
				
			||||
           ipv4_address: 172.31.31.200 | 
				
			||||
    ports: | 
				
			||||
        - 80:80 | 
				
			||||
        - 443:443 | 
				
			||||
        - 3448:3448 | 
				
			||||
    external_links: | 
				
			||||
        - flyapps:flyapps | 
				
			||||
    depends_on: | 
				
			||||
        - flyapps | 
				
			||||
@ -0,0 +1,7 @@ | 
				
			||||
#!/bin/bash | 
				
			||||
# | 
				
			||||
# | 
				
			||||
 | 
				
			||||
for i in nginx flyapps mariadb redis buildclient buildshort buildadmin ;do echo $i;docker rm -f $i;done | 
				
			||||
 | 
				
			||||
docker network rm flyapps | 
				
			||||
@ -0,0 +1,10 @@ | 
				
			||||
#!/bin/bash | 
				
			||||
# | 
				
			||||
# | 
				
			||||
 | 
				
			||||
 | 
				
			||||
docker pull 'bitnami/mariadb:10.7.3' | 
				
			||||
docker pull 'bitnami/redis:6.2.7' | 
				
			||||
docker pull 'nginx:1.21.3' | 
				
			||||
docker pull 'nineven/flyapps:latest' | 
				
			||||
docker pull 'node:14.17.3' | 
				
			||||
@ -0,0 +1,24 @@ | 
				
			||||
#!/bin/bash | 
				
			||||
# | 
				
			||||
# | 
				
			||||
 | 
				
			||||
which dockerd | 
				
			||||
if [ $? -ne 0 ];then | 
				
			||||
	dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo | 
				
			||||
	dnf install docker-ce -y | 
				
			||||
fi | 
				
			||||
#which docker-compose | 
				
			||||
#if [ $? -ne 0 ];then | 
				
			||||
#	curl -L https://get.daocloud.io/docker/compose/releases/download/v2.5.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose | 
				
			||||
#	chmod +x /usr/local/bin/docker-compose | 
				
			||||
#fi | 
				
			||||
 | 
				
			||||
data_path="$(dirname $(dirname `pwd`))/data" | 
				
			||||
mkdir -pv ${data_path}/{flyapps/files,web,mariadb,redis,logs/{mariadb,nginx,flyapps}} | 
				
			||||
\cp $(dirname $(dirname `pwd`))/fir_ser/files/head_img.jpeg ${data_path}/flyapps/files/ | 
				
			||||
chown 1001.1001 -R ${data_path}/{flyapps,web,mariadb,redis,logs/{mariadb,nginx,flyapps}} | 
				
			||||
chown 101.101 -R ${data_path}/{flyapps,logs/flyapps} | 
				
			||||
systemctl start docker && docker network create flyapps --driver bridge --subnet=172.31.31.0/24 --gateway=172.31.31.1 | 
				
			||||
systemctl enable docker | 
				
			||||
systemctl status docker | 
				
			||||
 | 
				
			||||
@ -0,0 +1 @@ | 
				
			||||
Asia/Shanghai | 
				
			||||
@ -0,0 +1,43 @@ | 
				
			||||
version: '3.2' | 
				
			||||
 | 
				
			||||
  | 
				
			||||
 | 
				
			||||
networks: | 
				
			||||
    flyapps: | 
				
			||||
        external: true | 
				
			||||
        name: flyapps | 
				
			||||
 | 
				
			||||
services: | 
				
			||||
 | 
				
			||||
  mariadb: | 
				
			||||
    image: bitnami/mariadb:10.7.3 | 
				
			||||
    container_name: mariadb  | 
				
			||||
    restart: always | 
				
			||||
    environment: | 
				
			||||
            - MARIADB_ROOT_PASSWORD=rootIPD.xx2.19 | 
				
			||||
            - MARIADB_DATABASE=flyapps | 
				
			||||
            - MARIADB_USER=flyuser | 
				
			||||
            - MARIADB_PASSWORD=KGzKjZpWBp4R4RSa | 
				
			||||
              #- ALLOW_EMPTY_PASSWORD=yes | 
				
			||||
            - MARIADB_ENABLE_SLOW_QUERY=1 | 
				
			||||
            - MARIADB_LONG_QUERY_TIME=3 | 
				
			||||
            - MARIADB_SKIP_TEST_DB=yes | 
				
			||||
            - MARIADB_EXTRA_FLAGS=--max-connect-errors=3000 --max_connections=30000 | 
				
			||||
    ports: | 
				
			||||
      - 3306:3306 | 
				
			||||
    networks: | 
				
			||||
         flyapps: | 
				
			||||
           ipv4_address: 172.31.31.90 | 
				
			||||
    volumes: | 
				
			||||
       - ../init/timezone:/etc/timezone:ro | 
				
			||||
       - /etc/localtime:/etc/localtime:ro | 
				
			||||
       - ../../data/mariadb:/bitnami/mariadb/data | 
				
			||||
       - ../../data/logs/mariadb:/data/logs/mariadb | 
				
			||||
       - ./server.cnf:/opt/bitnami/mariadb/conf/my_custom.cnf:ro | 
				
			||||
 | 
				
			||||
#  adminer: | 
				
			||||
#    image: adminer | 
				
			||||
#    ports: | 
				
			||||
#      - 8080:8080 | 
				
			||||
#    networks: | 
				
			||||
#         - fungame | 
				
			||||
@ -0,0 +1,108 @@ | 
				
			||||
# | 
				
			||||
# These groups are read by MariaDB server. | 
				
			||||
# Use it for options that only the server (but not clients) should see | 
				
			||||
# | 
				
			||||
# See the examples of server my.cnf files in /usr/share/mysql/ | 
				
			||||
# | 
				
			||||
 | 
				
			||||
 | 
				
			||||
# this is only for the mysqld standalone daemon | 
				
			||||
[mysqld] | 
				
			||||
binlog_cache_size = 192K | 
				
			||||
thread_stack = 384K | 
				
			||||
join_buffer_size = 4096K | 
				
			||||
query_cache_type = 1 | 
				
			||||
max_heap_table_size = 1024M | 
				
			||||
 | 
				
			||||
default_storage_engine = InnoDB | 
				
			||||
performance_schema_max_table_instances = 400 | 
				
			||||
table_definition_cache = 400 | 
				
			||||
skip-external-locking | 
				
			||||
key_buffer_size = 512M | 
				
			||||
max_allowed_packet = 1G | 
				
			||||
table_open_cache = 1024 | 
				
			||||
sort_buffer_size = 2048K | 
				
			||||
net_buffer_length = 4K | 
				
			||||
read_buffer_size = 2048K | 
				
			||||
read_rnd_buffer_size = 1024K | 
				
			||||
myisam_sort_buffer_size = 16M | 
				
			||||
thread_cache_size = 192 | 
				
			||||
query_cache_size = 256M | 
				
			||||
tmp_table_size = 1024M | 
				
			||||
sql-mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES | 
				
			||||
 | 
				
			||||
 | 
				
			||||
max_connections = 30000 | 
				
			||||
max_connect_errors = 1000 | 
				
			||||
open_files_limit = 65535 | 
				
			||||
 | 
				
			||||
expire_logs_days = 10 | 
				
			||||
#log_queries_not_using_indexes=on | 
				
			||||
 | 
				
			||||
character-set-client-handshake = FALSE | 
				
			||||
character-set-server = utf8mb4 | 
				
			||||
collation-server = utf8mb4_general_ci | 
				
			||||
init_connect='SET NAMES utf8mb4' | 
				
			||||
#character-set-server=utf8 | 
				
			||||
skip_name_resolve | 
				
			||||
event_scheduler=1 | 
				
			||||
#skip-grant-tables | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#innodb_data_home_dir = /var/lib/mysql/ | 
				
			||||
#innodb_data_file_path = ibdata1:10M:autoextend | 
				
			||||
#innodb_log_group_home_dir = /var/lib/mysql/ | 
				
			||||
#innodb_buffer_pool_size = 1024M | 
				
			||||
#innodb_log_file_size = 128M | 
				
			||||
#innodb_log_buffer_size = 32M | 
				
			||||
#innodb_flush_log_at_trx_commit = 1 | 
				
			||||
#innodb_lock_wait_timeout = 50 | 
				
			||||
#innodb_max_dirty_pages_pct = 90 | 
				
			||||
#innodb_read_io_threads = 4 | 
				
			||||
#innodb_write_io_threads = 4 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
# | 
				
			||||
# Allow server to accept connections on all interfaces. | 
				
			||||
# | 
				
			||||
#bind-address=0.0.0.0 | 
				
			||||
# | 
				
			||||
# this is only for embedded server | 
				
			||||
# This group is only read by MariaDB servers, not by MySQL. | 
				
			||||
# If you use the same .cnf file for MySQL and MariaDB, | 
				
			||||
# you can put MariaDB-only options here | 
				
			||||
[mariadb] | 
				
			||||
#autoset_open_files_limit | 
				
			||||
#enable_slow_query_log | 
				
			||||
 | 
				
			||||
#audit | 
				
			||||
plugin_load_add=server_audit | 
				
			||||
server_audit_logging=on | 
				
			||||
server_audit_events=connect,query | 
				
			||||
server_audit=force_plus_permanent | 
				
			||||
server_audit_events=QUERY_DDL,QUERY_DML,CONNECT | 
				
			||||
server_audit_output_type=file | 
				
			||||
server_audit_file_rotate_now=on | 
				
			||||
server_audit_file_rotations=9 | 
				
			||||
server_audit_file_rotate_size=1G | 
				
			||||
server_audit_file_path=/data/logs/mariadb | 
				
			||||
 | 
				
			||||
 | 
				
			||||
log_error=/data/logs/mariadb/mariadb.err.log | 
				
			||||
 | 
				
			||||
log_output=FILE | 
				
			||||
slow_query_log | 
				
			||||
long_query_time=3 | 
				
			||||
slow_query_log_file=/data/logs/mariadb/mariadb-slow.log | 
				
			||||
log_queries_not_using_indexes=ON  #Logging Queries That Don't Use Indexes | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#server_id=2 | 
				
			||||
log-bin=/data/logs/mariadb/mysql-bin | 
				
			||||
 | 
				
			||||
# This group is only read by MariaDB-10.5 servers. | 
				
			||||
# If you use the same .cnf file for MariaDB of different versions, | 
				
			||||
# use this group for options that older servers don't understand | 
				
			||||
 | 
				
			||||
@ -0,0 +1,25 @@ | 
				
			||||
version: '3.2' | 
				
			||||
 | 
				
			||||
 | 
				
			||||
networks: | 
				
			||||
    flyapps: | 
				
			||||
        external: true | 
				
			||||
        name: flyapps | 
				
			||||
 | 
				
			||||
services: | 
				
			||||
  redis: | 
				
			||||
    image: 'bitnami/redis:6.2.7' | 
				
			||||
    container_name: redis | 
				
			||||
    restart: always | 
				
			||||
    volumes: | 
				
			||||
         - ../init/timezone:/etc/timezone:ro | 
				
			||||
         - /etc/localtime:/etc/localtime:ro | 
				
			||||
         - ../../data/redis:/bitnami/redis/data | 
				
			||||
    environment: | 
				
			||||
      #- REDIS_REPLICATION_MODE=master | 
				
			||||
      #- ALLOW_EMPTY_PASSWORD=yes | 
				
			||||
      - REDIS_PASSWORD=nineven | 
				
			||||
    networks: | 
				
			||||
      - flyapps | 
				
			||||
    #ports: | 
				
			||||
    #  - 6379:6379 | 
				
			||||
@ -0,0 +1,6 @@ | 
				
			||||
#!/bin/bash | 
				
			||||
# | 
				
			||||
# | 
				
			||||
 | 
				
			||||
cd ../build/ | 
				
			||||
docker compose up buildclient buildadmin | 
				
			||||
@ -0,0 +1,9 @@ | 
				
			||||
#!/bin/bash | 
				
			||||
# | 
				
			||||
# | 
				
			||||
 | 
				
			||||
cd ../mariadb/ && docker compose up -d | 
				
			||||
cd ../redis/ && docker compose up -d | 
				
			||||
 | 
				
			||||
cd ../flyapps/ && docker compose up -d | 
				
			||||
docker logs -f flyapps | 
				
			||||
@ -0,0 +1,10 @@ | 
				
			||||
#!/bin/bash | 
				
			||||
# | 
				
			||||
# | 
				
			||||
 | 
				
			||||
 | 
				
			||||
cd ../flyapps/ && docker compose down | 
				
			||||
 | 
				
			||||
cd ../redis/ && docker compose down | 
				
			||||
 | 
				
			||||
cd ../mariadb/ && docker compose down | 
				
			||||
| 
		 After Width: | Height: | Size: 71 KiB  | 
| 
		 Before Width: | Height: | Size: 22 KiB  | 
@ -0,0 +1,470 @@ | 
				
			||||
<template> | 
				
			||||
  <el-main> | 
				
			||||
 | 
				
			||||
    <el-dialog | 
				
			||||
        :close-on-click-modal="false" | 
				
			||||
        :close-on-press-escape="false" | 
				
			||||
        :visible.sync="configVisible" | 
				
			||||
        center | 
				
			||||
        title="下载页部署配置" | 
				
			||||
        width="666px"> | 
				
			||||
 | 
				
			||||
 | 
				
			||||
      <el-card v-for="info in config_lists" :key="info.key" class="box-card" shadow="hover" | 
				
			||||
               style="margin-bottom: 20px"> | 
				
			||||
        <div slot="header" class="clearfix"> | 
				
			||||
          <span><el-tag size="medium" type="info">配置KEY</el-tag> <el-tag size="medium">{{ info.key }}</el-tag></span> | 
				
			||||
          <div style="float: right"> | 
				
			||||
            <el-switch | 
				
			||||
                v-model="info.value" | 
				
			||||
                active-color="#13ce66" | 
				
			||||
                active-text="启用" | 
				
			||||
                active-value="true" | 
				
			||||
                inactive-color="#ff4949" | 
				
			||||
                inactive-text="关闭" | 
				
			||||
                inactive-value="false" | 
				
			||||
                @change="changeConfig(info)"> | 
				
			||||
            </el-switch> | 
				
			||||
          </div> | 
				
			||||
        </div> | 
				
			||||
        <el-tag size="medium" type="info">描述信息</el-tag> | 
				
			||||
        {{ info.title }} | 
				
			||||
      </el-card> | 
				
			||||
      <el-divider></el-divider> | 
				
			||||
      <el-card style="margin-top: 20px"> | 
				
			||||
        <div slot="header" class="clearfix"> | 
				
			||||
          <el-tag size="medium" type="success">下载页源码及操作文档</el-tag> | 
				
			||||
        </div> | 
				
			||||
        <div v-if="short_download_list.length>0"> | 
				
			||||
          <div style="margin: 10px" v-for="short_download_uri in short_download_list" :key="short_download_uri.key"> | 
				
			||||
            <el-tag size="medium" type="info">{{short_download_uri.title}}</el-tag> | 
				
			||||
            <el-link style="margin-left: 10px" :href="short_download_uri.value" target="_blank">点击下载</el-link> | 
				
			||||
        </div> | 
				
			||||
        </div> | 
				
			||||
      </el-card> | 
				
			||||
 | 
				
			||||
      <div slot="footer" class="dialog-footer"> | 
				
			||||
        <el-button @click="updateConfig">恢复默认值</el-button> | 
				
			||||
        <el-button @click="configVisible=false">取消</el-button> | 
				
			||||
      </div> | 
				
			||||
 | 
				
			||||
    </el-dialog> | 
				
			||||
 | 
				
			||||
    <el-dialog | 
				
			||||
        :close-on-click-modal="false" | 
				
			||||
        :close-on-press-escape="false" | 
				
			||||
        :visible.sync="addCnameVisible" | 
				
			||||
        center | 
				
			||||
        title="添加下载页服务器域名" | 
				
			||||
        width="800px"> | 
				
			||||
 | 
				
			||||
      <el-steps :active="p_active" finish-status="success" :align-center="true"> | 
				
			||||
        <el-step title="添加服务器域名"></el-step> | 
				
			||||
        <el-step title="验证服务器域名所有权"></el-step> | 
				
			||||
        <el-step title="添加成功"></el-step> | 
				
			||||
      </el-steps> | 
				
			||||
 | 
				
			||||
      <el-container> | 
				
			||||
 | 
				
			||||
        <div v-if="p_active===0" style="margin-top: 20px"> | 
				
			||||
          <el-tag style="margin: 10px 5px">1.如果是cdn等含有CNAME,直接添加cdn的 CNAME 值</el-tag> | 
				
			||||
          <el-tag style="margin: 10px 5px">2.如果是服务器,需要将域名解析到服务器,然后添加该解析的域名</el-tag> | 
				
			||||
          <div style="width: 600px;text-align: center;margin: auto"> | 
				
			||||
 | 
				
			||||
            <el-form ref="form" :model="addSerInfo" label-width="120px"> | 
				
			||||
 | 
				
			||||
              <el-form-item label="下载服务器域名"> | 
				
			||||
                <el-input v-model="addSerInfo.domain_record" placeholder="cdn的cname或者服务器的域名,必填"></el-input> | 
				
			||||
              </el-form-item> | 
				
			||||
 | 
				
			||||
              <el-form-item label="下载服务器地址"> | 
				
			||||
                <el-input v-model="addSerInfo.ip_address" placeholder="如果有服务器地址,添加服务器ip,否则填写服务器域名"></el-input> | 
				
			||||
              </el-form-item> | 
				
			||||
              <el-form-item label="备注"> | 
				
			||||
                <el-input type="textarea" v-model="addSerInfo.description"></el-input> | 
				
			||||
              </el-form-item> | 
				
			||||
            </el-form> | 
				
			||||
            <div style="margin-top: 20px;"> | 
				
			||||
              <el-button type="primary" @click="addCnameSer">下一步</el-button> | 
				
			||||
            </div> | 
				
			||||
          </div> | 
				
			||||
 | 
				
			||||
        </div> | 
				
			||||
 | 
				
			||||
        <div v-else-if="p_active===1" style="margin-top: 30px;text-align: center"> | 
				
			||||
 | 
				
			||||
          请联系域名管理员,前往 <strong>{{ cnameInfo.domain_record }}</strong> 域名 DNS 管理后台添加如下 {{ cnameInfo.r_type }} 记录。 | 
				
			||||
          <el-table | 
				
			||||
              :data="domain_tData" | 
				
			||||
              border | 
				
			||||
              stripe | 
				
			||||
              v-loading="loading" | 
				
			||||
              style="width: 100%;margin-top: 20px"> | 
				
			||||
            <el-table-column | 
				
			||||
                align="center" | 
				
			||||
                label="记录类型" | 
				
			||||
                prop="r_type" | 
				
			||||
                width="100"> | 
				
			||||
            </el-table-column> | 
				
			||||
            <el-table-column | 
				
			||||
                align="center" | 
				
			||||
                label="主机记录" | 
				
			||||
                prop="host_r" | 
				
			||||
            > | 
				
			||||
              <template slot-scope="scope"> | 
				
			||||
                <el-tooltip content="点击复制到剪贴板"> | 
				
			||||
                  <el-link v-if="scope.row.host_r" v-clipboard:copy="scope.row.host_r" | 
				
			||||
                           v-clipboard:success="copy_success" | 
				
			||||
                           :underline="false">{{ scope.row.host_r }} | 
				
			||||
                  </el-link> | 
				
			||||
                </el-tooltip> | 
				
			||||
              </template> | 
				
			||||
            </el-table-column> | 
				
			||||
            <el-table-column | 
				
			||||
                align="center" | 
				
			||||
                label="记录值" | 
				
			||||
                prop="cname_r" | 
				
			||||
                width="300"> | 
				
			||||
              <template slot-scope="scope"> | 
				
			||||
                <el-tooltip content="点击复制到剪贴板"> | 
				
			||||
                  <el-link v-if="scope.row.cname_r" v-clipboard:copy="scope.row.cname_r" | 
				
			||||
                           v-clipboard:success="copy_success" | 
				
			||||
                           :underline="false">{{ scope.row.cname_r }} | 
				
			||||
                  </el-link> | 
				
			||||
                </el-tooltip> | 
				
			||||
              </template> | 
				
			||||
            </el-table-column> | 
				
			||||
          </el-table> | 
				
			||||
          <el-alert :closable="false" | 
				
			||||
                    show-icon | 
				
			||||
                    style="margin-top: 30px" | 
				
			||||
                    title="请在域名DNS配置成功后,点击“下一步”按钮" | 
				
			||||
                    type="warning"/> | 
				
			||||
 | 
				
			||||
          <div style="margin-top: 20px;text-align: center;"> | 
				
			||||
            <el-button type="primary" @click="p_active=0">上一步</el-button> | 
				
			||||
            <el-button type="primary" @click="checkCnameSer" :disabled="loading">下一步</el-button> | 
				
			||||
          </div> | 
				
			||||
        </div> | 
				
			||||
      </el-container> | 
				
			||||
 | 
				
			||||
 | 
				
			||||
    </el-dialog> | 
				
			||||
 | 
				
			||||
 | 
				
			||||
    <div> | 
				
			||||
      <el-input | 
				
			||||
          v-model="search_key" | 
				
			||||
          clearable | 
				
			||||
          placeholder="输入下载服务器域名" | 
				
			||||
          style="width: 30%;margin-right: 30px;margin-bottom: 5px"/> | 
				
			||||
      <el-button icon="el-icon-search" type="primary" @click="handleCurrentChange(1)"> | 
				
			||||
        搜索 | 
				
			||||
      </el-button> | 
				
			||||
      <div style="float: right"> | 
				
			||||
 | 
				
			||||
 | 
				
			||||
        <el-tooltip content="下载页配置,可以定制部署私有下载页"> | 
				
			||||
          <el-button plain type="primary" @click="configFun"> | 
				
			||||
            下载页配置 | 
				
			||||
          </el-button> | 
				
			||||
        </el-tooltip> | 
				
			||||
        <el-button plain type="primary" @click="addDownloadSer"> | 
				
			||||
          添加下载页服务器 | 
				
			||||
        </el-button> | 
				
			||||
      </div> | 
				
			||||
 | 
				
			||||
      <el-table | 
				
			||||
          v-loading="loading" | 
				
			||||
          :data="cname_info_list" | 
				
			||||
          border | 
				
			||||
          stripe | 
				
			||||
          style="width: 100%"> | 
				
			||||
 | 
				
			||||
        <el-table-column | 
				
			||||
            align="center" | 
				
			||||
            fixed | 
				
			||||
            label="下载服务器域名" | 
				
			||||
            prop="domain_name"> | 
				
			||||
          <template slot-scope="scope"> | 
				
			||||
            <el-tooltip content="点击复制到剪贴板"> | 
				
			||||
              <el-link v-if="scope.row.domain_record" v-clipboard:copy="scope.row.domain_record" | 
				
			||||
                       v-clipboard:success="copy_success" | 
				
			||||
                       :underline="false">{{ scope.row.domain_record }} | 
				
			||||
              </el-link> | 
				
			||||
            </el-tooltip> | 
				
			||||
          </template> | 
				
			||||
        </el-table-column> | 
				
			||||
 | 
				
			||||
        <el-table-column | 
				
			||||
            align="center" | 
				
			||||
            label="下载服务器地址" | 
				
			||||
            prop="ip_address"> | 
				
			||||
        </el-table-column> | 
				
			||||
 | 
				
			||||
        <el-table-column | 
				
			||||
            align="center" | 
				
			||||
            label="状态" | 
				
			||||
            prop="is_enable" | 
				
			||||
            width="110"> | 
				
			||||
 | 
				
			||||
          <template slot-scope="scope"> | 
				
			||||
            <el-tooltip v-if="scope.row.is_enable === true" content="已经绑定成功" placement="left-start"> | 
				
			||||
              <el-button size="small" type="success">成功 | 
				
			||||
              </el-button> | 
				
			||||
            </el-tooltip> | 
				
			||||
            <el-tooltip v-else content="点击激活服务器域名绑定信息" placement="left-start"> | 
				
			||||
              <el-button size="small" type="warning" @click="continueBind(scope.row)">继续绑定 | 
				
			||||
              </el-button> | 
				
			||||
            </el-tooltip> | 
				
			||||
 | 
				
			||||
          </template> | 
				
			||||
 | 
				
			||||
        </el-table-column> | 
				
			||||
 | 
				
			||||
        <el-table-column | 
				
			||||
            :formatter="format_create_time" | 
				
			||||
            align="center" | 
				
			||||
            label="域名绑定时间" | 
				
			||||
            prop="created_time" | 
				
			||||
            width="170" | 
				
			||||
        > | 
				
			||||
        </el-table-column> | 
				
			||||
        <el-table-column | 
				
			||||
            align="center" | 
				
			||||
            label="备注" | 
				
			||||
            prop="description"> | 
				
			||||
        </el-table-column> | 
				
			||||
        <el-table-column | 
				
			||||
            align="center" | 
				
			||||
            label="操作" | 
				
			||||
            prop="is_enable" | 
				
			||||
            width="100"> | 
				
			||||
 | 
				
			||||
          <template slot-scope="scope"> | 
				
			||||
            <el-tooltip content="删除该下载页服务器" placement="left-start"> | 
				
			||||
              <el-button size="small" type="danger" @click="delCnameSer(scope.row)">删除 | 
				
			||||
              </el-button> | 
				
			||||
            </el-tooltip> | 
				
			||||
 | 
				
			||||
          </template> | 
				
			||||
 | 
				
			||||
        </el-table-column> | 
				
			||||
      </el-table> | 
				
			||||
 | 
				
			||||
 | 
				
			||||
    </div> | 
				
			||||
    <div style="margin-top: 20px;margin-bottom: 20px"> | 
				
			||||
      <el-pagination | 
				
			||||
          :current-page.sync="pagination.currentPage" | 
				
			||||
          :page-size="pagination.pagesize" | 
				
			||||
          :page-sizes="[10, 20, 50, 100]" | 
				
			||||
          :total="pagination.total" | 
				
			||||
          layout="total,sizes, prev, pager, next" | 
				
			||||
          @size-change="handleSizeChange" | 
				
			||||
          @current-change="handleCurrentChange"> | 
				
			||||
      </el-pagination> | 
				
			||||
    </div> | 
				
			||||
  </el-main> | 
				
			||||
</template> | 
				
			||||
 | 
				
			||||
<script> | 
				
			||||
 | 
				
			||||
import {dCnameInfoFun, personalConfigInfo} from "@/restful"; | 
				
			||||
import {getUserInfoFun} from '@/utils' | 
				
			||||
import {format_time} from "@/utils/base/utils"; | 
				
			||||
 | 
				
			||||
export default { | 
				
			||||
  name: "FirUserDomain", | 
				
			||||
  data() { | 
				
			||||
    return { | 
				
			||||
      addSerInfo: {}, | 
				
			||||
      cnameInfo: {}, | 
				
			||||
      domain_tData: [], | 
				
			||||
      p_active: 0, | 
				
			||||
      cname_info_list: [], | 
				
			||||
      search_key: "", | 
				
			||||
      pagination: {"currentPage": 1, "total": 0, "pagesize": 10}, | 
				
			||||
      loading: false, | 
				
			||||
      configVisible: false, | 
				
			||||
      addCnameVisible: false, | 
				
			||||
      config_lists: [], | 
				
			||||
      short_download_list: [] | 
				
			||||
    } | 
				
			||||
  }, | 
				
			||||
  methods: { | 
				
			||||
    continueBind(cname_info) { | 
				
			||||
      this.addSerInfo = cname_info | 
				
			||||
      this.addCnameVisible = true | 
				
			||||
      this.addCnameSer() | 
				
			||||
    }, | 
				
			||||
    delCnameSer(cname_info) { | 
				
			||||
      this.$confirm('若下载域名绑定到该解析,同时也会删除绑定的下载域名,是否继续删除?', '警告', { | 
				
			||||
        confirmButtonText: '确定', | 
				
			||||
        cancelButtonText: '取消', | 
				
			||||
        type: 'warning' | 
				
			||||
      }).then(() => { | 
				
			||||
        dCnameInfoFun(data => { | 
				
			||||
          if (data.code === 1000) { | 
				
			||||
            this.$message.success("删除成功") | 
				
			||||
            this.get_data_from_tabname(); | 
				
			||||
          } else { | 
				
			||||
            this.$message.error("操作失败了 " + data.msg) | 
				
			||||
          } | 
				
			||||
        }, { | 
				
			||||
          methods: 'DELETE', | 
				
			||||
          data: {'domain_record': cname_info.domain_record} | 
				
			||||
        }) | 
				
			||||
      }) | 
				
			||||
    }, | 
				
			||||
    checkCnameSer() { | 
				
			||||
      this.loading=true | 
				
			||||
      dCnameInfoFun(data => { | 
				
			||||
        this.loading=false | 
				
			||||
        if (data.code === 1000) { | 
				
			||||
          this.$message.success(this.addSerInfo.domain_record + " 添加成功") | 
				
			||||
          this.get_data_from_tabname(); | 
				
			||||
          this.addDownloadSer() | 
				
			||||
          this.addCnameVisible = false | 
				
			||||
        } else { | 
				
			||||
          this.$message.error("操作失败了 " + data.msg) | 
				
			||||
        } | 
				
			||||
      }, { | 
				
			||||
        methods: 'PUT', | 
				
			||||
        data: {'act': 'check', 'domain_record': this.addSerInfo.domain_record} | 
				
			||||
      }) | 
				
			||||
    }, | 
				
			||||
    addCnameSer() { | 
				
			||||
      let domain_record = this.addSerInfo.domain_record | 
				
			||||
      let ip_address = this.addSerInfo.ip_address | 
				
			||||
      if (domain_record && domain_record.length > 6 && ip_address && ip_address.length > 6) { | 
				
			||||
        dCnameInfoFun(data => { | 
				
			||||
          if (data.code === 1000) { | 
				
			||||
            this.p_active = 1 | 
				
			||||
            this.cnameInfo = data.data | 
				
			||||
            this.domain_tData = [this.cnameInfo] | 
				
			||||
          } else { | 
				
			||||
            this.$message.error("操作失败了 " + data.msg) | 
				
			||||
          } | 
				
			||||
        }, { | 
				
			||||
          methods: 'POST', | 
				
			||||
          data: this.addSerInfo | 
				
			||||
        }) | 
				
			||||
      } else { | 
				
			||||
        this.$message.error("参数有误") | 
				
			||||
      } | 
				
			||||
 | 
				
			||||
    }, | 
				
			||||
    addDownloadSer() { | 
				
			||||
      this.addSerInfo = {} | 
				
			||||
      this.cnameInfo = {} | 
				
			||||
      this.p_active = 0 | 
				
			||||
      this.addCnameVisible = true | 
				
			||||
    }, | 
				
			||||
    configFun() { | 
				
			||||
      personalConfigInfo(data => { | 
				
			||||
        if (data.code === 1000) { | 
				
			||||
          this.short_download_list = data.data | 
				
			||||
        } else { | 
				
			||||
          this.$message.error("获取数据失败了 " + data.msg) | 
				
			||||
        } | 
				
			||||
      }, { | 
				
			||||
        methods: 'GET' | 
				
			||||
      }, 'short_download_uri') | 
				
			||||
 | 
				
			||||
 | 
				
			||||
      personalConfigInfo(data => { | 
				
			||||
        if (data.code === 1000) { | 
				
			||||
          this.config_lists = data.data | 
				
			||||
          this.configVisible = true | 
				
			||||
        } else { | 
				
			||||
          this.$message.error("获取数据失败了 " + data.msg) | 
				
			||||
        } | 
				
			||||
      }, { | 
				
			||||
        methods: 'GET' | 
				
			||||
      }, 'preview_route') | 
				
			||||
    }, | 
				
			||||
    changeConfig(info) { | 
				
			||||
      personalConfigInfo(data => { | 
				
			||||
        if (data.code === 1000) { | 
				
			||||
          this.$message.success("操作成功") | 
				
			||||
          this.configFun() | 
				
			||||
        } else { | 
				
			||||
          this.$message.error("操作失败了 " + data.msg) | 
				
			||||
        } | 
				
			||||
      }, { | 
				
			||||
        methods: 'PUT', data: {config_key: info.key, config_value: info.value} | 
				
			||||
      }, 'preview_route') | 
				
			||||
    }, | 
				
			||||
    updateConfig() { | 
				
			||||
      personalConfigInfo(data => { | 
				
			||||
        if (data.code === 1000) { | 
				
			||||
          this.$message.success("操作成功") | 
				
			||||
          this.configFun() | 
				
			||||
        } else { | 
				
			||||
          this.$message.error("操作失败了 " + data.msg) | 
				
			||||
        } | 
				
			||||
      }, { | 
				
			||||
        methods: 'DELETE' | 
				
			||||
      }, 'preview_route') | 
				
			||||
    }, | 
				
			||||
 | 
				
			||||
    copy_success() { | 
				
			||||
      this.$message.success('复制剪切板成功'); | 
				
			||||
    }, | 
				
			||||
    handleSizeChange(val) { | 
				
			||||
      this.pagination.pagesize = val; | 
				
			||||
      this.get_data_from_tabname({ | 
				
			||||
        "size": this.pagination.pagesize, | 
				
			||||
        "page": 1 | 
				
			||||
      }) | 
				
			||||
    }, | 
				
			||||
    handleCurrentChange(val) { | 
				
			||||
      this.pagination.currentPage = val; | 
				
			||||
      this.get_data_from_tabname({ | 
				
			||||
        "size": this.pagination.pagesize, | 
				
			||||
        "page": this.pagination.currentPage | 
				
			||||
      }) | 
				
			||||
    }, | 
				
			||||
 | 
				
			||||
    get_data_from_tabname(data = {}) { | 
				
			||||
      data.search_key = this.search_key.replace(/^\s+|\s+$/g, ""); | 
				
			||||
      this.UserCnameInfoFun(data) | 
				
			||||
    }, | 
				
			||||
    UserCnameInfoFun(params) { | 
				
			||||
      this.loading = true; | 
				
			||||
      dCnameInfoFun(data => { | 
				
			||||
        if (data.code === 1000) { | 
				
			||||
          this.cname_info_list = data.data; | 
				
			||||
          this.pagination.total = data.count; | 
				
			||||
 | 
				
			||||
        } else { | 
				
			||||
          this.$message.error("域名绑定信息获取失败") | 
				
			||||
        } | 
				
			||||
        this.loading = false; | 
				
			||||
      }, {methods: 'GET', data: params}) | 
				
			||||
    }, | 
				
			||||
 | 
				
			||||
    format_create_time(row) { | 
				
			||||
      return format_time(row.created_time) | 
				
			||||
    }, | 
				
			||||
 | 
				
			||||
  }, mounted() { | 
				
			||||
    getUserInfoFun(this); | 
				
			||||
    this.get_data_from_tabname(); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
</script> | 
				
			||||
 | 
				
			||||
<style scoped> | 
				
			||||
.el-main { | 
				
			||||
  margin: 20px auto 100px; | 
				
			||||
  width: 1166px; | 
				
			||||
  position: relative; | 
				
			||||
  padding-bottom: 1px; | 
				
			||||
  color: #9b9b9b; | 
				
			||||
  -webkit-font-smoothing: antialiased; | 
				
			||||
  border-radius: 1%; | 
				
			||||
} | 
				
			||||
 | 
				
			||||
</style> | 
				
			||||
@ -0,0 +1,22 @@ | 
				
			||||
module.exports =function dateFormat(format, date=null) { | 
				
			||||
    if(!date){ | 
				
			||||
        date = new Date() | 
				
			||||
    } | 
				
			||||
    const args = { | 
				
			||||
        "M+": date.getMonth() + 1, | 
				
			||||
        "d+": date.getDate(), | 
				
			||||
        "h+": date.getHours(), | 
				
			||||
        "m+": date.getMinutes(), | 
				
			||||
        "s+": date.getSeconds(), | 
				
			||||
        "q+": Math.floor((date.getMonth() + 3) / 3), | 
				
			||||
        "S": date.getMilliseconds() | 
				
			||||
    }; | 
				
			||||
    if (/(y+)/.test(format)) | 
				
			||||
        format = format.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length)); | 
				
			||||
    for (let i in args) { | 
				
			||||
        let n = args[i]; | 
				
			||||
        if (new RegExp("(" + i + ")").test(format)) | 
				
			||||
            format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? n : ("00" + n).substr(("" + n).length)); | 
				
			||||
    } | 
				
			||||
    return format; | 
				
			||||
} | 
				
			||||
@ -1,41 +1,32 @@ | 
				
			||||
FROM python:3.6.14-slim | 
				
			||||
FROM python:3.9.14-slim | 
				
			||||
 | 
				
			||||
# Fixes some weird terminal issues such as broken clear / CTRL+L | 
				
			||||
ARG PIP_MIRROR=https://mirrors.aliyun.com/pypi/simple | 
				
			||||
 | 
				
			||||
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list \ | 
				
			||||
    && sed -i 's/security.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list \ | 
				
			||||
    && apt update  | 
				
			||||
#RUN sed -i 's/deb.debian.org/mirrors.163.com/g' /etc/apt/sources.list \ | 
				
			||||
#    && sed -i 's/security.debian.org/mirrors.163.com/g' /etc/apt/sources.list \ | 
				
			||||
RUN apt update  \ | 
				
			||||
    && apt-get install g++ wget zip unzip -y \ | 
				
			||||
    && apt-get install libssl-dev openssl libmariadb-dev  -y \ | 
				
			||||
    && apt-get clean \ | 
				
			||||
    && rm -rf /var/lib/apt/lists/* | 
				
			||||
 | 
				
			||||
RUN apt-get install g++ wget -y | 
				
			||||
RUN apt-get install libssl-dev openssl libmariadb-dev  -y | 
				
			||||
RUN rm -rf /var/lib/apt/lists/*  | 
				
			||||
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
#COPY fir_client/dist /data/flyapps/fir_client | 
				
			||||
 | 
				
			||||
#RUN cd /opt/ && wget https://github.com/nineaiyu/zsign/archive/refs/tags/v1.1.2.tar.gz | 
				
			||||
COPY zsign-1.1.2.tar.gz /opt/zsign-1.1.2.tar.gz | 
				
			||||
RUN cd /opt/ && tar xvf zsign-1.1.2.tar.gz && cd zsign-1.1.2/ && g++ *.cpp common/*.cpp -lcrypto -O3 -std=c++11 -o zsign && cp zsign /usr/bin/ | 
				
			||||
ADD zsign-1.1.2.tar.gz /opt/ | 
				
			||||
RUN cd /opt/zsign-1.1.2/ && g++ *.cpp common/*.cpp -lcrypto -O3 -std=c++11 -o zsign && cp zsign /usr/bin/ && rm -rf /opt/zsign-1.1.2/ | 
				
			||||
# install pip | 
				
			||||
COPY requirements.txt /opt/requirements.txt | 
				
			||||
RUN cd /opt/ && pip install -U setuptools pip -i ${PIP_MIRROR} --ignore-installed && pip install --no-cache-dir -r requirements.txt -i ${PIP_MIRROR}  && pip install --no-cache-dir uwsgi -i ${PIP_MIRROR}  | 
				
			||||
 | 
				
			||||
RUN rm -rf /var/cache/yum/ | 
				
			||||
RUN cd /opt/ && pip install -U setuptools pip --ignore-installed && pip install --no-cache-dir -r requirements.txt && pip install --no-cache-dir uwsgi | 
				
			||||
 | 
				
			||||
#COPY Docker/flyapps.conf  /etc/supervisor/conf.d/flyapps.conf | 
				
			||||
#COPY Docker/uwsgi.conf /data/flyapps/fir_ser/uwsgi.conf | 
				
			||||
#COPY Docker/flyapps-vhost.conf  /etc/nginx/conf.d/flyapps-vhost.conf | 
				
			||||
#COPY Docker/app.hehelucky.cn.pem /data/flyapps/app.hehelucky.cn.pem | 
				
			||||
#COPY Docker/app.hehelucky.cn.key /data/flyapps/app.hehelucky.cn.key | 
				
			||||
 | 
				
			||||
WORKDIR /data/fir_ser/ | 
				
			||||
COPY entrypoint.sh entrypoint.sh | 
				
			||||
RUN addgroup --system --gid 101 nginx \ | 
				
			||||
    && adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid 101 nginx  | 
				
			||||
 | 
				
			||||
#EXPOSE 443 | 
				
			||||
#ENTRYPOINT ["./entrypoint.sh"] | 
				
			||||
#ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf", "-n"] | 
				
			||||
CMD ["python", "manage.py", "start", "all","-u","nginx","-usm","1"] | 
				
			||||
#CMD ["python", "manage.py", "start", "all","-u","nginx","-usm","1"] | 
				
			||||
ENTRYPOINT ["/bin/bash", "entrypoint.sh"] | 
				
			||||
 | 
				
			||||
 | 
				
			||||
@ -0,0 +1,11 @@ | 
				
			||||
FROM python:3.9.14-slim | 
				
			||||
 | 
				
			||||
RUN pip install --upgrade pip --no-cache-dir && \ | 
				
			||||
        pip install setuptools-rust oss2 requests-toolbelt androguard requests --no-cache-dir | 
				
			||||
 | 
				
			||||
WORKDIR /opt/ | 
				
			||||
 | 
				
			||||
COPY cli.py /opt/cli.py | 
				
			||||
 | 
				
			||||
CMD ["python", "cli.py"] | 
				
			||||
 | 
				
			||||
@ -0,0 +1,14 @@ | 
				
			||||
from django.core.management.base import BaseCommand | 
				
			||||
 | 
				
			||||
from common.utils.caches import add_user_ds | 
				
			||||
 | 
				
			||||
 | 
				
			||||
class Command(BaseCommand): | 
				
			||||
    help = 'add user download times' | 
				
			||||
 | 
				
			||||
    def add_arguments(self, parser): | 
				
			||||
        parser.add_argument('uid', type=str, default='') | 
				
			||||
        parser.add_argument('download_times', type=int, default=100) | 
				
			||||
 | 
				
			||||
    def handle(self, *args, **options): | 
				
			||||
        add_user_ds(options.get('uid', None), options.get('download_times', 100)) | 
				
			||||
@ -0,0 +1,32 @@ | 
				
			||||
# Generated by Django 3.2.3 on 2022-07-25 16:12 | 
				
			||||
 | 
				
			||||
from django.db import migrations, models | 
				
			||||
 | 
				
			||||
 | 
				
			||||
class Migration(migrations.Migration): | 
				
			||||
 | 
				
			||||
    dependencies = [ | 
				
			||||
        ('api', '0006_auto_20220513_0843'), | 
				
			||||
    ] | 
				
			||||
 | 
				
			||||
    operations = [ | 
				
			||||
        migrations.AlterField( | 
				
			||||
            model_name='domaincnameinfo', | 
				
			||||
            name='is_enable', | 
				
			||||
            field=models.BooleanField(default=False, verbose_name='是否启用该解析'), | 
				
			||||
        ), | 
				
			||||
        migrations.AlterField( | 
				
			||||
            model_name='domaincnameinfo', | 
				
			||||
            name='domain_record', | 
				
			||||
            field=models.CharField(max_length=128, verbose_name='记录值'), | 
				
			||||
        ), | 
				
			||||
        migrations.AddField( | 
				
			||||
            model_name='domaincnameinfo', | 
				
			||||
            name='user_ipk', | 
				
			||||
            field=models.IntegerField(default=0, verbose_name='用户ipk'), | 
				
			||||
        ), | 
				
			||||
        migrations.AlterUniqueTogether( | 
				
			||||
            name='domaincnameinfo', | 
				
			||||
            unique_together={('user_ipk', 'domain_record')}, | 
				
			||||
        ), | 
				
			||||
    ] | 
				
			||||
@ -1,146 +0,0 @@ | 
				
			||||
from functools import wraps, WRAPPER_ASSIGNMENTS | 
				
			||||
 | 
				
			||||
from django.http.response import HttpResponse | 
				
			||||
 | 
				
			||||
from common.cache.storage import AppDownloadShortShowCache | 
				
			||||
 | 
				
			||||
 | 
				
			||||
def get_cache(alias): | 
				
			||||
    from django.core.cache import caches | 
				
			||||
    return caches[alias] | 
				
			||||
 | 
				
			||||
 | 
				
			||||
def set_short_show_cache(short, cache_key): | 
				
			||||
    short_show_cache = AppDownloadShortShowCache("ShortDownloadView".lower(), short) | 
				
			||||
    key_list = short_show_cache.get_storage_cache() | 
				
			||||
 | 
				
			||||
    if key_list and isinstance(key_list, list): | 
				
			||||
        key_list.append(cache_key) | 
				
			||||
        key_list = list(set(key_list)) | 
				
			||||
    else: | 
				
			||||
        key_list = [cache_key] | 
				
			||||
    short_show_cache.set_storage_cache(key_list, 600) | 
				
			||||
 | 
				
			||||
 | 
				
			||||
class CacheResponse: | 
				
			||||
    """ | 
				
			||||
    Store/Receive and return cached `HttpResponse` based on DRF response. | 
				
			||||
    .. note:: | 
				
			||||
        This decorator will render and discard the original DRF response in | 
				
			||||
        favor of Django's `HttpResponse`. The allows the cache to retain a | 
				
			||||
        smaller memory footprint and eliminates the need to re-render | 
				
			||||
        responses on each request. Furthermore it eliminates the risk for users | 
				
			||||
        to unknowingly cache whole Serializers and QuerySets. | 
				
			||||
    """ | 
				
			||||
 | 
				
			||||
    def __init__(self, | 
				
			||||
                 timeout=None, | 
				
			||||
                 key_func=None, | 
				
			||||
                 cache=None, | 
				
			||||
                 cache_errors=None): | 
				
			||||
        if timeout is None: | 
				
			||||
            self.timeout = None | 
				
			||||
        else: | 
				
			||||
            self.timeout = timeout | 
				
			||||
 | 
				
			||||
        if key_func is None: | 
				
			||||
            self.key_func = '' | 
				
			||||
        else: | 
				
			||||
            self.key_func = key_func | 
				
			||||
 | 
				
			||||
        if cache_errors is None: | 
				
			||||
            self.cache_errors = True | 
				
			||||
        else: | 
				
			||||
            self.cache_errors = cache_errors | 
				
			||||
 | 
				
			||||
        self.cache = get_cache(cache or 'default') | 
				
			||||
 | 
				
			||||
    def __call__(self, func): | 
				
			||||
        this = self | 
				
			||||
 | 
				
			||||
        @wraps(func, assigned=WRAPPER_ASSIGNMENTS) | 
				
			||||
        def inner(self, request, *args, **kwargs): | 
				
			||||
            return this.process_cache_response( | 
				
			||||
                view_instance=self, | 
				
			||||
                view_method=func, | 
				
			||||
                request=request, | 
				
			||||
                args=args, | 
				
			||||
                kwargs=kwargs, | 
				
			||||
            ) | 
				
			||||
 | 
				
			||||
        return inner | 
				
			||||
 | 
				
			||||
    def process_cache_response(self, | 
				
			||||
                               view_instance, | 
				
			||||
                               view_method, | 
				
			||||
                               request, | 
				
			||||
                               args, | 
				
			||||
                               kwargs): | 
				
			||||
 | 
				
			||||
        key = self.calculate_key( | 
				
			||||
            view_instance=view_instance, | 
				
			||||
            view_method=view_method, | 
				
			||||
            request=request, | 
				
			||||
            args=args, | 
				
			||||
            kwargs=kwargs | 
				
			||||
        ) | 
				
			||||
 | 
				
			||||
        timeout = self.calculate_timeout(view_instance=view_instance) | 
				
			||||
 | 
				
			||||
        response_triple = self.cache.get(key) | 
				
			||||
        if not response_triple: | 
				
			||||
            # render response to create and cache the content byte string | 
				
			||||
            response = view_method(view_instance, request, *args, **kwargs) | 
				
			||||
            response = view_instance.finalize_response(request, response, *args, **kwargs) | 
				
			||||
            response.render() | 
				
			||||
 | 
				
			||||
            if not response.status_code >= 400 or self.cache_errors: | 
				
			||||
                # django 3.0 has not .items() method, django 3.2 has not ._headers | 
				
			||||
                if hasattr(response, '_headers'): | 
				
			||||
                    headers = response._headers.copy() | 
				
			||||
                else: | 
				
			||||
                    headers = {k: (k, v) for k, v in response.items()} | 
				
			||||
                response_triple = ( | 
				
			||||
                    response.rendered_content, | 
				
			||||
                    response.status_code, | 
				
			||||
                    headers | 
				
			||||
                ) | 
				
			||||
                short = kwargs.get("short", '') | 
				
			||||
                set_short_show_cache(short, key) | 
				
			||||
                self.cache.set(key, response_triple, timeout) | 
				
			||||
        else: | 
				
			||||
            # build smaller Django HttpResponse | 
				
			||||
            content, status, headers = response_triple | 
				
			||||
            response = HttpResponse(content=content, status=status) | 
				
			||||
            for k, v in headers.values(): | 
				
			||||
                response[k] = v | 
				
			||||
        if not hasattr(response, '_closable_objects'): | 
				
			||||
            response._closable_objects = [] | 
				
			||||
 | 
				
			||||
        return response | 
				
			||||
 | 
				
			||||
    def calculate_key(self, | 
				
			||||
                      view_instance, | 
				
			||||
                      view_method, | 
				
			||||
                      request, | 
				
			||||
                      args, | 
				
			||||
                      kwargs): | 
				
			||||
        if isinstance(self.key_func, str): | 
				
			||||
            key_func = getattr(view_instance, self.key_func) | 
				
			||||
        else: | 
				
			||||
            key_func = self.key_func | 
				
			||||
        return key_func( | 
				
			||||
            view_instance=view_instance, | 
				
			||||
            view_method=view_method, | 
				
			||||
            request=request, | 
				
			||||
            args=args, | 
				
			||||
            kwargs=kwargs, | 
				
			||||
        ) | 
				
			||||
 | 
				
			||||
    def calculate_timeout(self, view_instance, **_): | 
				
			||||
        if isinstance(self.timeout, str): | 
				
			||||
            self.timeout = getattr(view_instance, self.timeout) | 
				
			||||
        return self.timeout | 
				
			||||
 | 
				
			||||
 | 
				
			||||
cache_response = CacheResponse | 
				
			||||