Compare commits

...

10 Commits

Author SHA1 Message Date
whyour 201f578bbc 修复sqlite加载顺序 2022-01-20 22:19:39 +08:00
whyour ce9aa369d2 更新版本 v2.11.1 2022-01-20 19:11:41 +08:00
whyour c5c41c0859 修改cdn地址,增加重启服务延迟 2022-01-20 19:02:29 +08:00
whyour d3009f82dd 移除默认github代理,增加http或者socks代理参数 2022-01-19 23:29:55 +08:00
whyour 0eb9a1fdb0 定时任务默认倒序 2022-01-18 23:50:18 +08:00
whyour 83f6d9926a 修改迁移数据库逻辑 2022-01-18 22:56:12 +08:00
whyour 14134842b0 修复环境变量更新时间显示 2022-01-17 22:47:23 +08:00
whyour 4c094c4710 修复重置应用秘钥 2022-01-16 18:55:18 +08:00
whyour 3ac41075fd 修复停止任务后任务状态修改 2022-01-14 23:44:22 +08:00
whyour fdc97773d1 修改数据迁移逻辑 2022-01-14 23:17:16 +08:00
17 changed files with 160 additions and 130 deletions
+6 -6
View File
@@ -39,11 +39,11 @@ export default defineConfig({
scripts: [
'https://gw.alipayobjects.com/os/lib/react/16.13.1/umd/react.production.min.js',
'https://gw.alipayobjects.com/os/lib/react-dom/16.13.1/umd/react-dom.production.min.js',
'https://cdn.jsdelivr.net/npm/darkreader@4.9.40/darkreader.min.js',
'https://cdn.jsdelivr.net/npm/codemirror@5/lib/codemirror.min.js',
'https://cdn.jsdelivr.net/npm/codemirror@5/mode/shell/shell.js',
'https://cdn.jsdelivr.net/npm/codemirror@5/mode/python/python.js',
'https://cdn.jsdelivr.net/npm/codemirror@5/mode/javascript/javascript.js',
'https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js',
'https://unpkg.zhimg.com/darkreader@4.9.40/darkreader.js',
'https://unpkg.zhimg.com/codemirror@5/lib/codemirror.js',
'https://unpkg.zhimg.com/codemirror@5/mode/shell/shell.js',
'https://unpkg.zhimg.com/codemirror@5/mode/python/python.js',
'https://unpkg.zhimg.com/codemirror@5/mode/javascript/javascript.js',
'https://unpkg.zhimg.com/sockjs-client@1/dist/sockjs.min.js',
],
});
+60 -79
View File
@@ -1,7 +1,6 @@
import DataStore from 'nedb';
import config from '../config';
import Logger from './logger';
import fs from 'fs';
import { fileExist } from '../config/util';
import { EnvModel } from '../data/env';
import { CrontabModel } from '../data/cron';
@@ -10,91 +9,75 @@ import { AppModel } from '../data/open';
import { AuthModel } from '../data/auth';
import { sequelize } from '../data';
interface Dbs {
cronDb: DataStore;
dependenceDb: DataStore;
envDb: DataStore;
appDb: DataStore;
authDb: DataStore;
}
const db: Dbs = {} as any;
async function truncateDb() {
return new Promise(async (resolve) => {
const files = [
config.cronDbFile,
config.dependenceDbFile,
config.envDbFile,
config.appDbFile,
config.authDbFile,
];
for (const file of files) {
const _fileExist = await fileExist(file);
if (_fileExist && fs.statSync(file).size >= 1024 * 1024 * 500) {
fs.truncateSync(file, 1024 * 1024 * 500);
}
}
resolve(null);
});
}
export default async () => {
try {
await truncateDb();
await sequelize.sync({ alter: true });
db.cronDb = new DataStore({ filename: config.cronDbFile, autoload: true });
db.dependenceDb = new DataStore({
filename: config.dependenceDbFile,
autoload: true,
});
db.envDb = new DataStore({ filename: config.envDbFile, autoload: true });
db.appDb = new DataStore({ filename: config.appDbFile, autoload: true });
db.authDb = new DataStore({ filename: config.authDbFile, autoload: true });
const crondbExist = await fileExist(config.cronDbFile);
const dependenceDbExist = await fileExist(config.dependenceDbFile);
const envDbExist = await fileExist(config.envDbFile);
const appDbExist = await fileExist(config.appDbFile);
const authDbExist = await fileExist(config.authDbFile);
// compaction data file
db.cronDb.persistence.compactDatafile();
db.envDb.persistence.compactDatafile();
db.dependenceDb.persistence.compactDatafile();
db.appDb.persistence.compactDatafile();
db.authDb.persistence.compactDatafile();
try {
await sequelize.sync({ alter: true });
} catch (error) {
console.log(error);
const cronCount = await CrontabModel.count();
const dependenceCount = await DependenceModel.count();
const envCount = await EnvModel.count();
const appCount = await AppModel.count();
const authCount = await AuthModel.count();
if (crondbExist && cronCount === 0) {
const cronDb = new DataStore({
filename: config.cronDbFile,
autoload: true,
});
cronDb.persistence.compactDatafile();
cronDb.find({}).exec(async (err, docs) => {
await CrontabModel.bulkCreate(docs, { ignoreDuplicates: true });
});
}
// migrate db to sqlite
setTimeout(async () => {
try {
const count = await CrontabModel.count();
if (count !== 0) {
return;
}
db.cronDb.find({}).exec(async (err, docs) => {
await CrontabModel.bulkCreate(docs);
});
if (dependenceDbExist && dependenceCount === 0) {
const dependenceDb = new DataStore({
filename: config.dependenceDbFile,
autoload: true,
});
dependenceDb.persistence.compactDatafile();
dependenceDb.find({}).exec(async (err, docs) => {
await DependenceModel.bulkCreate(docs, { ignoreDuplicates: true });
});
}
db.dependenceDb.find({}).exec(async (err, docs) => {
await DependenceModel.bulkCreate(docs);
});
if (envDbExist && envCount === 0) {
const envDb = new DataStore({
filename: config.envDbFile,
autoload: true,
});
envDb.persistence.compactDatafile();
envDb.find({}).exec(async (err, docs) => {
await EnvModel.bulkCreate(docs, { ignoreDuplicates: true });
});
}
db.envDb.find({}).exec(async (err, docs) => {
await EnvModel.bulkCreate(docs);
});
if (appDbExist && appCount === 0) {
const appDb = new DataStore({
filename: config.appDbFile,
autoload: true,
});
appDb.persistence.compactDatafile();
appDb.find({}).exec(async (err, docs) => {
await AppModel.bulkCreate(docs, { ignoreDuplicates: true });
});
}
db.appDb.find({}).exec(async (err, docs) => {
await AppModel.bulkCreate(docs);
});
db.authDb.find({}).exec(async (err, docs) => {
await AuthModel.bulkCreate(docs);
});
} catch (error) {
console.log(error);
}
}, 5000);
if (authDbExist && authCount === 0) {
const authDb = new DataStore({
filename: config.authDbFile,
autoload: true,
});
authDb.persistence.compactDatafile();
authDb.find({}).exec(async (err, docs) => {
await AuthModel.bulkCreate(docs, { ignoreDuplicates: true });
});
}
Logger.info('✌️ DB loaded');
} catch (error) {
@@ -102,5 +85,3 @@ export default async () => {
Logger.info(error);
}
};
export const dbs: Dbs = db;
+5 -2
View File
@@ -163,7 +163,10 @@ export default class CronService {
}
}
try {
const result = await CrontabModel.findAll({ where: query });
const result = await CrontabModel.findAll({
where: query,
order: [['updatedAt', 'DESC']],
});
return result as any;
} catch (error) {
throw error;
@@ -209,7 +212,7 @@ export default class CronService {
}
await CrontabModel.update(
{ status: CrontabStatus.queued, pid: undefined },
{ status: CrontabStatus.idle, pid: undefined },
{ where: { id: ids } },
);
}
+1 -1
View File
@@ -1,7 +1,6 @@
import { Service, Inject } from 'typedi';
import winston from 'winston';
import config from '../config';
import DataStore from 'nedb';
import {
Dependence,
InstallDependenceCommandTypes,
@@ -64,6 +63,7 @@ export default class DependenceService {
);
const docs = await DependenceModel.findAll({ where: { id: ids } });
this.installOrUninstallDependencies(docs, false);
return docs;
}
public async removeDb(ids: number[]) {
-1
View File
@@ -3,7 +3,6 @@ import winston from 'winston';
import { getFileContentByName } from '../config/util';
import config from '../config';
import * as fs from 'fs';
import DataStore from 'nedb';
import { Env, EnvModel, EnvStatus, initEnvPosition } from '../data/env';
import _ from 'lodash';
import { Op } from 'sequelize';
+11 -2
View File
@@ -2,7 +2,6 @@ import { Service, Inject } from 'typedi';
import winston from 'winston';
import { createRandomString } from '../config/util';
import config from '../config';
import DataStore from 'nedb';
import { App, AppModel } from '../data/open';
import { v4 as uuidV4 } from 'uuid';
import sequelize, { Op } from 'sequelize';
@@ -54,7 +53,17 @@ export default class OpenService {
}
public async resetSecret(id: number): Promise<App> {
const tab: any = { client_secret: createRandomString(24, 24), tokens: [] };
const tab: any = {
client_secret: createRandomString(24, 24),
tokens: [],
id,
};
// const doc = await this.get(id);
// const tab = new App({ ...doc });
// tab.client_secret = createRandomString(24, 24);
// tab.tokens = [];
// const newDoc = await this.updateDb(tab);
// return newDoc;
const newDoc = await this.updateDb(tab);
return newDoc;
}
-1
View File
@@ -10,7 +10,6 @@ import ScheduleService from './schedule';
import { spawn } from 'child_process';
import SockService from './sock';
import got from 'got';
import { dbs } from '../loaders/db';
@Service()
export default class SystemService {
+2 -2
View File
@@ -16,8 +16,8 @@ DefaultCronRule=""
## ql repo命令拉取脚本时需要拉取的文件后缀,直接写文件后缀名即可
RepoFileExtensions="js py"
## 由于github仓库拉取较慢,所以会默认添加代理前缀,如不需要请移除
GithubProxyUrl="https://ghproxy.com/"
## 代理地址,支持http/https/socks,例如 http://127.0.0.1:7890
ProxyUrl=""
## 设置定时任务执行的超时时间,默认1h,后缀"s"代表秒(默认值), "m"代表分, "h"代表小时, "d"代表天
CommandTimeoutTime="1h"
+1 -1
View File
@@ -5,7 +5,7 @@ dir_shell=/ql/shell
. $dir_shell/share.sh
if [[ -z ${BotRepoUrl} ]]; then
url="${github_proxy_url}https://github.com/SuMaiKaDe/bot.git"
url="https://github.com/SuMaiKaDe/bot.git"
repo_path="${dir_repo}/dockerbot"
else
url=${BotRepoUrl}
+21 -1
View File
@@ -67,7 +67,7 @@ import_config() {
[[ -f $file_env ]] && . $file_env
command_timeout_time=${CommandTimeoutTime:-"1h"}
github_proxy_url=${GithubProxyUrl:-""}
proxy_url=${ProxyUrl:-""}
file_extensions=${RepoFileExtensions:-"js py"}
if [[ -n "${DefaultCronRule}" ]]; then
@@ -77,6 +77,18 @@ import_config() {
fi
}
set_proxy() {
if [[ $proxy_url ]]; then
export http_proxy="${proxy_url}"
export https_proxy="${proxy_url}"
fi
}
unset_proxy() {
unset http_proxy
unset https_proxy
}
make_dir() {
local dir=$1
if [[ ! -d $dir ]]; then
@@ -287,7 +299,11 @@ git_clone_scripts() {
local branch=$3
[[ $branch ]] && local part_cmd="-b $branch "
echo -e "开始克隆仓库 $url$dir\n"
set_proxy
git clone $part_cmd $url $dir
unset_proxy
exit_status=$?
}
@@ -298,10 +314,14 @@ git_pull_scripts() {
[[ $branch ]] && local part_cmd="origin/${branch}"
cd $dir_work
echo -e "开始更新仓库:$dir_work\n"
set_proxy
git fetch --all
exit_status=$?
git reset --hard $part_cmd
git pull
unset_proxy
cd $dir_current
}
+6 -12
View File
@@ -151,11 +151,6 @@ update_repo() {
make_dir "${dir_scripts}/${uniq_path}"
local formatUrl="$url"
if [[ $github_proxy_url ]]; then
if [[ $url =~ "github.com" ]] || [[ $url =~ "githubusercontent.com" ]]; then
[[ ! $url =~ "https://ghproxy.com" ]] && formatUrl="${github_proxy_url}${url}"
fi
fi
if [[ -d ${repo_path}/.git ]]; then
reset_romote_url ${repo_path} "${formatUrl}" "${branch}"
git_pull_scripts ${repo_path} "${branch}"
@@ -183,15 +178,14 @@ update_raw() {
echo -e "--------------------------------------------------------------\n"
local url="$1"
local raw_url="$url"
if [[ $github_proxy_url ]]; then
if [[ $url =~ "github.com" ]] || [[ $url =~ "githubusercontent.com" ]]; then
[[ ! $url =~ "https://ghproxy.com" ]] && raw_url="${github_proxy_url}${url}"
fi
fi
local suffix="${raw_url##*.}"
local raw_file_name="${uniq_path}.${suffix}"
echo -e "开始下载:${raw_url} \n\n保存路径:$dir_raw/${raw_file_name}\n"
set_proxy
wget -q --no-check-certificate -O "$dir_raw/${raw_file_name}.new" ${raw_url}
unset_proxy
if [[ $? -eq 0 ]]; then
mv "$dir_raw/${raw_file_name}.new" "$dir_raw/${raw_file_name}"
echo -e "下载 ${raw_file_name} 成功...\n"
@@ -259,7 +253,7 @@ update_qinglong() {
local no_restart="$1"
[[ -f $dir_root/package.json ]] && ql_depend_old=$(cat $dir_root/package.json)
reset_romote_url ${dir_root} "${github_proxy_url}https://github.com/whyour/qinglong.git" "master"
reset_romote_url ${dir_root} "https://github.com/whyour/qinglong.git" "master"
git_pull_scripts $dir_root "master"
if [[ $exit_status -eq 0 ]]; then
@@ -274,7 +268,7 @@ update_qinglong() {
echo -e "\n更新$dir_root失败,请检查原因...\n"
fi
local url="${github_proxy_url}https://github.com/whyour/qinglong-static.git"
local url="https://github.com/whyour/qinglong-static.git"
if [[ -d ${ql_static_repo}/.git ]]; then
reset_romote_url ${ql_static_repo} ${url} "master"
git_pull_scripts ${ql_static_repo} "master"
+2 -2
View File
@@ -61,7 +61,7 @@ const CronLogModal = ({
<Countdown
className="inline-countdown"
format="ss"
value={Date.now() + 1000 * 10}
value={Date.now() + 1000 * 30}
/>
</span>
@@ -70,7 +70,7 @@ const CronLogModal = ({
});
setTimeout(() => {
window.location.reload();
}, 10000);
}, 30000);
}
}
})
+16 -1
View File
@@ -94,7 +94,22 @@ const Dependence = ({ headerStyle, isPhone, socketMessage }: any) => {
dataIndex: 'timestamp',
align: 'center' as const,
render: (text: string, record: any) => {
return <span>{new Date(record.timestamp).toLocaleString()}</span>;
const language = navigator.language || navigator.languages[0];
const time = record.createdAt || record.timestamp;
const date = new Date(time)
.toLocaleString(language, {
hour12: false,
})
.replace(' 24:', ' 00:');
return (
<Tooltip
placement="topLeft"
title={date}
trigger={['hover', 'click']}
>
<span>{date}</span>
</Tooltip>
);
},
},
{
+2 -1
View File
@@ -151,7 +151,8 @@ const Env = ({ headerStyle, isPhone, theme }: any) => {
},
render: (text: string, record: any) => {
const language = navigator.language || navigator.languages[0];
const date = new Date(text)
const time = record.updatedAt || record.timestamp;
const date = new Date(time)
.toLocaleString(language, {
hour12: false,
})
+13 -9
View File
@@ -36,16 +36,20 @@ const EnvModal = ({
} else {
payload = { ...values, id: env.id };
}
const { code, data } = await request[method](`${config.apiPrefix}envs`, {
data: payload,
});
if (code === 200) {
message.success(env ? '更新变量成功' : '新建变量成功');
} else {
message.error(data);
try {
const { code, data } = await request[method](`${config.apiPrefix}envs`, {
data: payload,
});
if (code === 200) {
message.success(env ? '更新变量成功' : '新建变量成功');
} else {
message.error(data);
}
setLoading(false);
handleCancel(data);
} catch (error: any) {
setLoading(false);
}
setLoading(false);
handleCancel(data);
};
useEffect(() => {
+2 -2
View File
@@ -172,7 +172,7 @@ const CheckUpdate = ({ socketMessage }: any) => {
<Countdown
className="inline-countdown"
format="ss"
value={Date.now() + 1000 * 10}
value={Date.now() + 1000 * 30}
/>
</span>
@@ -181,7 +181,7 @@ const CheckUpdate = ({ socketMessage }: any) => {
});
setTimeout(() => {
window.location.reload();
}, 10000);
}, 30000);
}
}, [socketMessage]);
+12 -7
View File
@@ -1,8 +1,13 @@
export const version = '2.11.0';
export const changeLogLink = 'https://t.me/jiao_long/254';
export const changeLog = `2.11.0 版本说明
1. 使用sqlite替换nedb,增加数据库稳定性
2. 任务添加标签功能,感谢https://github.com/kilo5hz
3. 支持自定义bot仓库,感谢https://github.com/chiupam
5. 其他bug修复
export const version = '2.11.1';
export const changeLogLink = 'https://t.me/jiao_long/261';
export const changeLog = `2.11.1 版本说明
1. 修复openapi获取tokentoken认证
2. 修复环境变量搜索,排序,更新
3. 修复重置应用秘钥
4. 修复环境变量更新时间显示
5. 修复定时默认任务排序
6. task支持运行pyc文件,感谢https://github.com/chiupam
6. 移除ghproxy默认代理,增加新配置ProxyUrl,支持http或者socks代理。例如 http://127.0.0.1:7890
7. 更换JavaScript cdn地址
8. 其他bug修复
`;