@whyour/qinglong 2.20.2-3 → 2.21.0-10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +5 -0
- package/AGENTS.md +43 -0
- package/README-en.md +11 -0
- package/README.md +11 -0
- package/back/protos/api.proto +3 -0
- package/deploy/kubernetes/README.md +81 -0
- package/deploy/kubernetes/base/kustomization.yaml +5 -0
- package/deploy/kubernetes/base/qinglong.yaml +95 -0
- package/deploy/kubernetes/overlays/example/kustomization.yaml +10 -0
- package/docker/Dockerfile +51 -69
- package/docker/Dockerfile.310 +94 -0
- package/docker/Dockerfile.debian +120 -0
- package/docker/{310.Dockerfile → Dockerfile.debian310} +13 -5
- package/docker/docker-entrypoint.sh +95 -3
- package/docs/PROJECT_ARCHITECTURE.md +550 -0
- package/package.json +29 -28
- package/sample/config.sample.sh +19 -3
- package/sample/notify.js +145 -9
- package/sample/notify.py +110 -11
- package/shell/api.sh +51 -21
- package/shell/bot.sh +30 -16
- package/shell/check.sh +21 -19
- package/shell/lang/en.sh +105 -0
- package/shell/lang/zh.sh +105 -0
- package/shell/otask.sh +117 -28
- package/shell/preload/client.js +20 -2
- package/shell/preload/esm-loader.mjs +41 -0
- package/shell/preload/sitecustomize.js +36 -0
- package/shell/pub.sh +8 -8
- package/shell/rmlog.sh +5 -5
- package/shell/share.sh +50 -31
- package/shell/start.sh +40 -27
- package/shell/task.sh +10 -2
- package/shell/update.sh +22 -22
- package/static/build/api/config.js +17 -7
- package/static/build/api/cron.js +40 -3
- package/static/build/api/dashboard.js +344 -0
- package/static/build/api/env.js +40 -2
- package/static/build/api/index.js +2 -0
- package/static/build/api/log.js +15 -5
- package/static/build/api/script.js +34 -9
- package/static/build/api/system.js +22 -8
- package/static/build/api/user.js +6 -5
- package/static/build/app.js +22 -19
- package/static/build/config/const.js +8 -6
- package/static/build/config/container.js +12 -0
- package/static/build/config/grpcCerts.js +150 -0
- package/static/build/config/index.js +6 -4
- package/static/build/config/util.js +69 -18
- package/static/build/data/cron.js +3 -1
- package/static/build/data/cronStats.js +59 -0
- package/static/build/data/env.js +2 -0
- package/static/build/data/notify.js +18 -1
- package/static/build/data/runningInstance.js +57 -0
- package/static/build/data/sock.js +1 -0
- package/static/build/loaders/app.js +7 -7
- package/static/build/loaders/db.js +8 -2
- package/static/build/loaders/deps.js +1 -22
- package/static/build/loaders/express.js +19 -15
- package/static/build/loaders/initData.js +20 -2
- package/static/build/loaders/initFile.js +3 -1
- package/static/build/loaders/initTask.js +3 -2
- package/static/build/loaders/server.js +1 -1
- package/static/build/protos/api.js +23 -1
- package/static/build/schedule/addCron.js +67 -10
- package/static/build/schedule/api.js +1 -1
- package/static/build/schedule/client.js +9 -1
- package/static/build/schedule/delCron.js +11 -1
- package/static/build/schedule/health.js +1 -1
- package/static/build/services/config.js +19 -5
- package/static/build/services/cron.js +198 -38
- package/static/build/services/dependence.js +19 -18
- package/static/build/services/env.js +31 -3
- package/static/build/services/grpc.js +32 -6
- package/static/build/services/http.js +33 -18
- package/static/build/services/notify.js +87 -8
- package/static/build/services/open.js +2 -1
- package/static/build/services/sshKey.js +6 -3
- package/static/build/services/subscription.js +8 -5
- package/static/build/services/system.js +34 -9
- package/static/build/services/user.js +39 -13
- package/static/build/shared/auth.js +7 -1
- package/static/build/shared/i18n.js +160 -0
- package/static/build/shared/pLimit.js +15 -3
- package/static/build/shared/runCron.js +5 -0
- package/static/build/shared/store.js +7 -0
- package/static/build/validation/schedule.js +10 -0
- package/static/dist/1089.0ecc5383.async.js +1 -0
- package/static/dist/1147.62793604.async.js +1 -0
- package/static/dist/1192.4e5740f2.async.js +1 -0
- package/static/dist/1214.c6469b53.async.js +1 -0
- package/static/dist/134.54df9e38.async.js +1 -0
- package/static/dist/1352.96a77e1d.async.js +1 -0
- package/static/dist/{1765.d8e002d7.async.js → 1765.5ac01a93.async.js} +1 -1
- package/static/dist/1836.f0b74cf1.async.js +1 -0
- package/static/dist/{1885.e0d00d2d.async.js → 1885.e1ea09f6.async.js} +1 -1
- package/static/dist/1967.3f3945d0.async.js +1 -0
- package/static/dist/{2096.383c1047.async.js → 2096.6d98fd12.async.js} +1 -1
- package/static/dist/2208.85285476.async.js +1 -0
- package/static/dist/2286.f371c743.async.js +1 -0
- package/static/dist/2476.4e9b0992.async.js +1 -0
- package/static/dist/2537.2b262ee0.async.js +1 -0
- package/static/dist/{255.12f03ab2.async.js → 255.8a80b983.async.js} +1 -1
- package/static/dist/2635.d4c59d23.async.js +1 -0
- package/static/dist/2808.cdc0995c.async.js +1 -0
- package/static/dist/{2821.be3dc88e.async.js → 2821.651f31e5.async.js} +1 -1
- package/static/dist/2986.4c49eef7.async.js +1 -0
- package/static/dist/300.08ac9875.async.js +1 -0
- package/static/dist/3191.545ab873.async.js +1 -0
- package/static/dist/3714.8d6dba9e.async.js +1 -0
- package/static/dist/3906.a5eee612.async.js +1 -0
- package/static/dist/{6541.a6d499de.async.js → 3948.4fe809fd.async.js} +1 -1
- package/static/dist/{5171.7fc6d0a2.async.js → 4573.16f19278.async.js} +1 -1
- package/static/dist/{4859.93e63ea6.async.js → 4859.6592cebb.async.js} +1 -1
- package/static/dist/4887.8e3ae573.async.js +1 -0
- package/static/dist/{4902.54ecbdb5.async.js → 4902.555f92ab.async.js} +1 -1
- package/static/dist/{4934.1ca6b6b0.async.js → 4934.f3539d08.async.js} +1 -1
- package/static/dist/5077.cbd111cd.async.js +1 -0
- package/static/dist/{6247.b550d996.async.js → 5157.7c5af144.async.js} +1 -1
- package/static/dist/{540.481d4708.async.js → 540.19ddf020.async.js} +1 -1
- package/static/dist/{5970.10ac4f16.async.js → 5970.d3a6e7bd.async.js} +1 -1
- package/static/dist/{6013.2d7bb12a.async.js → 6013.4e38de36.async.js} +1 -1
- package/static/dist/{6016.9c379049.async.js → 6016.1e6574b6.async.js} +1 -1
- package/static/dist/{6035.5889ddc7.async.js → 6035.32ebfad9.async.js} +1 -1
- package/static/dist/6339.ab305e96.async.js +1 -0
- package/static/dist/6569.55177f6a.async.js +1 -0
- package/static/dist/6610.c111af7e.async.js +1 -0
- package/static/dist/{3034.6413c38e.async.js → 6638.87a163d2.async.js} +1 -1
- package/static/dist/{6646.5fc37228.async.js → 6646.95e92533.async.js} +1 -1
- package/static/dist/6665.1d099ad1.async.js +1 -0
- package/static/dist/{7355.b7c0562f.async.js → 7355.f9f263d8.async.js} +1 -1
- package/static/dist/{7384.065ccae2.async.js → 7384.1bb449d5.async.js} +1 -1
- package/static/dist/7441.ee1bf2bb.async.js +1 -0
- package/static/dist/{7508.a31662a3.async.js → 7508.7dcee91c.async.js} +1 -1
- package/static/dist/{7802.6b73f16a.async.js → 7802.34255805.async.js} +1 -1
- package/static/dist/{7984.e6bb9378.async.js → 7984.594296a5.async.js} +1 -1
- package/static/dist/{5653.4fce7ce8.async.js → 8033.5cb31493.async.js} +1 -1
- package/static/dist/8147.2fb55202.async.js +1 -0
- package/static/dist/8187.48c130d6.async.js +1 -0
- package/static/dist/8495.d53e15ca.async.js +1 -0
- package/static/dist/8587.315b06c0.async.js +1 -0
- package/static/dist/8826.db34ad8d.async.js +1 -0
- package/static/dist/{2742.4852aac8.async.js → 8865.ed665d31.async.js} +1 -1
- package/static/dist/901.7ee5c6d3.async.js +1 -0
- package/static/dist/9271.231db2ce.async.js +1 -0
- package/static/dist/9323.a33f47da.async.js +1 -0
- package/static/dist/{9730.30083c91.async.js → 9730.801665a3.async.js} +1 -1
- package/static/dist/{9761.627ca3b5.async.js → 9761.360a19d8.async.js} +1 -1
- package/static/dist/index.html +2 -2
- package/static/dist/layouts__index.a7a2bfe0.async.js +1 -0
- package/static/dist/layouts__index.adf0692f.chunk.css +1 -0
- package/static/dist/preload_helper.3048fe5b.js +1 -0
- package/static/dist/{src__pages__config__index.622b6ee8.async.js → src__pages__config__index.a22ff7dc.async.js} +1 -1
- package/static/dist/{src__pages__crontab__const.323d5124.async.js → src__pages__crontab__const.aba07deb.async.js} +1 -1
- package/static/dist/src__pages__crontab__detail.b98f0084.async.js +1 -0
- package/static/dist/src__pages__crontab__index.68e78a33.async.js +1 -0
- package/static/dist/{src__pages__crontab__logModal.5e6a4bf2.async.js → src__pages__crontab__logModal.831d5e4b.async.js} +1 -1
- package/static/dist/src__pages__crontab__modal.f7041c7c.async.js +1 -0
- package/static/dist/src__pages__crontab__type.d7af36e5.async.js +1 -0
- package/static/dist/{src__pages__crontab__viewCreateModal.ffcf7a24.async.js → src__pages__crontab__viewCreateModal.4d589f66.async.js} +1 -1
- package/static/dist/{src__pages__crontab__viewManageModal.c2724575.async.js → src__pages__crontab__viewManageModal.0e317746.async.js} +1 -1
- package/static/dist/src__pages__dashboard__index.58177357.async.js +1 -0
- package/static/dist/src__pages__dependence__index.b7bbc795.async.js +1 -0
- package/static/dist/{src__pages__dependence__logModal.f123e2ac.async.js → src__pages__dependence__logModal.0681830b.async.js} +1 -1
- package/static/dist/src__pages__dependence__modal.f7bb47ba.async.js +1 -0
- package/static/dist/src__pages__env__editNameModal.48715576.async.js +1 -0
- package/static/dist/src__pages__env__index.452cdc47.async.js +1 -0
- package/static/dist/src__pages__env__modal.e1234834.async.js +1 -0
- package/static/dist/src__pages__error__index.dedb2b90.async.js +1 -0
- package/static/dist/src__pages__initialization__index.22620a77.async.js +1 -0
- package/static/dist/src__pages__log__index.9c66639f.async.js +1 -0
- package/static/dist/{src__pages__login__index.cd6e3152.async.js → src__pages__login__index.8c813eb1.async.js} +1 -1
- package/static/dist/{src__pages__script__components__UnsupportedFilePreview__index.39074c68.async.js → src__pages__script__components__UnsupportedFilePreview__index.c347a13a.async.js} +1 -1
- package/static/dist/src__pages__script__editNameModal.532a3044.async.js +1 -0
- package/static/dist/src__pages__script__index.1fc20f22.async.js +1 -0
- package/static/dist/src__pages__script__renameModal.5cdde919.async.js +1 -0
- package/static/dist/src__pages__script__saveModal.5ffed35f.async.js +1 -0
- package/static/dist/src__pages__script__setting.1a82c6d7.async.js +1 -0
- package/static/dist/src__pages__setting__appModal.43b7758a.async.js +1 -0
- package/static/dist/src__pages__setting__checkUpdate.34d773f2.async.js +1 -0
- package/static/dist/src__pages__setting__dependence.9c04c79a.async.js +1 -0
- package/static/dist/src__pages__setting__index.7e070838.async.js +1 -0
- package/static/dist/src__pages__setting__notification.bac481c2.async.js +1 -0
- package/static/dist/src__pages__setting__other.707cfafe.async.js +1 -0
- package/static/dist/src__pages__setting__security.b7235753.async.js +1 -0
- package/static/dist/src__pages__setting__systemLog.b81a8c1d.async.js +1 -0
- package/static/dist/{src__pages__subscription__logModal.0caa7283.async.js → src__pages__subscription__logModal.3864b37f.async.js} +1 -1
- package/static/dist/src__pages__subscription__modal.562448e2.async.js +1 -0
- package/static/dist/{umi.ef8199a4.js → umi.a54a59f6.js} +1 -1
- package/version.yaml +33 -4
- package/sample/notify.py.save +0 -1010
- package/static/dist/105.85a5c47a.async.js +0 -1
- package/static/dist/1083.f86ce804.async.js +0 -1
- package/static/dist/1147.32f41a88.async.js +0 -1
- package/static/dist/1352.ab6da08e.async.js +0 -1
- package/static/dist/1690.f0290540.async.js +0 -1
- package/static/dist/1742.6cbe5aca.async.js +0 -1
- package/static/dist/2208.8e3a7325.async.js +0 -1
- package/static/dist/3191.70bc19db.async.js +0 -1
- package/static/dist/5312.74b95311.async.js +0 -1
- package/static/dist/5691.931f59c5.async.js +0 -1
- package/static/dist/6159.55cb068a.async.js +0 -1
- package/static/dist/7025.f4080d63.async.js +0 -1
- package/static/dist/739.6be5552a.async.js +0 -1
- package/static/dist/7571.4f6240b1.async.js +0 -1
- package/static/dist/786.59fc381c.async.js +0 -1
- package/static/dist/8317.c44c1ebd.async.js +0 -1
- package/static/dist/8826.0291edfd.async.js +0 -1
- package/static/dist/955.3c9481f7.async.js +0 -1
- package/static/dist/layouts__index.1fce90e0.chunk.css +0 -1
- package/static/dist/layouts__index.8dcf1576.async.js +0 -1
- package/static/dist/preload_helper.116a62f6.js +0 -1
- package/static/dist/src__pages__crontab__detail.b07f0c0a.async.js +0 -1
- package/static/dist/src__pages__crontab__index.2e2e1096.async.js +0 -1
- package/static/dist/src__pages__crontab__modal.4d8c2a22.async.js +0 -1
- package/static/dist/src__pages__crontab__type.db7c1858.async.js +0 -1
- package/static/dist/src__pages__dependence__index.3d87ceac.async.js +0 -1
- package/static/dist/src__pages__dependence__modal.631ffb5b.async.js +0 -1
- package/static/dist/src__pages__env__editNameModal.ff85ef8c.async.js +0 -1
- package/static/dist/src__pages__env__index.a0a2fece.async.js +0 -1
- package/static/dist/src__pages__env__modal.d1004662.async.js +0 -1
- package/static/dist/src__pages__error__index.1bc3c90b.async.js +0 -1
- package/static/dist/src__pages__initialization__index.8b1cbaf9.async.js +0 -1
- package/static/dist/src__pages__log__index.cf00c9af.async.js +0 -1
- package/static/dist/src__pages__script__editNameModal.53424d49.async.js +0 -1
- package/static/dist/src__pages__script__index.e65df827.async.js +0 -1
- package/static/dist/src__pages__script__renameModal.4bbe7fb1.async.js +0 -1
- package/static/dist/src__pages__script__saveModal.cf449f3c.async.js +0 -1
- package/static/dist/src__pages__script__setting.b345d59a.async.js +0 -1
- package/static/dist/src__pages__setting__appModal.03faec89.async.js +0 -1
- package/static/dist/src__pages__setting__checkUpdate.46efe057.async.js +0 -1
- package/static/dist/src__pages__setting__dependence.4495c7b6.async.js +0 -1
- package/static/dist/src__pages__setting__index.6919c399.async.js +0 -1
- package/static/dist/src__pages__setting__notification.d6a3884f.async.js +0 -1
- package/static/dist/src__pages__setting__other.0d931d6f.async.js +0 -1
- package/static/dist/src__pages__setting__security.91cb545f.async.js +0 -1
- package/static/dist/src__pages__setting__systemLog.1d433a48.async.js +0 -1
- package/static/dist/src__pages__subscription__modal.0b84f6cf.async.js +0 -1
package/shell/task.sh
CHANGED
|
@@ -4,9 +4,17 @@ dir_shell=$QL_DIR/shell
|
|
|
4
4
|
. $dir_shell/share.sh
|
|
5
5
|
. $dir_shell/api.sh
|
|
6
6
|
|
|
7
|
-
trap
|
|
7
|
+
trap 'single_hanle SIGINT' INT
|
|
8
|
+
trap 'single_hanle SIGTERM' TERM
|
|
9
|
+
trap 'single_hanle SIGHUP' HUP
|
|
10
|
+
trap 'single_hanle SIGALRM' ALRM
|
|
11
|
+
trap 'single_hanle SIGTSTP' TSTP
|
|
12
|
+
trap 'single_hanle SIGQUIT' QUIT
|
|
13
|
+
|
|
8
14
|
single_hanle() {
|
|
9
|
-
|
|
15
|
+
_task_exit_code="${_task_exit_code:-$?}"
|
|
16
|
+
[[ "$_task_exit_code" == "0" ]] && _task_exit_code="1"
|
|
17
|
+
eval MANUAL=true handle_task_end "$@"
|
|
10
18
|
exit 1
|
|
11
19
|
}
|
|
12
20
|
|
package/shell/update.sh
CHANGED
|
@@ -33,7 +33,7 @@ output_list_add_drop() {
|
|
|
33
33
|
local list=$1
|
|
34
34
|
local type=$2
|
|
35
35
|
if [[ -s $list ]]; then
|
|
36
|
-
|
|
36
|
+
t '检测到有%s的定时任务:' "$type"
|
|
37
37
|
cat $list
|
|
38
38
|
fi
|
|
39
39
|
}
|
|
@@ -45,7 +45,7 @@ del_cron() {
|
|
|
45
45
|
local path=$2
|
|
46
46
|
local detail=""
|
|
47
47
|
local ids=""
|
|
48
|
-
|
|
48
|
+
t '\n开始尝试自动删除失效的定时任务...'
|
|
49
49
|
for cron in $(cat $list_drop); do
|
|
50
50
|
local id=$(cat $list_crontab_user | grep -E "$cmd_task.* $cron" | perl -pe "s|.*ID=(.*) $cmd_task.* $cron\.*|\1|" | head -1 | awk -F " " '{print $1}')
|
|
51
51
|
if [[ $ids ]]; then
|
|
@@ -76,7 +76,7 @@ del_cron() {
|
|
|
76
76
|
add_cron() {
|
|
77
77
|
local list_add=$1
|
|
78
78
|
local path=$2
|
|
79
|
-
|
|
79
|
+
t '\n开始尝试自动添加定时任务...'
|
|
80
80
|
local detail=""
|
|
81
81
|
cd $dir_scripts
|
|
82
82
|
for file in $(cat $list_add); do
|
|
@@ -136,10 +136,10 @@ update_repo() {
|
|
|
136
136
|
git_clone_scripts "${formatUrl}" ${repo_path} "${branch}" "${proxy}"
|
|
137
137
|
|
|
138
138
|
if [[ $exit_status -eq 0 ]]; then
|
|
139
|
-
|
|
139
|
+
t '拉取 %s 成功...\n' "${uniq_path}"
|
|
140
140
|
diff_scripts "$repo_path" "$author" "$path" "$blackword" "$dependence" "$extensions" "$autoAddCron" "$autoDelCron"
|
|
141
141
|
else
|
|
142
|
-
|
|
142
|
+
t '拉取 %s 失败,请检查日志...\n' "${uniq_path}"
|
|
143
143
|
fi
|
|
144
144
|
}
|
|
145
145
|
|
|
@@ -160,7 +160,7 @@ update_raw() {
|
|
|
160
160
|
local raw_url="$url"
|
|
161
161
|
local suffix="${raw_url##*.}"
|
|
162
162
|
local raw_file_name="${uniq_path}.${suffix}"
|
|
163
|
-
|
|
163
|
+
t '开始下载:%s 保存路径:%s\n' "${raw_url}" "$dir_raw/${raw_file_name}"
|
|
164
164
|
|
|
165
165
|
set_proxy "$proxy"
|
|
166
166
|
wget -q --no-check-certificate -O "$dir_raw/${raw_file_name}.new" ${raw_url}
|
|
@@ -169,7 +169,7 @@ update_raw() {
|
|
|
169
169
|
|
|
170
170
|
if [[ $? -eq 0 ]]; then
|
|
171
171
|
mv "$dir_raw/${raw_file_name}.new" "$dir_raw/${raw_file_name}"
|
|
172
|
-
|
|
172
|
+
t '下载 %s 成功...\n' "${raw_file_name}"
|
|
173
173
|
cd $dir_raw
|
|
174
174
|
local filename="raw_${raw_file_name}"
|
|
175
175
|
local cron_id=$(cat $list_crontab_user | grep -E "$cmd_task.* $filename" | perl -pe "s|.*ID=(.*) $cmd_task.* $filename\.*|\1|" | head -1 | awk -F " " '{print $1}')
|
|
@@ -196,7 +196,7 @@ update_raw() {
|
|
|
196
196
|
# update_cron_api "$cron_line:$cmd_task $filename:$cron_name:$cron_id"
|
|
197
197
|
fi
|
|
198
198
|
else
|
|
199
|
-
|
|
199
|
+
t '下载 %s 失败,保留之前正常下载的版本...\n' "${raw_file_name}"
|
|
200
200
|
[[ -f "$dir_raw/${raw_file_name}.new" ]] && rm -f "$dir_raw/${raw_file_name}.new"
|
|
201
201
|
fi
|
|
202
202
|
|
|
@@ -207,13 +207,13 @@ run_extra_shell() {
|
|
|
207
207
|
if [[ -f $file_extra_shell ]]; then
|
|
208
208
|
. $file_extra_shell
|
|
209
209
|
else
|
|
210
|
-
|
|
210
|
+
t '%s文件不存在,跳过执行...\n' "$file_extra_shell"
|
|
211
211
|
fi
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
## 脚本用法
|
|
215
215
|
usage() {
|
|
216
|
-
|
|
216
|
+
t "$cmd_update 命令使用方法:"
|
|
217
217
|
echo -e "1. $cmd_update update # 更新并重启青龙"
|
|
218
218
|
echo -e "2. $cmd_update extra # 运行自定义脚本"
|
|
219
219
|
echo -e "3. $cmd_update raw <fileurl> # 更新单个脚本文件"
|
|
@@ -268,7 +268,7 @@ update_qinglong() {
|
|
|
268
268
|
downloadQLUrl="https://github.com/whyour/qinglong/archive/refs/heads"
|
|
269
269
|
downloadStaticUrl="https://github.com/whyour/qinglong-static/archive/refs/heads"
|
|
270
270
|
fi
|
|
271
|
-
|
|
271
|
+
t '使用 %s 源更新...\n' "${mirror}"
|
|
272
272
|
|
|
273
273
|
local primary_branch="master"
|
|
274
274
|
if [[ "${QL_BRANCH}" == "develop" ]] || [[ "${QL_BRANCH}" == "debian" ]] || [[ "${QL_BRANCH}" == "debian-dev" ]]; then
|
|
@@ -279,13 +279,13 @@ update_qinglong() {
|
|
|
279
279
|
exit_status=$?
|
|
280
280
|
|
|
281
281
|
if [[ $exit_status -eq 0 ]]; then
|
|
282
|
-
|
|
282
|
+
t '更新青龙源文件成功...\n'
|
|
283
283
|
|
|
284
284
|
unzip -oq ${dir_tmp}/ql.zip -d ${dir_tmp}
|
|
285
285
|
|
|
286
286
|
update_qinglong_static
|
|
287
287
|
else
|
|
288
|
-
|
|
288
|
+
t '更新青龙源文件失败,请检查网络...\n'
|
|
289
289
|
fi
|
|
290
290
|
}
|
|
291
291
|
|
|
@@ -294,30 +294,30 @@ update_qinglong_static() {
|
|
|
294
294
|
exit_status=$?
|
|
295
295
|
|
|
296
296
|
if [[ $exit_status -eq 0 ]]; then
|
|
297
|
-
|
|
297
|
+
t '更新青龙静态资源成功...\n'
|
|
298
298
|
unzip -oq ${dir_tmp}/static.zip -d ${dir_tmp}
|
|
299
299
|
|
|
300
300
|
check_update_dep
|
|
301
301
|
else
|
|
302
|
-
|
|
302
|
+
t '更新青龙静态资源失败,请检查网络...\n'
|
|
303
303
|
fi
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
check_update_dep() {
|
|
307
|
-
|
|
307
|
+
t '\n开始检测依赖...\n'
|
|
308
308
|
if [[ $(diff $dir_root/package.json ${dir_tmp}/qinglong-${primary_branch}/package.json) ]]; then
|
|
309
309
|
npm_install_2 "${dir_tmp}/qinglong-${primary_branch}"
|
|
310
310
|
fi
|
|
311
311
|
|
|
312
312
|
if [[ $exit_status -eq 0 ]]; then
|
|
313
|
-
|
|
314
|
-
|
|
313
|
+
t '\n依赖检测安装成功...\n'
|
|
314
|
+
t '更新包下载成功...\n'
|
|
315
315
|
|
|
316
316
|
if [[ "$needRestart" == 'true' ]]; then
|
|
317
317
|
reload_qinglong "system"
|
|
318
318
|
fi
|
|
319
319
|
else
|
|
320
|
-
|
|
320
|
+
t '\n依赖检测安装失败,请检查网络...\n'
|
|
321
321
|
fi
|
|
322
322
|
}
|
|
323
323
|
|
|
@@ -514,7 +514,7 @@ main() {
|
|
|
514
514
|
if [[ -n $p2 ]]; then
|
|
515
515
|
update_repo "$p2" "$p3" "$p4" "$p5" "$p6" "$p7" "$p8" "$p9" "$p10"
|
|
516
516
|
else
|
|
517
|
-
|
|
517
|
+
t '命令输入错误...\n'
|
|
518
518
|
eval usage $cmd
|
|
519
519
|
fi
|
|
520
520
|
;;
|
|
@@ -523,7 +523,7 @@ main() {
|
|
|
523
523
|
if [[ -n $p2 ]]; then
|
|
524
524
|
update_raw "$p2" "$p3" "$p4" "$p5"
|
|
525
525
|
else
|
|
526
|
-
|
|
526
|
+
t '命令输入错误...\n'
|
|
527
527
|
eval usage $cmd
|
|
528
528
|
fi
|
|
529
529
|
;;
|
|
@@ -549,7 +549,7 @@ main() {
|
|
|
549
549
|
eval update_auth_config "\\\"username\\\":\\\"$p2\\\"" "重置用户名" $cmd
|
|
550
550
|
;;
|
|
551
551
|
*)
|
|
552
|
-
|
|
552
|
+
t '命令输入错误...\n'
|
|
553
553
|
eval usage $cmd
|
|
554
554
|
;;
|
|
555
555
|
esac
|
|
@@ -33,6 +33,7 @@ const fs = __importStar(require("fs/promises"));
|
|
|
33
33
|
const celebrate_1 = require("celebrate");
|
|
34
34
|
const path_1 = require("path");
|
|
35
35
|
const const_1 = require("../config/const");
|
|
36
|
+
const i18n_1 = require("../shared/i18n");
|
|
36
37
|
const config_2 = __importDefault(require("../services/config"));
|
|
37
38
|
const utils_1 = require("../shared/utils");
|
|
38
39
|
const route = (0, express_1.Router)();
|
|
@@ -84,15 +85,24 @@ exports.default = (app) => {
|
|
|
84
85
|
const logger = typedi_1.Container.get('logger');
|
|
85
86
|
try {
|
|
86
87
|
const { name, content } = req.body;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
let path = (0, path_1.join)(config_1.default.configPath, name);
|
|
88
|
+
// Resolve path first to prevent traversal attacks
|
|
89
|
+
let basePath = config_1.default.configPath;
|
|
91
90
|
if (name.startsWith('data/scripts/')) {
|
|
92
|
-
|
|
91
|
+
basePath = (0, path_1.join)(config_1.default.rootPath, 'data/scripts');
|
|
92
|
+
}
|
|
93
|
+
const cleanName = name.replace(/^data\/scripts\//, '');
|
|
94
|
+
const resolvedPath = (0, path_1.join)(basePath, cleanName);
|
|
95
|
+
const normalized = (0, path_1.join)(resolvedPath);
|
|
96
|
+
// Verify the resolved path stays within allowed directory
|
|
97
|
+
if (!normalized.startsWith(basePath)) {
|
|
98
|
+
return res.send({ code: 403, message: (0, i18n_1.t)('文件路径无效') });
|
|
99
|
+
}
|
|
100
|
+
// Check blacklist on actual filename (not user input)
|
|
101
|
+
if (config_1.default.blackFileList.includes((0, path_1.basename)(normalized))) {
|
|
102
|
+
return res.send({ code: 403, message: (0, i18n_1.t)('文件无法访问') });
|
|
93
103
|
}
|
|
94
|
-
await (0, utils_1.writeFileWithLock)(
|
|
95
|
-
res.send({ code: 200, message: '保存成功' });
|
|
104
|
+
await (0, utils_1.writeFileWithLock)(normalized, content);
|
|
105
|
+
res.send({ code: 200, message: (0, i18n_1.t)('保存成功') });
|
|
96
106
|
}
|
|
97
107
|
catch (e) {
|
|
98
108
|
return next(e);
|
package/static/build/api/cron.js
CHANGED
|
@@ -9,6 +9,8 @@ const cron_1 = __importDefault(require("../services/cron"));
|
|
|
9
9
|
const cronView_1 = __importDefault(require("../services/cronView"));
|
|
10
10
|
const celebrate_1 = require("celebrate");
|
|
11
11
|
const schedule_1 = require("../validation/schedule");
|
|
12
|
+
const runningInstance_1 = require("../data/runningInstance");
|
|
13
|
+
const i18n_1 = require("../shared/i18n");
|
|
12
14
|
const route = (0, express_1.Router)();
|
|
13
15
|
exports.default = (app) => {
|
|
14
16
|
app.use('/crons', route);
|
|
@@ -51,7 +53,7 @@ exports.default = (app) => {
|
|
|
51
53
|
try {
|
|
52
54
|
const cronViewService = typedi_1.Container.get(cronView_1.default);
|
|
53
55
|
if (req.body.type === 1) {
|
|
54
|
-
return res.send({ code: 400, message: '参数错误' });
|
|
56
|
+
return res.send({ code: 400, message: (0, i18n_1.t)('参数错误') });
|
|
55
57
|
}
|
|
56
58
|
else {
|
|
57
59
|
const data = await cronViewService.update(req.body);
|
|
@@ -245,8 +247,8 @@ exports.default = (app) => {
|
|
|
245
247
|
const logger = typedi_1.Container.get('logger');
|
|
246
248
|
try {
|
|
247
249
|
const cronService = typedi_1.Container.get(cron_1.default);
|
|
248
|
-
const
|
|
249
|
-
return res.send({ code: 200, data });
|
|
250
|
+
const result = await cronService.log(req.params.id);
|
|
251
|
+
return res.send({ code: 200, data: result.content, logStatus: result.status });
|
|
250
252
|
}
|
|
251
253
|
catch (e) {
|
|
252
254
|
return next(e);
|
|
@@ -338,6 +340,7 @@ exports.default = (app) => {
|
|
|
338
340
|
log_path: celebrate_1.Joi.string().optional().allow(null),
|
|
339
341
|
last_running_time: celebrate_1.Joi.number().optional().allow(null),
|
|
340
342
|
last_execution_time: celebrate_1.Joi.number().optional().allow(null),
|
|
343
|
+
exit_code: celebrate_1.Joi.number().optional().allow(null),
|
|
341
344
|
}),
|
|
342
345
|
}), async (req, res, next) => {
|
|
343
346
|
try {
|
|
@@ -349,6 +352,40 @@ exports.default = (app) => {
|
|
|
349
352
|
return next(e);
|
|
350
353
|
}
|
|
351
354
|
});
|
|
355
|
+
route.get('/:id/instances', (0, celebrate_1.celebrate)({
|
|
356
|
+
params: celebrate_1.Joi.object({
|
|
357
|
+
id: celebrate_1.Joi.number().required(),
|
|
358
|
+
}),
|
|
359
|
+
}), async (req, res, next) => {
|
|
360
|
+
try {
|
|
361
|
+
const instances = await runningInstance_1.RunningInstanceModel.findAll({
|
|
362
|
+
where: {
|
|
363
|
+
cron_id: req.params.id,
|
|
364
|
+
},
|
|
365
|
+
order: [['started_at', 'DESC']],
|
|
366
|
+
raw: true,
|
|
367
|
+
});
|
|
368
|
+
return res.send({ code: 200, data: instances });
|
|
369
|
+
}
|
|
370
|
+
catch (e) {
|
|
371
|
+
return next(e);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
route.post('/:id/instances/:instanceId/stop', (0, celebrate_1.celebrate)({
|
|
375
|
+
params: celebrate_1.Joi.object({
|
|
376
|
+
id: celebrate_1.Joi.number().required(),
|
|
377
|
+
instanceId: celebrate_1.Joi.number().required(),
|
|
378
|
+
}),
|
|
379
|
+
}), async (req, res, next) => {
|
|
380
|
+
try {
|
|
381
|
+
const cronService = typedi_1.Container.get(cron_1.default);
|
|
382
|
+
const data = await cronService.stopInstance(req.params.instanceId);
|
|
383
|
+
return res.send(data);
|
|
384
|
+
}
|
|
385
|
+
catch (e) {
|
|
386
|
+
return next(e);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
352
389
|
route.get('/:id/logs', (0, celebrate_1.celebrate)({
|
|
353
390
|
params: celebrate_1.Joi.object({
|
|
354
391
|
id: celebrate_1.Joi.number().required(),
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const express_1 = require("express");
|
|
7
|
+
const sequelize_1 = require("sequelize");
|
|
8
|
+
const cron_1 = require("../data/cron");
|
|
9
|
+
const cronStats_1 = require("../data/cronStats");
|
|
10
|
+
const runningInstance_1 = require("../data/runningInstance");
|
|
11
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
12
|
+
const os_1 = __importDefault(require("os"));
|
|
13
|
+
const lodash_1 = require("lodash");
|
|
14
|
+
const i18n_1 = require("../shared/i18n");
|
|
15
|
+
const route = (0, express_1.Router)();
|
|
16
|
+
exports.default = (app) => {
|
|
17
|
+
app.use('/dashboard', route);
|
|
18
|
+
route.post('/record', async (req, res) => {
|
|
19
|
+
try {
|
|
20
|
+
const { ref_id, code, elapsed } = req.body;
|
|
21
|
+
if (!ref_id)
|
|
22
|
+
return res.send({ code: 400, message: 'ref_id required' });
|
|
23
|
+
const today = (0, dayjs_1.default)().format('YYYY-MM-DD');
|
|
24
|
+
const isSuccess = code === 0 ? 1 : 0;
|
|
25
|
+
const isFail = code !== 0 ? 1 : 0;
|
|
26
|
+
const elapsedMs = (Number(elapsed) || 0) * 1000;
|
|
27
|
+
const existing = await cronStats_1.CrontabStatModel.findOne({
|
|
28
|
+
where: { ref_id: Number(ref_id), date: today },
|
|
29
|
+
});
|
|
30
|
+
if (existing) {
|
|
31
|
+
await cronStats_1.CrontabStatModel.update({
|
|
32
|
+
run_count: (existing.run_count || 0) + 1,
|
|
33
|
+
success_count: (existing.success_count || 0) + isSuccess,
|
|
34
|
+
fail_count: (existing.fail_count || 0) + isFail,
|
|
35
|
+
total_time: (existing.total_time || 0) + elapsedMs,
|
|
36
|
+
max_time: Math.max(existing.max_time || 0, elapsedMs),
|
|
37
|
+
}, { where: { id: existing.id } });
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
await cronStats_1.CrontabStatModel.create({
|
|
41
|
+
ref_id: Number(ref_id),
|
|
42
|
+
date: today,
|
|
43
|
+
run_count: 1,
|
|
44
|
+
success_count: isSuccess,
|
|
45
|
+
fail_count: isFail,
|
|
46
|
+
total_time: elapsedMs,
|
|
47
|
+
max_time: elapsedMs,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
res.send({ code: 200 });
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
res.send({ code: 500 });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
route.get('/overview', async (req, res, next) => {
|
|
57
|
+
try {
|
|
58
|
+
const today = (0, dayjs_1.default)().format('YYYY-MM-DD');
|
|
59
|
+
const [total, enabled, disabled, stats] = await Promise.all([
|
|
60
|
+
cron_1.CrontabModel.count(),
|
|
61
|
+
cron_1.CrontabModel.count({ where: { isDisabled: 0 } }),
|
|
62
|
+
cron_1.CrontabModel.count({ where: { isDisabled: 1 } }),
|
|
63
|
+
cronStats_1.CrontabStatModel.findOne({
|
|
64
|
+
attributes: [
|
|
65
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('run_count')), 'total_runs'],
|
|
66
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('success_count')), 'total_success'],
|
|
67
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('fail_count')), 'total_fail'],
|
|
68
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('total_time')), 'total_time'],
|
|
69
|
+
],
|
|
70
|
+
where: { date: today },
|
|
71
|
+
raw: true,
|
|
72
|
+
}),
|
|
73
|
+
]);
|
|
74
|
+
const row = stats;
|
|
75
|
+
const totalRuns = Number(row === null || row === void 0 ? void 0 : row.total_runs) || 0;
|
|
76
|
+
const totalSuccess = Number(row === null || row === void 0 ? void 0 : row.total_success) || 0;
|
|
77
|
+
const totalFail = Number(row === null || row === void 0 ? void 0 : row.total_fail) || 0;
|
|
78
|
+
const totalTime = Number(row === null || row === void 0 ? void 0 : row.total_time) || 0;
|
|
79
|
+
res.send({
|
|
80
|
+
code: 200,
|
|
81
|
+
data: {
|
|
82
|
+
total,
|
|
83
|
+
enabled,
|
|
84
|
+
disabled,
|
|
85
|
+
todayRuns: totalRuns,
|
|
86
|
+
todaySuccess: totalSuccess,
|
|
87
|
+
todayFail: totalFail,
|
|
88
|
+
successRate: totalRuns > 0 ? ((totalSuccess / totalRuns) * 100).toFixed(1) : '0',
|
|
89
|
+
avgTime: totalRuns > 0 ? Math.round(totalTime / totalRuns) : 0,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
next(e);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
route.get('/trend', async (req, res, next) => {
|
|
98
|
+
try {
|
|
99
|
+
const days = parseInt(req.query.days) || 7;
|
|
100
|
+
const dates = [];
|
|
101
|
+
for (let i = days - 1; i >= 0; i--) {
|
|
102
|
+
dates.push((0, dayjs_1.default)().subtract(i, 'day').format('YYYY-MM-DD'));
|
|
103
|
+
}
|
|
104
|
+
const rows = (await cronStats_1.CrontabStatModel.findAll({
|
|
105
|
+
attributes: [
|
|
106
|
+
'date',
|
|
107
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('run_count')), 'total_runs'],
|
|
108
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('success_count')), 'total_success'],
|
|
109
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('fail_count')), 'total_fail'],
|
|
110
|
+
],
|
|
111
|
+
where: {
|
|
112
|
+
date: { [sequelize_1.Op.in]: dates },
|
|
113
|
+
},
|
|
114
|
+
group: ['date'],
|
|
115
|
+
order: [['date', 'ASC']],
|
|
116
|
+
raw: true,
|
|
117
|
+
}));
|
|
118
|
+
const dataMap = {};
|
|
119
|
+
rows.forEach((r) => {
|
|
120
|
+
dataMap[r.date] = {
|
|
121
|
+
total: Number(r.total_runs) || 0,
|
|
122
|
+
success: Number(r.total_success) || 0,
|
|
123
|
+
fail: Number(r.total_fail) || 0,
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
const data = dates.map((d) => (Object.assign({ date: (0, dayjs_1.default)(d).format('MM-DD') }, (dataMap[d] || { total: 0, success: 0, fail: 0 }))));
|
|
127
|
+
res.send({ code: 200, data });
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
next(e);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
route.get('/top-time', async (req, res, next) => {
|
|
134
|
+
try {
|
|
135
|
+
const today = (0, dayjs_1.default)().format('YYYY-MM-DD');
|
|
136
|
+
const rows = (await cronStats_1.CrontabStatModel.findAll({
|
|
137
|
+
attributes: [
|
|
138
|
+
'ref_id',
|
|
139
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('total_time')), 'total_time'],
|
|
140
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('run_count')), 'run_count'],
|
|
141
|
+
[(0, sequelize_1.fn)('MAX', (0, sequelize_1.col)('max_time')), 'max_time'],
|
|
142
|
+
],
|
|
143
|
+
where: { date: today, run_count: { [sequelize_1.Op.gt]: 0 } },
|
|
144
|
+
group: ['ref_id'],
|
|
145
|
+
order: [[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('total_time')), 'DESC']],
|
|
146
|
+
limit: 5,
|
|
147
|
+
raw: true,
|
|
148
|
+
}));
|
|
149
|
+
const ids = rows.map((r) => Number(r.ref_id));
|
|
150
|
+
const crons = await cron_1.CrontabModel.findAll({
|
|
151
|
+
where: { id: { [sequelize_1.Op.in]: ids } },
|
|
152
|
+
raw: true,
|
|
153
|
+
});
|
|
154
|
+
const nameMap = {};
|
|
155
|
+
crons.forEach((c) => { nameMap[c.id] = c.name || c.command; });
|
|
156
|
+
const data = rows.map((r, i) => ({
|
|
157
|
+
rank: i + 1,
|
|
158
|
+
name: nameMap[Number(r.ref_id)] || (0, i18n_1.tf)('任务#%s', r.ref_id),
|
|
159
|
+
avgTime: Math.round(Number(r.total_time) / Number(r.run_count)),
|
|
160
|
+
maxTime: Number(r.max_time),
|
|
161
|
+
}));
|
|
162
|
+
res.send({ code: 200, data });
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
next(e);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
route.get('/top-count', async (req, res, next) => {
|
|
169
|
+
try {
|
|
170
|
+
const today = (0, dayjs_1.default)().format('YYYY-MM-DD');
|
|
171
|
+
const rows = (await cronStats_1.CrontabStatModel.findAll({
|
|
172
|
+
attributes: [
|
|
173
|
+
'ref_id',
|
|
174
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('run_count')), 'run_count'],
|
|
175
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('total_time')), 'total_time'],
|
|
176
|
+
[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('success_count')), 'success_count'],
|
|
177
|
+
],
|
|
178
|
+
where: { date: today, run_count: { [sequelize_1.Op.gt]: 0 } },
|
|
179
|
+
group: ['ref_id'],
|
|
180
|
+
order: [[(0, sequelize_1.fn)('SUM', (0, sequelize_1.col)('run_count')), 'DESC']],
|
|
181
|
+
limit: 5,
|
|
182
|
+
raw: true,
|
|
183
|
+
}));
|
|
184
|
+
const ids = rows.map((r) => Number(r.ref_id));
|
|
185
|
+
const crons = await cron_1.CrontabModel.findAll({
|
|
186
|
+
where: { id: { [sequelize_1.Op.in]: ids } },
|
|
187
|
+
raw: true,
|
|
188
|
+
});
|
|
189
|
+
const nameMap = {};
|
|
190
|
+
crons.forEach((c) => { nameMap[c.id] = c.name || c.command; });
|
|
191
|
+
const data = rows.map((r, i) => ({
|
|
192
|
+
rank: i + 1,
|
|
193
|
+
name: nameMap[Number(r.ref_id)] || (0, i18n_1.tf)('任务#%s', r.ref_id),
|
|
194
|
+
runCount: Number(r.run_count),
|
|
195
|
+
avgTime: Math.round(Number(r.total_time) / Number(r.run_count)),
|
|
196
|
+
successRate: Number(r.run_count) > 0
|
|
197
|
+
? ((Number(r.success_count) / Number(r.run_count)) * 100).toFixed(1)
|
|
198
|
+
: '0',
|
|
199
|
+
}));
|
|
200
|
+
res.send({ code: 200, data });
|
|
201
|
+
}
|
|
202
|
+
catch (e) {
|
|
203
|
+
next(e);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
route.get('/runtime', async (req, res, next) => {
|
|
207
|
+
try {
|
|
208
|
+
const runningInstances = await runningInstance_1.RunningInstanceModel.findAll({
|
|
209
|
+
where: {
|
|
210
|
+
status: runningInstance_1.InstanceStatus.running,
|
|
211
|
+
},
|
|
212
|
+
raw: true,
|
|
213
|
+
});
|
|
214
|
+
const queuedCrons = await cron_1.CrontabModel.findAll({
|
|
215
|
+
where: {
|
|
216
|
+
status: 3, // queued
|
|
217
|
+
},
|
|
218
|
+
raw: true,
|
|
219
|
+
});
|
|
220
|
+
// Fetch cron names for running instances
|
|
221
|
+
const cronIds = [
|
|
222
|
+
...new Set(runningInstances.map((i) => i.cron_id)),
|
|
223
|
+
];
|
|
224
|
+
const crons = cronIds.length > 0
|
|
225
|
+
? await cron_1.CrontabModel.findAll({
|
|
226
|
+
where: { id: cronIds },
|
|
227
|
+
raw: true,
|
|
228
|
+
})
|
|
229
|
+
: [];
|
|
230
|
+
const cronMap = new Map(crons.map((c) => [c.id, c]));
|
|
231
|
+
const now = (0, dayjs_1.default)().unix();
|
|
232
|
+
const running = runningInstances.map((inst) => {
|
|
233
|
+
const cron = cronMap.get(inst.cron_id);
|
|
234
|
+
return {
|
|
235
|
+
instanceId: inst.id,
|
|
236
|
+
id: inst.cron_id,
|
|
237
|
+
name: (cron === null || cron === void 0 ? void 0 : cron.name) || (cron === null || cron === void 0 ? void 0 : cron.command) || (0, i18n_1.tf)('任务#%s', inst.cron_id),
|
|
238
|
+
pid: inst.pid,
|
|
239
|
+
elapsed: inst.started_at ? now - inst.started_at : 0,
|
|
240
|
+
logPath: inst.log_path,
|
|
241
|
+
};
|
|
242
|
+
});
|
|
243
|
+
const dayAgo = (0, dayjs_1.default)().subtract(24, 'hour').unix();
|
|
244
|
+
const idleTasks = await cron_1.CrontabModel.findAll({
|
|
245
|
+
where: {
|
|
246
|
+
isDisabled: 0,
|
|
247
|
+
status: 1,
|
|
248
|
+
last_execution_time: { [sequelize_1.Op.lt]: dayAgo },
|
|
249
|
+
},
|
|
250
|
+
order: [['last_execution_time', 'ASC']],
|
|
251
|
+
limit: 5,
|
|
252
|
+
raw: true,
|
|
253
|
+
});
|
|
254
|
+
res.send({
|
|
255
|
+
code: 200,
|
|
256
|
+
data: {
|
|
257
|
+
runningCount: running.length,
|
|
258
|
+
queuedCount: queuedCrons.length,
|
|
259
|
+
running,
|
|
260
|
+
idleTasks: idleTasks.map((c) => ({
|
|
261
|
+
id: c.id,
|
|
262
|
+
name: c.name || c.command || (0, i18n_1.tf)('任务#%s', c.id),
|
|
263
|
+
lastRun: c.last_execution_time
|
|
264
|
+
? dayjs_1.default.unix(c.last_execution_time).format('MM-DD HH:mm')
|
|
265
|
+
: '-',
|
|
266
|
+
})),
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
catch (e) {
|
|
271
|
+
next(e);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
route.get('/labels', async (req, res, next) => {
|
|
275
|
+
try {
|
|
276
|
+
const today = (0, dayjs_1.default)().format('YYYY-MM-DD');
|
|
277
|
+
const [crons, stats] = (await Promise.all([
|
|
278
|
+
cron_1.CrontabModel.findAll({ where: { isDisabled: 0 }, raw: true }),
|
|
279
|
+
cronStats_1.CrontabStatModel.findAll({ where: { date: today }, raw: true }),
|
|
280
|
+
]));
|
|
281
|
+
const statMap = {};
|
|
282
|
+
stats.forEach((s) => { statMap[s.ref_id] = s; });
|
|
283
|
+
const labelMap = {};
|
|
284
|
+
crons.forEach((c) => {
|
|
285
|
+
let rawLabels = c.labels;
|
|
286
|
+
if (typeof rawLabels === 'string')
|
|
287
|
+
rawLabels = JSON.parse(rawLabels);
|
|
288
|
+
const labels = Array.isArray(rawLabels)
|
|
289
|
+
? [...new Set(rawLabels.filter((l) => !(0, lodash_1.isEmpty)(l)))]
|
|
290
|
+
: [];
|
|
291
|
+
if (labels.length === 0) {
|
|
292
|
+
labels.push((0, i18n_1.t)('未分类'));
|
|
293
|
+
}
|
|
294
|
+
const st = statMap[c.id];
|
|
295
|
+
labels.forEach((label) => {
|
|
296
|
+
if (!labelMap[label])
|
|
297
|
+
labelMap[label] = { count: 0, runs: 0, success: 0, totalTime: 0 };
|
|
298
|
+
labelMap[label].count += 1;
|
|
299
|
+
if (st) {
|
|
300
|
+
labelMap[label].runs += Number(st.run_count) || 0;
|
|
301
|
+
labelMap[label].success += Number(st.success_count) || 0;
|
|
302
|
+
labelMap[label].totalTime += Number(st.total_time) || 0;
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
const data = Object.entries(labelMap)
|
|
307
|
+
.map(([label, v]) => ({
|
|
308
|
+
label,
|
|
309
|
+
count: v.count,
|
|
310
|
+
todayRuns: v.runs,
|
|
311
|
+
successRate: v.runs > 0 ? ((v.success / v.runs) * 100).toFixed(1) : '0',
|
|
312
|
+
avgTime: v.runs > 0 ? Math.round(v.totalTime / v.runs) : 0,
|
|
313
|
+
}))
|
|
314
|
+
.sort((a, b) => b.todayRuns - a.todayRuns);
|
|
315
|
+
res.send({ code: 200, data });
|
|
316
|
+
}
|
|
317
|
+
catch (e) {
|
|
318
|
+
next(e);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
route.get('/system', async (req, res, next) => {
|
|
322
|
+
try {
|
|
323
|
+
const memUsage = process.memoryUsage();
|
|
324
|
+
res.send({
|
|
325
|
+
code: 200,
|
|
326
|
+
data: {
|
|
327
|
+
platform: os_1.default.platform(),
|
|
328
|
+
uptime: Math.floor(process.uptime()),
|
|
329
|
+
memTotal: os_1.default.totalmem(),
|
|
330
|
+
memFree: os_1.default.freemem(),
|
|
331
|
+
memUsagePercent: ((1 - os_1.default.freemem() / os_1.default.totalmem()) * 100).toFixed(1),
|
|
332
|
+
heapUsed: Math.round(memUsage.heapUsed / 1024 / 1024),
|
|
333
|
+
heapTotal: Math.round(memUsage.heapTotal / 1024 / 1024),
|
|
334
|
+
loadAvg: os_1.default.loadavg().map((v) => Number(v.toFixed(2))),
|
|
335
|
+
cpus: os_1.default.cpus().length,
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
catch (e) {
|
|
340
|
+
next(e);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
};
|
|
344
|
+
//# sourceMappingURL=dashboard.js.map
|