@whyour/qinglong 2.20.2-2 → 2.21.0
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/CLAUDE.md +43 -0
- package/README-en.md +11 -0
- package/README.md +11 -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 +28 -25
- package/sample/config.sample.sh +12 -1
- package/sample/notify.js +81 -9
- package/sample/notify.py +54 -11
- package/shell/api.sh +44 -20
- 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 +114 -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 +49 -30
- 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 +38 -1
- package/static/build/api/dashboard.js +337 -0
- package/static/build/api/env.js +40 -2
- package/static/build/api/index.js +2 -0
- package/static/build/api/log.js +5 -4
- package/static/build/api/script.js +34 -9
- package/static/build/api/system.js +16 -1
- package/static/build/api/user.js +6 -5
- package/static/build/app.js +3 -0
- package/static/build/config/const.js +7 -6
- package/static/build/config/container.js +12 -0
- package/static/build/config/grpcCerts.js +150 -0
- package/static/build/config/index.js +6 -0
- package/static/build/config/util.js +66 -15
- 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 +11 -1
- package/static/build/data/runningInstance.js +57 -0
- package/static/build/loaders/app.js +1 -1
- package/static/build/loaders/db.js +6 -0
- package/static/build/loaders/express.js +2 -1
- package/static/build/loaders/initData.js +19 -2
- package/static/build/loaders/initFile.js +2 -0
- package/static/build/schedule/api.js +1 -1
- package/static/build/schedule/client.js +9 -1
- package/static/build/schedule/health.js +1 -1
- package/static/build/services/config.js +19 -5
- package/static/build/services/cron.js +118 -8
- 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 +40 -3
- package/static/build/services/open.js +2 -1
- package/static/build/services/sshKey.js +6 -3
- package/static/build/services/subscription.js +2 -1
- package/static/build/services/system.js +22 -7
- package/static/build/services/user.js +8 -7
- package/static/build/shared/i18n.js +105 -0
- package/static/build/shared/pLimit.js +12 -1
- package/static/build/shared/runCron.js +5 -0
- package/static/build/validation/schedule.js +1 -0
- package/static/dist/1089.0ecc5383.async.js +1 -0
- package/static/dist/1147.c420132e.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.f7ba3dfa.async.js +1 -0
- package/static/dist/2286.164bb089.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.70bc19db.async.js → 3191.63263871.async.js} +1 -1
- 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.2447a104.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.0431c0f3.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.b9c36808.async.js +1 -0
- package/static/dist/src__pages__crontab__index.fed99fd0.async.js +1 -0
- package/static/dist/{src__pages__crontab__logModal.5e6a4bf2.async.js → src__pages__crontab__logModal.0b8cce8c.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.b30f2f47.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.11124896.async.js +1 -0
- package/static/dist/src__pages__env__editNameModal.5d264b25.async.js +1 -0
- package/static/dist/src__pages__env__index.baa27d4e.async.js +1 -0
- package/static/dist/src__pages__env__modal.7f2ef1bc.async.js +1 -0
- package/static/dist/src__pages__error__index.f156b45e.async.js +1 -0
- package/static/dist/src__pages__initialization__index.e96d4ba8.async.js +1 -0
- package/static/dist/{src__pages__log__index.cf00c9af.async.js → src__pages__log__index.e0978bae.async.js} +1 -1
- 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.3e7e100d.async.js +1 -0
- package/static/dist/src__pages__script__index.2765d1b8.async.js +1 -0
- package/static/dist/src__pages__script__renameModal.5e987ef5.async.js +1 -0
- package/static/dist/src__pages__script__saveModal.3f9d23d6.async.js +1 -0
- package/static/dist/src__pages__script__setting.a535793a.async.js +1 -0
- package/static/dist/src__pages__setting__appModal.251cd14f.async.js +1 -0
- package/static/dist/src__pages__setting__dependence.8a7a9529.async.js +1 -0
- package/static/dist/src__pages__setting__index.cc85fdfb.async.js +1 -0
- package/static/dist/src__pages__setting__notification.390fc905.async.js +1 -0
- package/static/dist/src__pages__setting__other.b22d2165.async.js +1 -0
- package/static/dist/src__pages__setting__security.598720a8.async.js +1 -0
- package/static/dist/src__pages__setting__systemLog.67406721.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.3562c670.async.js +1 -0
- package/static/dist/{umi.ef8199a4.js → umi.ca04a019.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/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__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__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__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
|
@@ -13,31 +13,46 @@ exports.HttpServerService = void 0;
|
|
|
13
13
|
const logger_1 = __importDefault(require("../loaders/logger"));
|
|
14
14
|
const metrics_1 = require("./metrics");
|
|
15
15
|
const typedi_1 = require("typedi");
|
|
16
|
+
const config_1 = __importDefault(require("../config"));
|
|
16
17
|
let HttpServerService = class HttpServerService {
|
|
17
18
|
constructor() {
|
|
18
19
|
this.server = undefined;
|
|
19
20
|
}
|
|
20
21
|
async initialize(expressApp, port) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
reject(err);
|
|
22
|
+
const hostsToTry = [
|
|
23
|
+
config_1.default.bindHost,
|
|
24
|
+
...(config_1.default.bindHost !== '0.0.0.0' ? ['0.0.0.0'] : [])
|
|
25
|
+
];
|
|
26
|
+
let lastError = null;
|
|
27
|
+
for (const host of hostsToTry) {
|
|
28
|
+
try {
|
|
29
|
+
const server = await this.tryListen(expressApp, port, host);
|
|
30
|
+
logger_1.default.debug(`✌️ HTTP service started successfully on ${host}:${port}`);
|
|
31
|
+
metrics_1.metricsService.record('http_service_start', 1, {
|
|
32
|
+
port: port.toString(),
|
|
33
|
+
host
|
|
34
34
|
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
this.server = server;
|
|
36
|
+
return server;
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
lastError = err;
|
|
40
|
+
logger_1.default.warn(`Failed to bind HTTP on ${host}:${port}, trying next...`, err);
|
|
41
|
+
}
|
|
40
42
|
}
|
|
43
|
+
logger_1.default.error('Failed to start HTTP service on all hosts');
|
|
44
|
+
throw lastError || new Error('Failed to start HTTP service');
|
|
45
|
+
}
|
|
46
|
+
async tryListen(expressApp, port, host) {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
const server = expressApp.listen(port, host, () => {
|
|
49
|
+
resolve(server);
|
|
50
|
+
});
|
|
51
|
+
server.on('error', (err) => {
|
|
52
|
+
server.close();
|
|
53
|
+
reject(err);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
41
56
|
}
|
|
42
57
|
async shutdown() {
|
|
43
58
|
try {
|
|
@@ -27,6 +27,7 @@ const crypto_1 = __importDefault(require("crypto"));
|
|
|
27
27
|
const nodemailer_1 = __importDefault(require("nodemailer"));
|
|
28
28
|
const typedi_1 = require("typedi");
|
|
29
29
|
const util_1 = require("../config/util");
|
|
30
|
+
const i18n_1 = require("../shared/i18n");
|
|
30
31
|
const user_1 = __importDefault(require("./user"));
|
|
31
32
|
const http_1 = require("../config/http");
|
|
32
33
|
const undici_1 = require("undici");
|
|
@@ -54,6 +55,7 @@ let NotificationService = class NotificationService {
|
|
|
54
55
|
['chronocat', this.chronocat],
|
|
55
56
|
['ntfy', this.ntfy],
|
|
56
57
|
['wxPusherBot', this.wxPusherBot],
|
|
58
|
+
['openiLink', this.openiLink],
|
|
57
59
|
]);
|
|
58
60
|
this.title = '';
|
|
59
61
|
this.content = '';
|
|
@@ -97,6 +99,13 @@ let NotificationService = class NotificationService {
|
|
|
97
99
|
}
|
|
98
100
|
return true;
|
|
99
101
|
}
|
|
102
|
+
parseMailRecipients(value) {
|
|
103
|
+
const recipients = (value || '')
|
|
104
|
+
.split(/[;;]/)
|
|
105
|
+
.map((item) => item.trim())
|
|
106
|
+
.filter(Boolean);
|
|
107
|
+
return recipients.length > 0 ? recipients : undefined;
|
|
108
|
+
}
|
|
100
109
|
async gotify() {
|
|
101
110
|
const { gotifyUrl, gotifyToken, gotifyPriority = 1 } = this.params;
|
|
102
111
|
try {
|
|
@@ -488,6 +497,7 @@ let NotificationService = class NotificationService {
|
|
|
488
497
|
}
|
|
489
498
|
async email() {
|
|
490
499
|
const { emailPass, emailService, emailUser, emailTo } = this.params;
|
|
500
|
+
const recipients = this.parseMailRecipients(emailTo) || emailUser;
|
|
491
501
|
try {
|
|
492
502
|
const transporter = nodemailer_1.default.createTransport({
|
|
493
503
|
service: emailService,
|
|
@@ -498,7 +508,7 @@ let NotificationService = class NotificationService {
|
|
|
498
508
|
});
|
|
499
509
|
const info = await transporter.sendMail({
|
|
500
510
|
from: `"青龙快讯" <${emailUser}>`,
|
|
501
|
-
to:
|
|
511
|
+
to: recipients,
|
|
502
512
|
subject: `${this.title}`,
|
|
503
513
|
html: `${this.content.replace(/\n/g, '<br/>')}`,
|
|
504
514
|
});
|
|
@@ -586,7 +596,7 @@ let NotificationService = class NotificationService {
|
|
|
586
596
|
: [];
|
|
587
597
|
// topic_ids 和 uids 至少要有一个
|
|
588
598
|
if (!topicIds.length && !uids.length) {
|
|
589
|
-
throw new Error('wxPusher 服务的 TopicIds 和 Uids 至少配置一个才行');
|
|
599
|
+
throw new Error((0, i18n_1.t)('wxPusher 服务的 TopicIds 和 Uids 至少配置一个才行'));
|
|
590
600
|
}
|
|
591
601
|
const url = `https://wxpusher.zjiecode.com/api/send/message`;
|
|
592
602
|
try {
|
|
@@ -665,7 +675,7 @@ let NotificationService = class NotificationService {
|
|
|
665
675
|
var _a;
|
|
666
676
|
const { webhookUrl, webhookBody, webhookHeaders, webhookMethod, webhookContentType, } = this.params;
|
|
667
677
|
if (!(webhookUrl === null || webhookUrl === void 0 ? void 0 : webhookUrl.includes('$title')) && !(webhookBody === null || webhookBody === void 0 ? void 0 : webhookBody.includes('$title'))) {
|
|
668
|
-
throw new Error('Url 或者 Body 中必须包含 $title');
|
|
678
|
+
throw new Error((0, i18n_1.t)('Url 或者 Body 中必须包含 $title'));
|
|
669
679
|
}
|
|
670
680
|
const headers = (0, util_1.parseHeaders)(webhookHeaders);
|
|
671
681
|
const body = (0, util_1.parseBody)(webhookBody, webhookContentType, (v) => { var _a; return (_a = v === null || v === void 0 ? void 0 : v.replaceAll('$title', this.title)) === null || _a === void 0 ? void 0 : _a.replaceAll('$content', this.content); });
|
|
@@ -700,6 +710,33 @@ let NotificationService = class NotificationService {
|
|
|
700
710
|
}
|
|
701
711
|
return {};
|
|
702
712
|
}
|
|
713
|
+
async openiLink() {
|
|
714
|
+
const { openiLinkAppToken, openiLinkHubUrl, openiLinkContextToken } = this.params;
|
|
715
|
+
const baseUrl = (openiLinkHubUrl === null || openiLinkHubUrl === void 0 ? void 0 : openiLinkHubUrl.replace(/\/$/, '')) || 'https://hub.openilink.com';
|
|
716
|
+
const url = `${baseUrl}/bot/v1/message/send`;
|
|
717
|
+
const body = {
|
|
718
|
+
type: 'text',
|
|
719
|
+
content: `${this.title}\n\n${this.content}`,
|
|
720
|
+
};
|
|
721
|
+
if (openiLinkContextToken) {
|
|
722
|
+
body.context_token = openiLinkContextToken;
|
|
723
|
+
}
|
|
724
|
+
try {
|
|
725
|
+
const res = await http_1.httpClient.post(url, Object.assign(Object.assign({}, this.gotOption), { json: body, headers: {
|
|
726
|
+
'Content-Type': 'application/json',
|
|
727
|
+
Authorization: `Bearer ${openiLinkAppToken}`,
|
|
728
|
+
} }));
|
|
729
|
+
if (res.ok) {
|
|
730
|
+
return true;
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
throw new Error(JSON.stringify(res));
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
catch (error) {
|
|
737
|
+
throw new Error(error.response ? error.response.body : error);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
703
740
|
};
|
|
704
741
|
__decorate([
|
|
705
742
|
(0, typedi_1.Inject)((type) => user_1.default),
|
|
@@ -22,6 +22,7 @@ const open_1 = require("../data/open");
|
|
|
22
22
|
const uuid_1 = require("uuid");
|
|
23
23
|
const sequelize_1 = require("sequelize");
|
|
24
24
|
const store_1 = require("../shared/store");
|
|
25
|
+
const i18n_1 = require("../shared/i18n");
|
|
25
26
|
let OpenService = class OpenService {
|
|
26
27
|
constructor(logger) {
|
|
27
28
|
this.logger = logger;
|
|
@@ -141,7 +142,7 @@ let OpenService = class OpenService {
|
|
|
141
142
|
};
|
|
142
143
|
}
|
|
143
144
|
else {
|
|
144
|
-
return { code: 400, message: 'client_id 或 client_seret 有误' };
|
|
145
|
+
return { code: 400, message: (0, i18n_1.t)('client_id 或 client_seret 有误') };
|
|
145
146
|
}
|
|
146
147
|
}
|
|
147
148
|
async generateSystemToken() {
|
|
@@ -48,9 +48,12 @@ let SshKeyService = class SshKeyService {
|
|
|
48
48
|
}
|
|
49
49
|
async generatePrivateKeyFile(alias, key) {
|
|
50
50
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
const filePath = path_1.default.join(this.sshPath, alias);
|
|
52
|
+
try {
|
|
53
|
+
await (0, util_1.rmPath)(filePath);
|
|
54
|
+
}
|
|
55
|
+
catch (_a) { }
|
|
56
|
+
await (0, utils_1.writeFileWithLock)(filePath, `${key}${os_1.default.EOL}`, { mode: '400' });
|
|
54
57
|
}
|
|
55
58
|
catch (error) {
|
|
56
59
|
this.logger.error('生成私钥文件失败', error);
|
|
@@ -48,6 +48,7 @@ const sequelize_1 = require("sequelize");
|
|
|
48
48
|
const path_1 = __importStar(require("path"));
|
|
49
49
|
const schedule_1 = __importDefault(require("./schedule"));
|
|
50
50
|
const sock_1 = __importDefault(require("./sock"));
|
|
51
|
+
const i18n_1 = require("../shared/i18n");
|
|
51
52
|
const sshKey_1 = __importDefault(require("./sshKey"));
|
|
52
53
|
const const_1 = require("../config/const");
|
|
53
54
|
const subscription_2 = require("../config/subscription");
|
|
@@ -171,7 +172,7 @@ let SubscriptionService = class SubscriptionService {
|
|
|
171
172
|
await subscription_1.SubscriptionModel.update({ status: subscription_1.SubscriptionStatus.idle, pid: undefined }, { where: { id: sub.id } });
|
|
172
173
|
this.sockService.sendMessage({
|
|
173
174
|
type: 'runSubscriptionEnd',
|
|
174
|
-
message: '订阅执行完成',
|
|
175
|
+
message: (0, i18n_1.t)('订阅执行完成'),
|
|
175
176
|
references: [doc.id],
|
|
176
177
|
});
|
|
177
178
|
},
|
|
@@ -44,6 +44,7 @@ const schedule_1 = __importDefault(require("./schedule"));
|
|
|
44
44
|
const sock_1 = __importDefault(require("./sock"));
|
|
45
45
|
const os_1 = __importDefault(require("os"));
|
|
46
46
|
const dayjs_1 = __importDefault(require("dayjs"));
|
|
47
|
+
const i18n_1 = require("../shared/i18n");
|
|
47
48
|
const util_2 = require("../config/util");
|
|
48
49
|
let SystemService = class SystemService {
|
|
49
50
|
constructor(logger, scheduleService, sockService) {
|
|
@@ -80,7 +81,7 @@ let SystemService = class SystemService {
|
|
|
80
81
|
return { code: 200, data: Object.assign(Object.assign({}, result), { code }) };
|
|
81
82
|
}
|
|
82
83
|
else {
|
|
83
|
-
return { code: 400, message: '通知发送失败,请检查参数' };
|
|
84
|
+
return { code: 400, message: (0, i18n_1.t)('通知发送失败,请检查参数') };
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
87
|
async updateLogRemoveFrequency(info) {
|
|
@@ -302,10 +303,10 @@ let SystemService = class SystemService {
|
|
|
302
303
|
}
|
|
303
304
|
const isSuccess = await this.notificationService.notify(title, content, notificationInfo);
|
|
304
305
|
if (isSuccess) {
|
|
305
|
-
return { code: 200, message: '通知发送成功' };
|
|
306
|
+
return { code: 200, message: (0, i18n_1.t)('通知发送成功') };
|
|
306
307
|
}
|
|
307
308
|
else {
|
|
308
|
-
return { code: 400, message: '通知发送失败,请检查系统设置/通知配置' };
|
|
309
|
+
return { code: 400, message: (0, i18n_1.t)('通知发送失败,请检查系统设置/通知配置') };
|
|
309
310
|
}
|
|
310
311
|
}
|
|
311
312
|
async run({ command, logPath }, callback) {
|
|
@@ -321,7 +322,7 @@ let SystemService = class SystemService {
|
|
|
321
322
|
}
|
|
322
323
|
async stop({ command, pid }) {
|
|
323
324
|
if (!pid && !command) {
|
|
324
|
-
return { code: 400, message: '参数错误' };
|
|
325
|
+
return { code: 400, message: (0, i18n_1.t)('参数错误') };
|
|
325
326
|
}
|
|
326
327
|
if (pid) {
|
|
327
328
|
await (0, util_1.killTask)(pid);
|
|
@@ -336,7 +337,7 @@ let SystemService = class SystemService {
|
|
|
336
337
|
return { code: 200 };
|
|
337
338
|
}
|
|
338
339
|
else {
|
|
339
|
-
return { code: 400, message: '任务未找到' };
|
|
340
|
+
return { code: 400, message: (0, i18n_1.t)('任务未找到') };
|
|
340
341
|
}
|
|
341
342
|
}
|
|
342
343
|
async exportData(res, type) {
|
|
@@ -411,9 +412,23 @@ let SystemService = class SystemService {
|
|
|
411
412
|
return { code: 200, data: info };
|
|
412
413
|
}
|
|
413
414
|
else {
|
|
414
|
-
return { code: 400, message: '设置时区失败' };
|
|
415
|
+
return { code: 400, message: (0, i18n_1.t)('设置时区失败') };
|
|
415
416
|
}
|
|
416
417
|
}
|
|
418
|
+
async updateLanguage(info) {
|
|
419
|
+
const oDoc = await this.getSystemConfig();
|
|
420
|
+
const lang = info.lang || 'zh';
|
|
421
|
+
await this.updateAuthDb(Object.assign(Object.assign({}, oDoc), { info: Object.assign(Object.assign({}, oDoc.info), { lang }) }));
|
|
422
|
+
// Write to standalone lang_env.sh, sourced by shell scripts
|
|
423
|
+
try {
|
|
424
|
+
await fs_1.default.promises.writeFile(config_1.default.langEnvFile, `export QL_LANG='${lang}'\n`);
|
|
425
|
+
}
|
|
426
|
+
catch (error) {
|
|
427
|
+
this.logger.error(`Failed to write lang_env.sh: ${error}`);
|
|
428
|
+
}
|
|
429
|
+
(0, i18n_1.setLang)(lang);
|
|
430
|
+
return { code: 200, data: { lang } };
|
|
431
|
+
}
|
|
417
432
|
async updateGlobalSshKey(info) {
|
|
418
433
|
const oDoc = await this.getSystemConfig();
|
|
419
434
|
const result = await this.updateAuthDb(Object.assign(Object.assign({}, oDoc), { info: Object.assign(Object.assign({}, oDoc.info), info) }));
|
|
@@ -431,7 +446,7 @@ let SystemService = class SystemService {
|
|
|
431
446
|
}
|
|
432
447
|
async cleanDependence(type) {
|
|
433
448
|
if (!type || !['node', 'python3'].includes(type)) {
|
|
434
|
-
return { code: 400, message: '参数错误' };
|
|
449
|
+
return { code: 400, message: (0, i18n_1.t)('参数错误') };
|
|
435
450
|
}
|
|
436
451
|
try {
|
|
437
452
|
const finalPath = path_1.default.join(config_1.default.dependenceCachePath, type);
|
|
@@ -32,6 +32,7 @@ const uniq_1 = __importDefault(require("lodash/uniq"));
|
|
|
32
32
|
const pickBy_1 = __importDefault(require("lodash/pickBy"));
|
|
33
33
|
const isNil_1 = __importDefault(require("lodash/isNil"));
|
|
34
34
|
const store_1 = require("../shared/store");
|
|
35
|
+
const i18n_1 = require("../shared/i18n");
|
|
35
36
|
let UserService = class UserService {
|
|
36
37
|
constructor(logger, scheduleService, sockService) {
|
|
37
38
|
this.logger = logger;
|
|
@@ -195,16 +196,16 @@ let UserService = class UserService {
|
|
|
195
196
|
}
|
|
196
197
|
async updateUsernameAndPassword({ username, password, }) {
|
|
197
198
|
if (password === 'admin') {
|
|
198
|
-
return { code: 400, message: '密码不能设置为admin' };
|
|
199
|
+
return { code: 400, message: (0, i18n_1.t)('密码不能设置为admin') };
|
|
199
200
|
}
|
|
200
201
|
const authInfo = await this.getAuthInfo();
|
|
201
202
|
await this.updateAuthInfo(authInfo, { username, password });
|
|
202
|
-
return { code: 200, message: '更新成功' };
|
|
203
|
+
return { code: 200, message: (0, i18n_1.t)('更新成功') };
|
|
203
204
|
}
|
|
204
205
|
async updateAvatar(avatar) {
|
|
205
206
|
const authInfo = await this.getAuthInfo();
|
|
206
207
|
await this.updateAuthInfo(authInfo, { avatar });
|
|
207
|
-
return { code: 200, data: avatar, message: '更新成功' };
|
|
208
|
+
return { code: 200, data: avatar, message: (0, i18n_1.t)('更新成功') };
|
|
208
209
|
}
|
|
209
210
|
async initTwoFactor() {
|
|
210
211
|
const secret = preset_default_1.authenticator.generateSecret();
|
|
@@ -228,7 +229,7 @@ let UserService = class UserService {
|
|
|
228
229
|
const authInfo = await this.getAuthInfo();
|
|
229
230
|
const { isTwoFactorChecking, twoFactorSecret } = authInfo;
|
|
230
231
|
if (!isTwoFactorChecking) {
|
|
231
|
-
return { code: 450, message: '未知错误' };
|
|
232
|
+
return { code: 450, message: (0, i18n_1.t)('未知错误') };
|
|
232
233
|
}
|
|
233
234
|
const isValid = preset_default_1.authenticator.verify({
|
|
234
235
|
token: code,
|
|
@@ -253,10 +254,10 @@ let UserService = class UserService {
|
|
|
253
254
|
lastaddr: address,
|
|
254
255
|
platform: req.platform,
|
|
255
256
|
});
|
|
256
|
-
return { code: 430, message: '验证失败' };
|
|
257
|
+
return { code: 430, message: (0, i18n_1.t)('验证失败') };
|
|
257
258
|
}
|
|
258
259
|
}
|
|
259
|
-
async
|
|
260
|
+
async deactivateTwoFactor() {
|
|
260
261
|
const authInfo = await this.getAuthInfo();
|
|
261
262
|
await this.updateAuthInfo(authInfo, {
|
|
262
263
|
twoFactorActivated: false,
|
|
@@ -316,7 +317,7 @@ let UserService = class UserService {
|
|
|
316
317
|
return { code: 200, data: Object.assign(Object.assign({}, result), { code }) };
|
|
317
318
|
}
|
|
318
319
|
else {
|
|
319
|
-
return { code: 400, message: '通知发送失败,请检查参数' };
|
|
320
|
+
return { code: 400, message: (0, i18n_1.t)('通知发送失败,请检查参数') };
|
|
320
321
|
}
|
|
321
322
|
}
|
|
322
323
|
normalizeTokens(tokens) {
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.t = exports.getLang = exports.setLang = void 0;
|
|
4
|
+
const messages = {
|
|
5
|
+
zh: {},
|
|
6
|
+
en: {
|
|
7
|
+
'暂无权限': 'Access denied',
|
|
8
|
+
'参数错误': 'Invalid parameter',
|
|
9
|
+
'参数不正确': 'Invalid parameter',
|
|
10
|
+
'文件无法访问': 'File not accessible',
|
|
11
|
+
'文件不存在': 'File not found',
|
|
12
|
+
'路径不存在': 'Path does not exist',
|
|
13
|
+
'路径不正确': 'Invalid path',
|
|
14
|
+
'通知发送失败,请检查参数': 'Notification failed, check parameters',
|
|
15
|
+
'通知发送失败,请检查系统设置/通知配置': 'Notification failed, check system settings',
|
|
16
|
+
'通知发送成功': 'Notification sent successfully',
|
|
17
|
+
'设置时区失败': 'Failed to set timezone',
|
|
18
|
+
'任务未找到': 'Task not found',
|
|
19
|
+
'密码不能设置为admin': 'Password cannot be admin',
|
|
20
|
+
'更新成功': 'Update successful',
|
|
21
|
+
'未知错误': 'Unknown error',
|
|
22
|
+
'验证失败': 'Verification failed',
|
|
23
|
+
'实例不存在或已停止': 'Instance does not exist or stopped',
|
|
24
|
+
'实例已停止': 'Instance stopped',
|
|
25
|
+
'确认停止实例': 'Confirm to stop instance',
|
|
26
|
+
'确认停止运行实例': 'Confirm to stop running instance',
|
|
27
|
+
'确认停止': 'Confirm to stop',
|
|
28
|
+
'确认停止定时任务': 'Confirm to stop scheduled task',
|
|
29
|
+
'确认删除': 'Confirm to delete',
|
|
30
|
+
'确认删除定时任务': 'Confirm to delete scheduled task',
|
|
31
|
+
'确认删除选中的定时任务吗': 'Confirm to delete selected tasks?',
|
|
32
|
+
'确认运行': 'Confirm to run',
|
|
33
|
+
'确认运行定时任务': 'Confirm to run scheduled task',
|
|
34
|
+
'确认保存': 'Confirm to save',
|
|
35
|
+
'确认保存文件': 'Confirm to save file',
|
|
36
|
+
'确认重启': 'Confirm restart',
|
|
37
|
+
'确认启用': 'Confirm to enable',
|
|
38
|
+
'确认禁用': 'Confirm to disable',
|
|
39
|
+
'确认': 'Confirm',
|
|
40
|
+
'删除成功': 'Deleted successfully',
|
|
41
|
+
'操作成功': 'Operation successful',
|
|
42
|
+
'参数不完整': 'Incomplete parameters',
|
|
43
|
+
'默认路径不支持删除': 'Default path cannot be deleted',
|
|
44
|
+
'必须在日志目录下': 'Must be within log directory',
|
|
45
|
+
'备份数据上传成功,确认覆盖数据': 'Backup uploaded, confirm overwrite',
|
|
46
|
+
'如果恢复失败,可进入容器执行': 'If restore fails, run in container:',
|
|
47
|
+
'系统将在': 'System will',
|
|
48
|
+
'秒后自动刷新': 'refresh in seconds',
|
|
49
|
+
'生成数据中...': 'Generating data...',
|
|
50
|
+
'每条数据 name 或者 value 字段不能为空,参考导出文件格式': 'Each entry must have name and value, see export format',
|
|
51
|
+
'不支持当前依赖类型': 'Unsupported dependency type',
|
|
52
|
+
'依赖已存在': 'Dependency already exists',
|
|
53
|
+
'依赖不存在': 'Dependency does not exist',
|
|
54
|
+
'该脚本正在运行中': 'Script is running',
|
|
55
|
+
'该脚本未在运行中': 'Script is not running',
|
|
56
|
+
'文件内容为空': 'File content is empty',
|
|
57
|
+
'文件名不能为空': 'File name cannot be empty',
|
|
58
|
+
'标签不能为空': 'Label cannot be empty',
|
|
59
|
+
'名称不能为空': 'Name cannot be empty',
|
|
60
|
+
'名称不能为保留关键字': 'Name cannot be reserved keyword',
|
|
61
|
+
'名称已存在': 'Name already exists',
|
|
62
|
+
'密码错误': 'Incorrect password',
|
|
63
|
+
'用户不存在': 'User does not exist',
|
|
64
|
+
'请输入用户名和密码': 'Please enter username and password',
|
|
65
|
+
'无权访问': 'Access denied',
|
|
66
|
+
'登录成功': 'Login successful',
|
|
67
|
+
'退出成功': 'Logout successful',
|
|
68
|
+
'Token 已失效': 'Token expired',
|
|
69
|
+
'Token 无效': 'Invalid token',
|
|
70
|
+
'两步骤验证已开启': '2FA enabled',
|
|
71
|
+
'两步骤验证已关闭': '2FA disabled',
|
|
72
|
+
'验证码错误': 'Invalid verification code',
|
|
73
|
+
'验证码已过期': 'Verification code expired',
|
|
74
|
+
'请先开启两步骤验证': 'Please enable 2FA first',
|
|
75
|
+
'两步骤验证密钥不能为空': '2FA secret cannot be empty',
|
|
76
|
+
'用户已存在': 'User already exists',
|
|
77
|
+
'用户名不能为admin': 'Username cannot be admin',
|
|
78
|
+
'不能删除自己': 'Cannot delete yourself',
|
|
79
|
+
'不能禁用自己': 'Cannot disable yourself',
|
|
80
|
+
'文件路径无效': 'Invalid file path',
|
|
81
|
+
'保存成功': 'Saved successfully',
|
|
82
|
+
'client_id 或 client_seret 有误': 'Invalid client_id or client_secret',
|
|
83
|
+
'订阅执行完成': 'Subscription completed',
|
|
84
|
+
'wxPusher 服务的 TopicIds 和 Uids 至少配置一个才行': 'wxPusher requires at least one of TopicIds or Uids',
|
|
85
|
+
'Url 或者 Body 中必须包含 $title': 'Url or Body must contain $title',
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
let currentLang = 'zh';
|
|
89
|
+
function setLang(lang) {
|
|
90
|
+
currentLang = lang || 'zh';
|
|
91
|
+
}
|
|
92
|
+
exports.setLang = setLang;
|
|
93
|
+
function getLang() {
|
|
94
|
+
return currentLang;
|
|
95
|
+
}
|
|
96
|
+
exports.getLang = getLang;
|
|
97
|
+
function t(key, lang) {
|
|
98
|
+
const effectiveLang = lang || currentLang;
|
|
99
|
+
if (effectiveLang === 'en' && messages.en[key]) {
|
|
100
|
+
return messages.en[key];
|
|
101
|
+
}
|
|
102
|
+
return key;
|
|
103
|
+
}
|
|
104
|
+
exports.t = t;
|
|
105
|
+
//# sourceMappingURL=i18n.js.map
|
|
@@ -11,7 +11,18 @@ const notify_1 = __importDefault(require("../services/notify"));
|
|
|
11
11
|
const config_1 = __importDefault(require("../config"));
|
|
12
12
|
const grpc_js_1 = require("@grpc/grpc-js");
|
|
13
13
|
const api_1 = require("../protos/api");
|
|
14
|
+
const grpcCerts_1 = require("../config/grpcCerts");
|
|
14
15
|
class TaskLimit {
|
|
16
|
+
get client() {
|
|
17
|
+
if (!this._client) {
|
|
18
|
+
const tlsConfig = (0, grpcCerts_1.getGrpcCerts)();
|
|
19
|
+
const creds = tlsConfig
|
|
20
|
+
? grpc_js_1.credentials.createSsl(Buffer.from(tlsConfig.caCert), Buffer.from(tlsConfig.clientKey), Buffer.from(tlsConfig.clientCert))
|
|
21
|
+
: grpc_js_1.credentials.createInsecure();
|
|
22
|
+
this._client = new api_1.ApiClient(`localhost:${config_1.default.grpcPort}`, creds, { 'grpc.enable_http_proxy': 0 });
|
|
23
|
+
}
|
|
24
|
+
return this._client;
|
|
25
|
+
}
|
|
15
26
|
get cronLimitActiveCount() {
|
|
16
27
|
return this.cronLimit.pending;
|
|
17
28
|
}
|
|
@@ -42,7 +53,7 @@ class TaskLimit {
|
|
|
42
53
|
this.systemLimit = new p_queue_cjs_1.default({
|
|
43
54
|
concurrency: Math.max(os_1.default.cpus().length, 4),
|
|
44
55
|
});
|
|
45
|
-
this.
|
|
56
|
+
this._client = null;
|
|
46
57
|
this.notificationService = new notify_1.default();
|
|
47
58
|
this.setCustomLimit();
|
|
48
59
|
this.handleEvents();
|
|
@@ -9,6 +9,8 @@ const pLimit_1 = __importDefault(require("./pLimit"));
|
|
|
9
9
|
const logger_1 = __importDefault(require("../loaders/logger"));
|
|
10
10
|
const cron_1 = require("../data/cron");
|
|
11
11
|
const util_1 = require("../config/util");
|
|
12
|
+
const runningInstance_1 = require("../data/runningInstance");
|
|
13
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
12
14
|
function runCron(cmd, cron) {
|
|
13
15
|
return pLimit_1.default.runWithCronLimit(cron, () => {
|
|
14
16
|
return new Promise(async (resolve) => {
|
|
@@ -26,6 +28,9 @@ function runCron(cmd, cron) {
|
|
|
26
28
|
existingCron.status === cron_1.CrontabStatus.queued)) {
|
|
27
29
|
logger_1.default.info(`[schedule][停止已运行任务] 任务ID: ${cron.id}, PID: ${existingCron.pid}`);
|
|
28
30
|
await (0, util_1.killTask)(existingCron.pid);
|
|
31
|
+
// Mark old running instances as stopped
|
|
32
|
+
const stoppedAt = (0, dayjs_1.default)().unix();
|
|
33
|
+
await runningInstance_1.RunningInstanceModel.update({ status: runningInstance_1.InstanceStatus.stopped, finished_at: stoppedAt }, { where: { cron_id: Number(cron.id), status: runningInstance_1.InstanceStatus.running } });
|
|
29
34
|
// Update the status to idle after killing
|
|
30
35
|
await cron_1.CrontabModel.update({ status: cron_1.CrontabStatus.idle, pid: undefined }, { where: { id: Number(cron.id) } });
|
|
31
36
|
}
|
|
@@ -75,5 +75,6 @@ exports.commonCronSchema = {
|
|
|
75
75
|
'string.unsafePath': '绝对路径必须在日志目录内或使用 /dev/null',
|
|
76
76
|
}),
|
|
77
77
|
allow_multiple_instances: celebrate_1.Joi.number().optional().valid(0, 1).allow(null),
|
|
78
|
+
work_dir: celebrate_1.Joi.string().optional().allow('').allow(null),
|
|
78
79
|
};
|
|
79
80
|
//# sourceMappingURL=schedule.js.map
|