Compare commits

...

28 Commits

Author SHA1 Message Date
whyour fa6d57d809 修复shell发送通知 2022-04-09 11:13:08 +08:00
whyour 1060fc7476 修复并发日志目录 2022-04-06 12:18:16 +08:00
whyour 56bc38e9e7 更新readme 2022-04-05 23:24:27 +08:00
whyour 18be65d6fe 更新发布脚本 2022-04-05 23:17:03 +08:00
whyour 3409085195 更新发布脚本 2022-04-05 23:14:47 +08:00
whyour 17e17ac077 增加发布脚本 2022-04-05 23:11:48 +08:00
whyour c655e1da38 修复日志目录判断 2022-04-05 00:28:14 +08:00
whyour 0ea158724f 修复日志目录获取 2022-04-05 00:21:32 +08:00
whyour fb521498ff 修复task日志打印 2022-04-04 23:32:27 +08:00
whyour 399550ccad 修复日志创建目录 2022-04-04 22:40:02 +08:00
whyour c7c30c86f2 修复目录获取 2022-04-04 18:06:21 +08:00
whyour 5f6c0882d6 修改版本说明 2022-04-04 17:28:15 +08:00
whyour 6e05a4f3a5 更新版本号 v2.12.1 2022-04-04 17:24:42 +08:00
whyour ea8aa6a231 修改获取版本链接 2022-04-04 17:17:34 +08:00
whyour ae2570c677 修复shell日志路径截取 2022-04-03 22:31:11 +08:00
whyour c76d952d41 修改yarn命令 2022-04-03 21:49:20 +08:00
whyour cdf9fb24be 修复定时任务获取日志 2022-04-03 20:00:31 +08:00
whyour 2131e16781 删除console 2022-04-03 19:50:44 +08:00
whyour b0c8425639 修复日志路径拼接规则 2022-04-03 19:32:44 +08:00
whyour f0869567de 七牛云改为http访问 2022-04-01 08:29:16 +08:00
whyour be2a19949b 修复获取日志相对目录 2022-03-30 11:34:36 +08:00
whyour 8627cccb58 修改日志路径合并方式 2022-03-30 11:17:11 +08:00
whyour 4a8eaebf17 修复获取任务日志路径 2022-03-30 10:57:43 +08:00
kan3Git e7edd0a5a4 tg发送消息改json (#1269)
发现有带&的消息都会漏掉&后面的内容,改为JSON发送
2022-03-26 17:23:54 +08:00
chen310 9ccbea0a04 修复PushDeer推送Python版本错误 (#1270)
* 修复PushDeer推送Python版本错误
2022-03-26 17:20:02 +08:00
whyour ab715ef840 修复系统pushDeer通知 2022-03-26 17:17:13 +08:00
whyour 117822fe7c 修改任务最大内存占用200兆 2022-03-26 16:53:03 +08:00
whyour da922678a1 修复定时任务获取日志目录 2022-03-26 00:29:42 +08:00
20 changed files with 254 additions and 140 deletions
+4 -3
View File
@@ -27,9 +27,10 @@ jobs:
- name: build front and back
run: |
yarn install
yarn build:front
yarn build:back
npm i -g pnpm
pnpm install
pnpm build:front
pnpm build:back
- name: copy to static repo
env:
+5 -3
View File
@@ -22,7 +22,7 @@
[docker-image-size-url]: https://hub.docker.com/r/whyour/qinglong
</div>
[![](https://z3.ax1x.com/2021/11/18/I7KrTg.jpg)](https://whyour.cn)
[![](https://user-images.githubusercontent.com/22700758/161788855-c4e51cb8-d4e9-44fe-bb17-ee1a56c8549b.png)](https://whyour.cn)
简体中文 | [English](./README-en.md)
@@ -168,8 +168,10 @@ task <file_path> desi <env_name> <account_number>
$ git clone git@github.com:whyour/qinglong.git
$ cd qinglong
$ cp .env.example .env
$ yarn install
$ yarn start
# 推荐使用 pnpm https://pnpm.io/zh/installation
$ npm install -g pnpm
$ pnpm install
$ pnpm start
```
打开你的浏览器,访问 http://127.0.0.1:5700
+1 -1
View File
@@ -4,7 +4,7 @@ import { createRandomString } from './util';
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
const lastVersionFile = 'https://qn.whyour.cn/version.ts';
const lastVersionFile = 'http://qn.whyour.cn/version.ts?v=2.12.1';
const envFound = dotenv.config();
const rootPath = process.cwd();
+1 -1
View File
@@ -39,7 +39,7 @@ export class PushDeerNotification extends NotificationBaseInfo {
export class BarkNotification extends NotificationBaseInfo {
public barkPush = '';
public barkIcon = 'https://qn.whyour.cn/logo.png';
public barkIcon = 'http://qn.whyour.cn/logo.png';
public barkSound = '';
public barkGroup = 'qinglong';
}
+52 -19
View File
@@ -9,6 +9,7 @@ import { getFileContentByName, concurrentRun, fileExist } from '../config/util';
import { promises, existsSync } from 'fs';
import { promisify } from 'util';
import { Op } from 'sequelize';
import path from 'path';
@Service()
export default class CronService {
@@ -16,7 +17,7 @@ export default class CronService {
private isSixCron(cron: Crontab) {
const { schedule } = cron;
if (schedule.split(/ +/).length === 6) {
if (schedule?.split(/ +/).length === 6) {
return true;
}
return false;
@@ -194,11 +195,12 @@ export default class CronService {
}
}
const err = await this.killTask(doc.command);
const logFileExist = await fileExist(doc.log_path);
if (doc.log_path && logFileExist) {
const absolutePath = path.resolve(config.logPath, `${doc.log_path}`);
const logFileExist = doc.log_path && (await fileExist(absolutePath));
if (logFileExist) {
const str = err ? `\n${err}` : '';
fs.appendFileSync(
`${doc.log_path}`,
`${absolutePath}`,
`${str}\n## 执行结束... ${new Date()
.toLocaleString('zh', { hour12: false })
.replace(' 24:', ' 00:')} `,
@@ -256,6 +258,8 @@ export default class CronService {
}
let { id, command, log_path } = cron;
const absolutePath = path.resolve(config.logPath, `${log_path}`);
const logFileExist = log_path && (await fileExist(absolutePath));
this.logger.silly('Running job');
this.logger.silly('ID: ' + id);
@@ -276,13 +280,13 @@ export default class CronService {
{ where: { id } },
);
cp.stderr.on('data', (data) => {
if (log_path) {
fs.appendFileSync(`${log_path}`, `${data}`);
if (logFileExist) {
fs.appendFileSync(`${absolutePath}`, `${data}`);
}
});
cp.on('error', (err) => {
if (log_path) {
fs.appendFileSync(`${log_path}`, `${JSON.stringify(err)}`);
if (logFileExist) {
fs.appendFileSync(`${absolutePath}`, `${JSON.stringify(err)}`);
}
});
@@ -323,8 +327,10 @@ export default class CronService {
return '';
}
if (doc.log_path) {
return getFileContentByName(`${doc.log_path}`);
const absolutePath = path.resolve(config.logPath, `${doc.log_path}`);
const logFileExist = doc.log_path && (await fileExist(absolutePath));
if (logFileExist) {
return getFileContentByName(`${absolutePath}`);
}
const [, commandStr, url] = doc.command.split(/ +/);
let logPath = this.getKey(commandStr);
@@ -353,6 +359,21 @@ export default class CronService {
return [];
}
if (doc.log_path) {
const relativeDir = path.dirname(`${doc.log_path}`);
const dir = path.resolve(config.logPath, relativeDir);
if (existsSync(dir)) {
let files = await promises.readdir(dir);
return files
.map((x) => ({
filename: x,
directory: relativeDir.replace(config.logPath, ''),
time: fs.statSync(`${dir}/${x}`).mtime.getTime(),
}))
.sort((a, b) => b.time - a.time);
}
}
const [, commandStr, url] = doc.command.split(/ +/);
let logPath = this.getKey(commandStr);
const isQlCommand = doc.command.startsWith('ql ');
@@ -380,14 +401,26 @@ export default class CronService {
}
}
private getKey(command: string) {
private getKey(command: string): string {
const start =
command.lastIndexOf('/') !== -1 ? command.lastIndexOf('/') + 1 : 0;
const end =
command.lastIndexOf('.') !== -1
? command.lastIndexOf('.')
: command.length;
return command.substring(start, end);
const tmpStr = command.substring(0, start - 1);
let index = 0;
if (tmpStr.lastIndexOf('/') !== -1 && tmpStr.startsWith('http')) {
index = tmpStr.lastIndexOf('/');
} else if (tmpStr.lastIndexOf(':') !== -1 && tmpStr.startsWith('git@')) {
index = tmpStr.lastIndexOf(':');
}
if (index) {
return `${tmpStr.substring(index + 1)}_${command.substring(start, end)}`;
} else {
return command.substring(start, end);
}
}
private make_command(tab: Crontab) {
@@ -400,7 +433,7 @@ export default class CronService {
var crontab_string = '';
tabs.forEach((tab) => {
const _schedule = tab.schedule && tab.schedule.split(/ +/);
if (tab.isDisabled === 1 || _schedule.length !== 5) {
if (tab.isDisabled === 1 || _schedule!.length !== 5) {
crontab_string += '# ';
crontab_string += tab.schedule;
crontab_string += ' ';
@@ -426,22 +459,22 @@ export default class CronService {
public import_crontab() {
exec('crontab -l', (error, stdout, stderr) => {
var lines = stdout.split('\n');
var namePrefix = new Date().getTime();
const lines = stdout.split('\n');
const namePrefix = new Date().getTime();
lines.reverse().forEach(async (line, index) => {
line = line.replace(/\t+/g, ' ');
var regex =
const regex =
/^((\@[a-zA-Z]+\s+)|(([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+))/;
var command = line.replace(regex, '').trim();
var schedule = line.replace(command, '').trim();
const command = line.replace(regex, '').trim();
const schedule = line.replace(command, '').trim();
if (
command &&
schedule &&
cron_parser.parseExpression(schedule).hasNext()
) {
var name = namePrefix + '_' + index;
const name = namePrefix + '_' + index;
const _crontab = await CrontabModel.findOne({
where: { command, schedule },
+3 -4
View File
@@ -119,15 +119,14 @@ export default class NotificationService {
private async pushDeer() {
const { pushDeerKey } = this.params;
// https://api2.pushdeer.com/message/push?pushkey=<key>&text=标题&desp=<markdown>&type=markdown
const url = `https://api2.pushdeer.com/message/push`;
const res: any = await got
.post(url, {
timeout: this.timeout,
retry: 0,
body: `pushkey=${pushDeerKey}&text=${
this.title
}&desp=${encodeURIComponent(this.content)}&type=markdown`,
body: `pushkey=${pushDeerKey}&text=${encodeURIComponent(
this.title,
)}&desp=${encodeURIComponent(this.content)}&type=markdown`,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
})
.json();
+46 -36
View File
@@ -16,6 +16,8 @@ export default class ScheduleService {
private intervalSchedule = new ToadScheduler();
private maxBuffer = 200 * 1024 * 1024;
constructor(@Inject('logger') private logger: winston.Logger) {}
async createCronTask({ id = 0, command, name, schedule = '' }: Crontab) {
@@ -32,25 +34,29 @@ export default class ScheduleService {
_id,
nodeSchedule.scheduleJob(id + '', schedule, async () => {
try {
exec(command, async (error, stdout, stderr) => {
if (error) {
await this.logger.info(
'执行任务%s失败,时间:%s, 错误信息:%j',
command,
new Date().toLocaleString(),
error,
);
}
exec(
command,
{ maxBuffer: this.maxBuffer },
async (error, stdout, stderr) => {
if (error) {
await this.logger.info(
'执行任务%s失败,时间:%s, 错误信息:%j',
command,
new Date().toLocaleString(),
error,
);
}
if (stderr) {
await this.logger.info(
'执行任务%s失败,时间:%s, 错误信息:%j',
command,
new Date().toLocaleString(),
stderr,
);
}
});
if (stderr) {
await this.logger.info(
'执行任务%s失败,时间:%s, 错误信息:%j',
command,
new Date().toLocaleString(),
stderr,
);
}
},
);
} catch (error) {
await this.logger.info(
'执行任务%s失败,时间:%s, 错误信息:%j',
@@ -83,25 +89,29 @@ export default class ScheduleService {
);
const task = new Task(name, async () => {
try {
exec(command, async (error, stdout, stderr) => {
if (error) {
await this.logger.info(
'执行任务%s失败,时间:%s, 错误信息:%j',
command,
new Date().toLocaleString(),
error,
);
}
exec(
command,
{ maxBuffer: this.maxBuffer },
async (error, stdout, stderr) => {
if (error) {
await this.logger.info(
'执行任务%s失败,时间:%s, 错误信息:%j',
command,
new Date().toLocaleString(),
error,
);
}
if (stderr) {
await this.logger.info(
'执行任务%s失败,时间:%s, 错误信息:%j',
command,
new Date().toLocaleString(),
stderr,
);
}
});
if (stderr) {
await this.logger.info(
'执行任务%s失败,时间:%s, 错误信息:%j',
command,
new Date().toLocaleString(),
stderr,
);
}
},
);
} catch (error) {
await this.logger.info(
'执行任务%s失败,时间:%s, 错误信息:%j',
+1 -1
View File
@@ -51,7 +51,7 @@ export PUSH_KEY=""
## 下方填写app提供的设备码,例如:https://api.day.app/123 那么此处的设备码就是123
export BARK_PUSH=""
## 下方填写推送图标设置,自定义推送图标(需iOS15或以上)
export BARK_ICON="https://qn.whyour.cn/logo.png"
export BARK_ICON="http://qn.whyour.cn/logo.png"
## 下方填写推送声音设置,例如choo,具体值请在bark-推送铃声-查看所有铃声
export BARK_SOUND=""
## 下方填写推送消息分组,默认为"QingLong"
+8 -4
View File
@@ -43,7 +43,7 @@ let PUSHDEER_KEY = '';
//此处填你BarkAPP的信息(IP/设备码,例如:https://api.day.app/XXXXXXXX)
let BARK_PUSH = '';
//BARK app推送图标,自定义推送图标(需iOS15或以上)
let BARK_ICON = 'https://qn.whyour.cn/logo.png';
let BARK_ICON = 'http://qn.whyour.cn/logo.png';
//BARK app推送铃声,铃声列表去APP查看复制填写
let BARK_SOUND = '';
//BARK app推送消息的分组, 默认为"QingLong"
@@ -383,7 +383,7 @@ function PushDeerNotify(text, desp, time = 2100) {
console.log(err);
} else {
data = JSON.parse(data);
// 通过反悔的result的长度来判断是否成功
// 通过返回的result的长度来判断是否成功
if (
data.content.result.length !== undefined &&
data.content.result.length > 0
@@ -529,9 +529,13 @@ function tgBotNotify(text, desp) {
if (TG_BOT_TOKEN && TG_USER_ID) {
const options = {
url: `https://${TG_API_HOST}/bot${TG_BOT_TOKEN}/sendMessage`,
body: `chat_id=${TG_USER_ID}&text=${text}\n\n${desp}&disable_web_page_preview=true`,
json: {
chat_id: `${TG_USER_ID}`,
text: `${text}\n\n${desp}`,
disable_web_page_preview: true,
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Type': 'application/json',
},
timeout,
};
+1 -1
View File
@@ -271,7 +271,7 @@ def pushdeer(title: str, content: str) -> None:
print("PushDeer 服务的 DEER_KEY 未设置!!\n取消推送")
return
print("PushDeer 服务启动")
data = {"text": title, "desp": urllib.parse.urlencode({"text": content})}
data = {"text": title, "desp": content, "type": "markdown", "pushkey": push_config.get("DEER_KEY")}
url = 'https://api2.pushdeer.com/message/push'
response = requests.post(url, data=data).json()
+7 -3
View File
@@ -5,8 +5,9 @@ const envFound = dotenv.config();
const accessKey = process.env.QINIU_AK;
const secretKey = process.env.QINIU_SK;
const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
const key = 'version.ts';
const options = {
scope: process.env.QINIU_SCOPE,
scope: `${process.env.QINIU_SCOPE}:${key}`,
};
const putPolicy = new qiniu.rs.PutPolicy(options);
const uploadToken = putPolicy.uploadToken(mac);
@@ -14,8 +15,11 @@ const uploadToken = putPolicy.uploadToken(mac);
const localFile = 'src/version.ts';
const config = new qiniu.conf.Config({ zone: qiniu.zone.Zone_z1 });
const formUploader = new qiniu.form_up.FormUploader(config);
const putExtra = new qiniu.form_up.PutExtra('', '', 'text/plain');
const key = 'version.ts';
const putExtra = new qiniu.form_up.PutExtra(
'',
'',
'text/plain; charset=utf-8',
);
// 文件上传
formUploader.putFile(
uploadToken,
+3 -3
View File
@@ -178,7 +178,7 @@ update_cron() {
notify_api() {
local title=$1
local content=$1
local content=$2
local currentTimeStamp=$(date +%s)
local api=$(
curl -s --noproxy "*" "http://0.0.0.0:5600/api/system/notify?t=$currentTimeStamp" \
@@ -196,9 +196,9 @@ notify_api() {
code=$(echo $api | jq -r .code)
message=$(echo $api | jq -r .message)
if [[ $code == 200 ]]; then
echo -e "成功"
echo -e "通知发送成功"
else
echo -e "失败(${message})"
echo -e "通知失败(${message})"
fi
}
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
echo -e "开始发布"
echo -e "切换master分支"
git checkout master
echo -e "合并develop代码"
git merge origin/develop
echo -e "提交master代码"
git push
echo -e "更新cdn文件"
ts-node sample/tool.ts
string=$(cat src/version.ts | grep "version" | egrep "[^\']*" -o | egrep "\d\.*")
version="v$string"
echo -e "当前版本$version"
echo -e "删除已经存在的本地tag"
git tag -d "$version" &>/dev/null
echo -e "删除已经存在的远程tag"
git push origin :refs/tags/$version &>/dev/null
echo -e "创建新tag"
git tag -a "$version" -m "release $version"
echo -e "提交tag"
git push --tags
echo -e "完成发布"
+69 -41
View File
@@ -7,14 +7,14 @@ dir_shell=$QL_DIR/shell
## 选择python3还是node
define_program() {
local first_param=$1
if [[ $first_param == *.js ]]; then
local file_param=$1
if [[ $file_param == *.js ]]; then
which_program="node"
elif [[ $first_param == *.py ]] || [[ $first_param == *.pyc ]]; then
elif [[ $file_param == *.py ]] || [[ $file_param == *.pyc ]]; then
which_program="python3"
elif [[ $first_param == *.sh ]]; then
elif [[ $file_param == *.sh ]]; then
which_program="bash"
elif [[ $first_param == *.ts ]]; then
elif [[ $file_param == *.ts ]]; then
which_program="ts-node-transpile-only"
else
which_program=""
@@ -76,41 +76,48 @@ run_nohup() {
## 正常运行单个脚本,$1:传入参数
run_normal() {
local first_param=$1
define_program "$first_param"
if [[ $first_param == *.js ]]; then
local file_param=$1
define_program "$file_param"
if [[ $file_param == *.js ]]; then
if [[ $# -eq 1 ]]; then
random_delay
fi
fi
log_time=$(date "+%Y-%m-%d-%H-%M-%S")
log_dir_tmp="${first_param##*/}"
log_dir_tmp_path="${first_param%%/*}"
log_dir_tmp="${file_param##*/}"
if [[ $file_param =~ "/" ]]; then
if [[ $file_param == /* ]]; then
log_dir_tmp_path="${file_param:1}"
else
log_dir_tmp_path="${file_param}"
fi
fi
log_dir_tmp_path="${log_dir_tmp_path%/*}"
log_dir_tmp_path="${log_dir_tmp_path##*/}"
[[ $log_dir_tmp_path ]] && log_dir_tmp="${log_dir_tmp_path}_${log_dir_tmp}"
log_dir="$dir_log/${log_dir_tmp%%.*}"
log_dir="${log_dir_tmp%.*}"
log_path="$log_dir/$log_time.log"
cmd="&>> $log_path"
cmd="&>> $dir_log/$log_path"
[[ "$show_log" == "true" ]] && cmd=""
make_dir "$log_dir"
make_dir "$dir_log/$log_dir"
local begin_time=$(date '+%Y-%m-%d %H:%M:%S')
local begin_timestamp=$(date "+%s")
eval echo -e "\#\# 开始执行... $begin_time\\\n" $cmd
[[ -f $task_error_log_path ]] && eval cat $task_error_log_path $cmd
local id=$(cat $list_crontab_user | grep -E "$cmd_task $first_param" | perl -pe "s|.*ID=(.*) $cmd_task $first_param\.*|\1|" | head -1 | awk -F " " '{print $1}')
local id=$(cat $list_crontab_user | grep -E "$cmd_task $file_param" | perl -pe "s|.*ID=(.*) $cmd_task $file_param\.*|\1|" | head -1 | awk -F " " '{print $1}')
[[ $id ]] && update_cron "\"$id\"" "0" "$$" "$log_path" "$begin_timestamp"
eval . $file_task_before "$@" $cmd
cd $dir_scripts
local relative_path="${first_param%/*}"
if [[ ! -z ${relative_path} ]] && [[ ${first_param} =~ "/" ]]; then
local relative_path="${file_param%/*}"
if [[ ! -z ${relative_path} ]] && [[ ${file_param} =~ "/" ]]; then
cd ${relative_path}
first_param=${first_param/$relative_path\//}
file_param=${file_param/$relative_path\//}
fi
eval timeout -k 10s $command_timeout_time $which_program $first_param $cmd
eval timeout -k 10s $command_timeout_time $which_program $file_param $cmd
eval . $file_task_after "$@" $cmd
local end_time=$(date '+%Y-%m-%d %H:%M:%S')
@@ -122,7 +129,7 @@ run_normal() {
## 并发执行时,设定的 RandomDelay 不会生效,即所有任务立即执行
run_concurrent() {
local first_param="$1"
local file_param="$1"
local env_param="$2"
local num_param=$(echo "$3" | perl -pe "s|.*$2(.*)|\1|")
if [[ ! $env_param ]]; then
@@ -145,17 +152,24 @@ run_concurrent() {
local cookieStr=$(echo ${array_run[*]} | sed 's/\ /\&/g')
[[ ! -z $cookieStr ]] && export ${env_param}=${cookieStr}
define_program "$first_param"
define_program "$file_param"
log_time=$(date "+%Y-%m-%d-%H-%M-%S")
log_dir_tmp="${first_param##*/}"
log_dir_tmp_path="${first_param%%/*}"
log_dir_tmp="${file_param##*/}"
if [[ $file_param =~ "/" ]]; then
if [[ $file_param == /* ]]; then
log_dir_tmp_path="${file_param:1}"
else
log_dir_tmp_path="${file_param}"
fi
fi
log_dir_tmp_path="${log_dir_tmp_path%/*}"
log_dir_tmp_path="${log_dir_tmp_path##*/}"
[[ $log_dir_tmp_path ]] && log_dir_tmp="${log_dir_tmp_path}_${log_dir_tmp}"
log_dir="$dir_log/${log_dir_tmp%%.*}"
log_dir="${log_dir_tmp%.*}"
log_path="$log_dir/$log_time.log"
cmd="&>> $log_path"
cmd="&>> $dir_log/$log_path"
[[ "$show_log" == "true" ]] && cmd=""
make_dir $log_dir
make_dir "$dir_log/$log_dir"
local begin_time=$(date '+%Y-%m-%d %H:%M:%S')
local begin_timestamp=$(date "+%s")
@@ -163,7 +177,7 @@ run_concurrent() {
eval echo -e "\#\# 开始执行... $begin_time\\\n" $cmd
[[ -f $task_error_log_path ]] && eval cat $task_error_log_path $cmd
local id=$(cat $list_crontab_user | grep -E "$cmd_task $first_param" | perl -pe "s|.*ID=(.*) $cmd_task $first_param\.*|\1|" | head -1 | awk -F " " '{print $1}')
local id=$(cat $list_crontab_user | grep -E "$cmd_task $file_param" | perl -pe "s|.*ID=(.*) $cmd_task $file_param\.*|\1|" | head -1 | awk -F " " '{print $1}')
[[ $id ]] && update_cron "\"$id\"" "0" "$$" "$log_path" "$begin_timestamp"
eval . $file_task_before "$@" $cmd
@@ -172,20 +186,20 @@ run_concurrent() {
single_log_time=$(date "+%Y-%m-%d-%H-%M-%S.%N")
cd $dir_scripts
local relative_path="${first_param%/*}"
if [[ ! -z ${relative_path} ]] && [[ ${first_param} =~ "/" ]]; then
local relative_path="${file_param%/*}"
if [[ ! -z ${relative_path} ]] && [[ ${file_param} =~ "/" ]]; then
cd ${relative_path}
first_param=${first_param/$relative_path\//}
file_param=${file_param/$relative_path\//}
fi
for i in "${!array[@]}"; do
export ${env_param}=${array[i]}
single_log_path="$log_dir/${single_log_time}_$((i + 1)).log"
timeout -k 10s $command_timeout_time $which_program $first_param &>$single_log_path &
single_log_path="$dir_log/$log_dir/${single_log_time}_$((i + 1)).log"
timeout -k 10s $command_timeout_time $which_program $file_param &>$single_log_path &
done
wait
for i in "${!array[@]}"; do
single_log_path="$log_dir/${single_log_time}_$((i + 1)).log"
single_log_path="$dir_log/$log_dir/${single_log_time}_$((i + 1)).log"
eval cat $single_log_path $cmd
[[ -f $single_log_path ]] && rm -f $single_log_path
done
@@ -210,14 +224,21 @@ run_designated() {
define_program "$file_param"
log_time=$(date "+%Y-%m-%d-%H-%M-%S")
log_dir_tmp="${file_param##*/}"
log_dir_tmp_path="${file_param%%/*}"
if [[ $file_param =~ "/" ]]; then
if [[ $file_param == /* ]]; then
log_dir_tmp_path="${file_param:1}"
else
log_dir_tmp_path="${file_param}"
fi
fi
log_dir_tmp_path="${log_dir_tmp_path%/*}"
log_dir_tmp_path="${log_dir_tmp_path##*/}"
[[ $log_dir_tmp_path ]] && log_dir_tmp="${log_dir_tmp_path}_${log_dir_tmp}"
log_dir="$dir_log/${log_dir_tmp%%.*}"
log_dir="${log_dir_tmp%.*}"
log_path="$log_dir/$log_time.log"
cmd="&>> $log_path"
cmd="&>> $dir_log/$log_path"
[[ "$show_log" == "true" ]] && cmd=""
make_dir $log_dir
make_dir "$dir_log/$log_dir"
local begin_time=$(date '+%Y-%m-%d %H:%M:%S')
local begin_timestamp=$(date "+%s")
@@ -266,14 +287,21 @@ run_else() {
define_program "$file_param"
log_time=$(date "+%Y-%m-%d-%H-%M-%S")
log_dir_tmp="${file_param##*/}"
log_dir_tmp_path="${file_param%%/*}"
if [[ $file_param =~ "/" ]]; then
if [[ $file_param == /* ]]; then
log_dir_tmp_path="${file_param:1}"
else
log_dir_tmp_path="${file_param}"
fi
fi
log_dir_tmp_path="${log_dir_tmp_path%/*}"
log_dir_tmp_path="${log_dir_tmp_path##*/}"
[[ $log_dir_tmp_path ]] && log_dir_tmp="${log_dir_tmp_path}_${log_dir_tmp}"
log_dir="$dir_log/${log_dir_tmp%%.*}"
log_dir="${log_dir_tmp%.*}"
log_path="$log_dir/$log_time.log"
cmd="&>> $log_path"
cmd="&>> $dir_log/$log_path"
[[ "$show_log" == "true" ]] && cmd=""
make_dir $log_dir
make_dir "$dir_log/$log_dir"
local begin_time=$(date '+%Y-%m-%d %H:%M:%S')
local begin_timestamp=$(date "+%s")
@@ -338,7 +366,7 @@ main() {
esac
;;
esac
[[ -f $log_path ]] && cat $log_path
[[ -f "$dir_log/$log_path" ]] && cat "$dir_log/$log_path"
elif [[ $# -eq 0 ]]; then
echo
usage
+1 -1
View File
@@ -226,7 +226,7 @@ export default function (props: any) {
selectedKeys={[props.location.pathname]}
loading={loading}
ErrorBoundary={Sentry.ErrorBoundary}
logo={<Image preview={false} src="https://qn.whyour.cn/logo.png" />}
logo={<Image preview={false} src="http://qn.whyour.cn/logo.png" />}
title={
<>
<span style={{ fontSize: 16 }}></span>
+1 -1
View File
@@ -233,7 +233,7 @@ const Initialization = () => {
<img
alt="logo"
className={styles.logo}
src="https://qn.whyour.cn/logo.png"
src="http://qn.whyour.cn/logo.png"
/>
<span className={styles.title}></span>
</div>
+1 -1
View File
@@ -135,7 +135,7 @@ const Login = () => {
<img
alt="logo"
className={styles.logo}
src="https://qn.whyour.cn/logo.png"
src="http://qn.whyour.cn/logo.png"
/>
<span className={styles.title}>
{twoFactor ? '两步验证' : config.siteName}
+1 -1
View File
@@ -10,7 +10,7 @@ const About = () => {
<img
alt="logo"
style={{ width: 140, marginRight: 20 }}
src="https://qn.whyour.cn/logo.png"
src="http://qn.whyour.cn/logo.png"
/>
<div className={styles.right}>
<span className={styles.title}></span>
+8 -2
View File
@@ -77,7 +77,7 @@ export default {
{ value: 'gotify', label: 'Gotify' },
{ value: 'goCqHttpBot', label: 'GoCqHttpBot' },
{ value: 'serverChan', label: 'Server酱' },
{ value: 'PushDeer', label: 'PushDeer' },
{ value: 'pushDeer', label: 'PushDeer' },
{ value: 'bark', label: 'Bark' },
{ value: 'telegramBot', label: 'Telegram机器人' },
{ value: 'dingtalkBot', label: '钉钉机器人' },
@@ -114,7 +114,13 @@ export default {
serverChan: [
{ label: 'serverChanKey', tip: 'Server酱SENDKEY', required: true },
],
PushDeer: [{ label: 'PushDeerKey', tip: 'PushDeer的Key', required: true }],
pushDeer: [
{
label: 'pushDeerKey',
tip: 'PushDeer的Keyhttps://github.com/easychen/pushdeer',
required: true,
},
],
bark: [
{
label: 'barkPush',
+9 -14
View File
@@ -1,15 +1,10 @@
export const version = '2.12.0';
export const changeLogLink = 'https://t.me/jiao_long/288';
export const changeLog = `2.12.0 版本说明
1. 全新定时任务详情,支持日志查看、脚本编辑
2. openapi增加发送通知接口,可用于脚本直接调用
3. 增加pushDeer推送,感谢 https://github.com/NekoMio PR
4. 增加public服务,当服务异常时,查询服务状态及日志,供页面使用。
5. 增加ql check可视化错误提示
6. 修改openapi获取token逻辑,最多存储5个可用的token。
7. 调整数据目录,log、db、scripts、config等目录迁移到 /ql/data 目录,docker映射只需映射data目录
8. 版本文件存储到七牛云,方便检查更新
9. 修复编辑应用初始值
10. 修复退出登录和定时任务搜索
11. 其他bug修复
export const version = '2.12.1';
export const changeLogLink = 'https://t.me/jiao_long/289';
export const changeLog = `2.12.1 版本说明
1. 修复定时任务详情获取日志
2. 修复系统通知pushdeer
3. 修复python pushDeer推送,感谢 https://github.com/chen310 PR
3. nodejs telegram推送改为json方式,感谢 https://github.com/kan3Git PR
4. 修复日志目录拼接规则
5. 其他bug修复
`;