@whyour/qinglong 2.21.0-1 → 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/AGENTS.md +2 -2
- 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/package.json +2 -4
- package/sample/config.sample.sh +7 -2
- package/sample/notify.js +64 -0
- package/sample/notify.py +56 -0
- package/shell/api.sh +7 -1
- package/shell/share.sh +1 -1
- package/static/build/api/cron.js +3 -3
- package/static/build/api/dashboard.js +13 -6
- package/static/build/api/env.js +2 -2
- package/static/build/api/log.js +10 -1
- package/static/build/api/system.js +6 -7
- package/static/build/app.js +19 -19
- package/static/build/config/const.js +1 -0
- package/static/build/config/grpcCerts.js +4 -4
- package/static/build/config/index.js +0 -4
- package/static/build/config/util.js +3 -3
- package/static/build/data/notify.js +8 -1
- package/static/build/data/sock.js +1 -0
- package/static/build/loaders/app.js +6 -6
- package/static/build/loaders/db.js +2 -2
- package/static/build/loaders/express.js +17 -14
- package/static/build/loaders/initData.js +8 -7
- package/static/build/loaders/initFile.js +1 -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/delCron.js +11 -1
- package/static/build/services/cron.js +103 -53
- package/static/build/services/dependence.js +19 -18
- package/static/build/services/grpc.js +1 -1
- package/static/build/services/http.js +1 -1
- package/static/build/services/notify.js +47 -5
- package/static/build/services/subscription.js +6 -4
- package/static/build/services/system.js +12 -2
- package/static/build/services/user.js +31 -6
- package/static/build/shared/auth.js +7 -1
- package/static/build/shared/i18n.js +59 -4
- package/static/build/shared/pLimit.js +3 -2
- package/static/build/shared/store.js +7 -0
- package/static/build/validation/schedule.js +9 -0
- package/static/dist/1147.62793604.async.js +1 -0
- package/static/dist/2208.85285476.async.js +1 -0
- package/static/dist/2286.f371c743.async.js +1 -0
- package/static/dist/3191.545ab873.async.js +1 -0
- package/static/dist/8826.db34ad8d.async.js +1 -0
- package/static/dist/index.html +2 -2
- package/static/dist/{preload_helper.0431c0f3.js → preload_helper.3048fe5b.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.0b8cce8c.async.js → src__pages__crontab__logModal.831d5e4b.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__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__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__modal.562448e2.async.js +1 -0
- package/static/dist/{umi.ca04a019.js → umi.a54a59f6.js} +1 -1
- package/CLAUDE.md +0 -43
- package/static/dist/1147.c420132e.async.js +0 -1
- package/static/dist/2208.f7ba3dfa.async.js +0 -1
- package/static/dist/2286.164bb089.async.js +0 -1
- package/static/dist/3191.63263871.async.js +0 -1
- package/static/dist/8826.2447a104.async.js +0 -1
- package/static/dist/src__pages__crontab__detail.b9c36808.async.js +0 -1
- package/static/dist/src__pages__crontab__index.fed99fd0.async.js +0 -1
- package/static/dist/src__pages__dashboard__index.b30f2f47.async.js +0 -1
- package/static/dist/src__pages__dependence__index.3d87ceac.async.js +0 -1
- package/static/dist/src__pages__dependence__modal.11124896.async.js +0 -1
- package/static/dist/src__pages__env__editNameModal.5d264b25.async.js +0 -1
- package/static/dist/src__pages__env__index.baa27d4e.async.js +0 -1
- package/static/dist/src__pages__env__modal.7f2ef1bc.async.js +0 -1
- package/static/dist/src__pages__error__index.f156b45e.async.js +0 -1
- package/static/dist/src__pages__initialization__index.e96d4ba8.async.js +0 -1
- package/static/dist/src__pages__log__index.e0978bae.async.js +0 -1
- package/static/dist/src__pages__script__editNameModal.3e7e100d.async.js +0 -1
- package/static/dist/src__pages__script__index.2765d1b8.async.js +0 -1
- package/static/dist/src__pages__script__renameModal.5e987ef5.async.js +0 -1
- package/static/dist/src__pages__script__saveModal.3f9d23d6.async.js +0 -1
- package/static/dist/src__pages__script__setting.a535793a.async.js +0 -1
- package/static/dist/src__pages__setting__appModal.251cd14f.async.js +0 -1
- package/static/dist/src__pages__setting__checkUpdate.46efe057.async.js +0 -1
- package/static/dist/src__pages__setting__dependence.8a7a9529.async.js +0 -1
- package/static/dist/src__pages__setting__index.cc85fdfb.async.js +0 -1
- package/static/dist/src__pages__setting__notification.390fc905.async.js +0 -1
- package/static/dist/src__pages__setting__other.b22d2165.async.js +0 -1
- package/static/dist/src__pages__setting__security.598720a8.async.js +0 -1
- package/static/dist/src__pages__setting__systemLog.67406721.async.js +0 -1
- package/static/dist/src__pages__subscription__modal.3562c670.async.js +0 -1
|
@@ -105,15 +105,24 @@ let CronService = class CronService {
|
|
|
105
105
|
return doc;
|
|
106
106
|
}
|
|
107
107
|
if (this.shouldUseCronClient(doc)) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
108
|
+
try {
|
|
109
|
+
await client_1.default.addCron([
|
|
110
|
+
{
|
|
111
|
+
name: doc.name || '',
|
|
112
|
+
id: String(doc.id),
|
|
113
|
+
schedule: doc.schedule,
|
|
114
|
+
command: this.makeCommand(doc),
|
|
115
|
+
extra_schedules: doc.extra_schedules || [],
|
|
116
|
+
},
|
|
117
|
+
]);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
// gRPC 注册失败时回滚 DB 记录,避免产生"僵尸任务"
|
|
121
|
+
// (DB 和 crontab.list 有记录但调度器永远不会执行)
|
|
122
|
+
await cron_1.CrontabModel.destroy({ where: { id: doc.id } });
|
|
123
|
+
this.logger.error('[crontab] Failed to register cron job in scheduler, task creation rolled back:', (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
124
|
+
throw new Error(`${(0, i18n_1.t)('调度器注册失败,任务创建已回滚')}: ${(error === null || error === void 0 ? void 0 : error.details) || (error === null || error === void 0 ? void 0 : error.message)}`);
|
|
125
|
+
}
|
|
117
126
|
}
|
|
118
127
|
await this.setCrontab();
|
|
119
128
|
return doc;
|
|
@@ -130,17 +139,46 @@ let CronService = class CronService {
|
|
|
130
139
|
if (doc.isDisabled === 1 || (0, util_1.isDemoEnv)()) {
|
|
131
140
|
return newDoc;
|
|
132
141
|
}
|
|
133
|
-
|
|
142
|
+
try {
|
|
143
|
+
await client_1.default.delCron([String(newDoc.id)]);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
this.logger.warn('[crontab] Failed to unregister cron job in scheduler:', (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
147
|
+
}
|
|
134
148
|
if (this.shouldUseCronClient(newDoc)) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
149
|
+
try {
|
|
150
|
+
await client_1.default.addCron([
|
|
151
|
+
{
|
|
152
|
+
name: doc.name || '',
|
|
153
|
+
id: String(newDoc.id),
|
|
154
|
+
schedule: newDoc.schedule,
|
|
155
|
+
command: this.makeCommand(newDoc),
|
|
156
|
+
extra_schedules: newDoc.extra_schedules || [],
|
|
157
|
+
},
|
|
158
|
+
]);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
// gRPC 注册新任务失败 → 回滚 DB 到旧数据,并尝试恢复旧调度注册
|
|
162
|
+
await cron_1.CrontabModel.update(doc, { where: { id: doc.id } });
|
|
163
|
+
if (this.shouldUseCronClient(doc)) {
|
|
164
|
+
try {
|
|
165
|
+
await client_1.default.addCron([
|
|
166
|
+
{
|
|
167
|
+
name: doc.name || '',
|
|
168
|
+
id: String(doc.id),
|
|
169
|
+
schedule: doc.schedule,
|
|
170
|
+
command: this.makeCommand(doc),
|
|
171
|
+
extra_schedules: doc.extra_schedules || [],
|
|
172
|
+
},
|
|
173
|
+
]);
|
|
174
|
+
}
|
|
175
|
+
catch (_recoveryError) {
|
|
176
|
+
this.logger.warn('[crontab] Failed to restore old cron job in scheduler after rollback:', (_recoveryError === null || _recoveryError === void 0 ? void 0 : _recoveryError.message) || _recoveryError);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
this.logger.error('[crontab] Failed to register updated cron job in scheduler, update rolled back:', (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
180
|
+
throw new Error(`${(0, i18n_1.t)('调度器注册失败,任务更新已回滚')}: ${(error === null || error === void 0 ? void 0 : error.details) || (error === null || error === void 0 ? void 0 : error.message)}`);
|
|
181
|
+
}
|
|
144
182
|
}
|
|
145
183
|
await this.setCrontab();
|
|
146
184
|
return newDoc;
|
|
@@ -149,7 +187,7 @@ let CronService = class CronService {
|
|
|
149
187
|
await cron_1.CrontabModel.update(payload, { where: { id: payload.id } });
|
|
150
188
|
return await this.getDb({ id: payload.id });
|
|
151
189
|
}
|
|
152
|
-
async status({ ids, status, pid, log_path, last_running_time = 0, last_execution_time = 0, }) {
|
|
190
|
+
async status({ ids, status, pid, log_path, last_running_time = 0, last_execution_time = 0, exit_code, }) {
|
|
153
191
|
let options = {
|
|
154
192
|
status,
|
|
155
193
|
pid,
|
|
@@ -185,9 +223,13 @@ let CronService = class CronService {
|
|
|
185
223
|
else if (status === cron_1.CrontabStatus.idle) {
|
|
186
224
|
// Mark the matching running instance as finished
|
|
187
225
|
const finishedAt = (0, dayjs_1.default)().unix();
|
|
226
|
+
const instanceStatus = exit_code !== undefined && exit_code !== null && exit_code !== 0
|
|
227
|
+
? runningInstance_1.InstanceStatus.error
|
|
228
|
+
: runningInstance_1.InstanceStatus.finished;
|
|
188
229
|
await runningInstance_1.RunningInstanceModel.update({
|
|
189
230
|
finished_at: finishedAt,
|
|
190
|
-
status:
|
|
231
|
+
status: instanceStatus,
|
|
232
|
+
exit_code: exit_code !== null && exit_code !== void 0 ? exit_code : undefined,
|
|
191
233
|
}, {
|
|
192
234
|
where: {
|
|
193
235
|
cron_id: id,
|
|
@@ -201,7 +243,12 @@ let CronService = class CronService {
|
|
|
201
243
|
}
|
|
202
244
|
async remove(ids) {
|
|
203
245
|
await cron_1.CrontabModel.destroy({ where: { id: ids } });
|
|
204
|
-
|
|
246
|
+
try {
|
|
247
|
+
await client_1.default.delCron(ids.map(String));
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
this.logger.warn('[crontab] Failed to unregister cron job in scheduler:', (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
251
|
+
}
|
|
205
252
|
await this.setCrontab();
|
|
206
253
|
}
|
|
207
254
|
async pin(ids) {
|
|
@@ -486,7 +533,7 @@ let CronService = class CronService {
|
|
|
486
533
|
this.logger.error(`[panel][停止实例失败] 实例ID: ${instanceId}, PID: ${instance.pid}, 错误: ${error}`);
|
|
487
534
|
}
|
|
488
535
|
}
|
|
489
|
-
await runningInstance_1.RunningInstanceModel.update({ status: runningInstance_1.InstanceStatus.stopped, finished_at: (0, dayjs_1.default)().unix() }, { where: { id: instanceId } });
|
|
536
|
+
await runningInstance_1.RunningInstanceModel.update({ status: runningInstance_1.InstanceStatus.stopped, finished_at: (0, dayjs_1.default)().unix(), exit_code: 143 }, { where: { id: instanceId } });
|
|
490
537
|
// Check if there are still other running instances for this cron
|
|
491
538
|
const otherRunning = await runningInstance_1.RunningInstanceModel.count({
|
|
492
539
|
where: { cron_id: instance.cron_id, status: runningInstance_1.InstanceStatus.running },
|
|
@@ -521,14 +568,6 @@ let CronService = class CronService {
|
|
|
521
568
|
const logPath = `${uniqPath}/${logTime}.log`;
|
|
522
569
|
const absolutePath = path_1.default.resolve(config_1.default.logPath, `${logPath}`);
|
|
523
570
|
const cp = (0, cross_spawn_1.spawn)(`real_log_path=${logPath} no_delay=true ${this.makeCommand(cron, true)}`, { shell: '/bin/bash' });
|
|
524
|
-
const startedAt = (0, dayjs_1.default)().unix();
|
|
525
|
-
const instance = await runningInstance_1.RunningInstanceModel.create({
|
|
526
|
-
cron_id: id,
|
|
527
|
-
pid: cp.pid,
|
|
528
|
-
log_path: logPath,
|
|
529
|
-
started_at: startedAt,
|
|
530
|
-
status: runningInstance_1.InstanceStatus.running,
|
|
531
|
-
});
|
|
532
571
|
await cron_1.CrontabModel.update({ status: cron_1.CrontabStatus.running, pid: cp.pid, log_path: logPath }, { where: { id } });
|
|
533
572
|
cp.stdout.on('data', async (data) => {
|
|
534
573
|
await logStreamManager_1.logStreamManager.write(absolutePath, data.toString());
|
|
@@ -544,19 +583,6 @@ let CronService = class CronService {
|
|
|
544
583
|
cp.on('exit', async (code) => {
|
|
545
584
|
this.logger.info('[panel][执行任务结束] 参数: %s, 退出码: %j', JSON.stringify(params), code);
|
|
546
585
|
await logStreamManager_1.logStreamManager.closeStream(absolutePath);
|
|
547
|
-
const finishedAt = (0, dayjs_1.default)().unix();
|
|
548
|
-
await runningInstance_1.RunningInstanceModel.update({
|
|
549
|
-
finished_at: finishedAt,
|
|
550
|
-
status: code === 0 ? runningInstance_1.InstanceStatus.finished : runningInstance_1.InstanceStatus.error,
|
|
551
|
-
exit_code: code !== null && code !== void 0 ? code : undefined,
|
|
552
|
-
}, { where: { id: instance.id } });
|
|
553
|
-
// Only set cron to idle if no other running instances exist
|
|
554
|
-
const otherRunning = await runningInstance_1.RunningInstanceModel.count({
|
|
555
|
-
where: { cron_id: id, status: runningInstance_1.InstanceStatus.running },
|
|
556
|
-
});
|
|
557
|
-
if (otherRunning === 0) {
|
|
558
|
-
await cron_1.CrontabModel.update({ status: cron_1.CrontabStatus.idle, pid: undefined }, { where: { id } });
|
|
559
|
-
}
|
|
560
586
|
resolve(Object.assign(Object.assign({}, params), { pid: cp.pid, code }));
|
|
561
587
|
});
|
|
562
588
|
});
|
|
@@ -564,7 +590,12 @@ let CronService = class CronService {
|
|
|
564
590
|
}
|
|
565
591
|
async disabled(ids) {
|
|
566
592
|
await cron_1.CrontabModel.update({ isDisabled: 1 }, { where: { id: ids } });
|
|
567
|
-
|
|
593
|
+
try {
|
|
594
|
+
await client_1.default.delCron(ids.map(String));
|
|
595
|
+
}
|
|
596
|
+
catch (error) {
|
|
597
|
+
this.logger.warn('[crontab] Failed to unregister cron job in scheduler:', (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
598
|
+
}
|
|
568
599
|
await this.setCrontab();
|
|
569
600
|
}
|
|
570
601
|
async enabled(ids) {
|
|
@@ -582,27 +613,38 @@ let CronService = class CronService {
|
|
|
582
613
|
if ((0, util_1.isDemoEnv)()) {
|
|
583
614
|
return;
|
|
584
615
|
}
|
|
585
|
-
|
|
616
|
+
try {
|
|
617
|
+
await client_1.default.addCron(crons);
|
|
618
|
+
}
|
|
619
|
+
catch (error) {
|
|
620
|
+
// gRPC 注册失败 → 回滚启用状态,避免 DB 显示已启用但调度器未注册
|
|
621
|
+
await cron_1.CrontabModel.update({ isDisabled: 1 }, { where: { id: ids } });
|
|
622
|
+
this.logger.error('[crontab] Failed to register cron job in scheduler, enable rolled back:', (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
623
|
+
throw new Error(`${(0, i18n_1.t)('调度器注册失败,任务启用已回滚')}: ${(error === null || error === void 0 ? void 0 : error.details) || (error === null || error === void 0 ? void 0 : error.message)}`);
|
|
624
|
+
}
|
|
586
625
|
await this.setCrontab();
|
|
587
626
|
}
|
|
588
627
|
async log(id) {
|
|
589
628
|
const doc = await this.getDb({ id });
|
|
590
629
|
if (!doc) {
|
|
591
|
-
return '';
|
|
630
|
+
return { content: '', status: 'empty' };
|
|
592
631
|
}
|
|
593
632
|
if (doc.log_name === '/dev/null') {
|
|
594
|
-
return '日志设置为忽略';
|
|
633
|
+
return { content: (0, i18n_1.t)('日志设置为忽略'), status: 'ignored' };
|
|
595
634
|
}
|
|
596
635
|
const absolutePath = path_1.default.resolve(config_1.default.logPath, `${doc.log_path}`);
|
|
597
636
|
const logFileExist = doc.log_path && (await (0, util_1.fileExist)(absolutePath));
|
|
598
637
|
if (logFileExist) {
|
|
599
|
-
|
|
638
|
+
const content = await (0, util_1.getFileContentByName)(`${absolutePath}`);
|
|
639
|
+
const isRunning = typeof doc.status === 'number' &&
|
|
640
|
+
[cron_1.CrontabStatus.running, cron_1.CrontabStatus.queued].includes(doc.status);
|
|
641
|
+
return { content, status: isRunning ? 'running' : 'completed' };
|
|
600
642
|
}
|
|
601
643
|
else {
|
|
602
644
|
return typeof doc.status === 'number' &&
|
|
603
645
|
[cron_1.CrontabStatus.queued, cron_1.CrontabStatus.running].includes(doc.status)
|
|
604
|
-
? '运行中...'
|
|
605
|
-
: '日志不存在...';
|
|
646
|
+
? { content: (0, i18n_1.t)('运行中...'), status: 'running' }
|
|
647
|
+
: { content: (0, i18n_1.t)('日志不存在...'), status: 'notFound' };
|
|
606
648
|
}
|
|
607
649
|
}
|
|
608
650
|
async logs(id) {
|
|
@@ -733,8 +775,16 @@ let CronService = class CronService {
|
|
|
733
775
|
await (0, utils_1.writeFileWithLock)(config_1.default.crontabFile, '');
|
|
734
776
|
return;
|
|
735
777
|
}
|
|
736
|
-
|
|
737
|
-
|
|
778
|
+
// 先同步 crontab.list 与系统 crontab,确保其始终反映数据库真实状态。
|
|
779
|
+
// gRPC 调度注册为尽力而为:失败时不阻断文件同步,调度器重启后会重新注册。
|
|
780
|
+
// 这避免了因调度器短暂不可用导致 crontab.list 与数据库脱节(订阅更新误判任务已存在)。
|
|
781
|
+
await this.setCrontab(tabs);
|
|
782
|
+
try {
|
|
783
|
+
await client_1.default.addCron(regularCrons);
|
|
784
|
+
}
|
|
785
|
+
catch (error) {
|
|
786
|
+
this.logger.warn('[crontab] Failed to register cron job in scheduler:', (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
787
|
+
}
|
|
738
788
|
}
|
|
739
789
|
async bootTask() {
|
|
740
790
|
const tabs = await this.crontabs();
|
|
@@ -38,6 +38,7 @@ const dayjs_1 = __importDefault(require("dayjs"));
|
|
|
38
38
|
const pLimit_1 = __importDefault(require("../shared/pLimit"));
|
|
39
39
|
const util_2 = require("../config/util");
|
|
40
40
|
const const_1 = require("../config/const");
|
|
41
|
+
const i18n_1 = require("../shared/i18n");
|
|
41
42
|
let DependenceService = class DependenceService {
|
|
42
43
|
constructor(logger, sockService) {
|
|
43
44
|
this.logger = logger;
|
|
@@ -183,7 +184,7 @@ let DependenceService = class DependenceService {
|
|
|
183
184
|
}
|
|
184
185
|
const depIds = [dependency.id];
|
|
185
186
|
let depName = dependency.name.trim();
|
|
186
|
-
const actionText = isInstall ? '安装' : '删除';
|
|
187
|
+
const actionText = isInstall ? (0, i18n_1.t)('安装') : (0, i18n_1.t)('删除');
|
|
187
188
|
const socketMessageType = isInstall
|
|
188
189
|
? 'installDependence'
|
|
189
190
|
: 'uninstallDependence';
|
|
@@ -197,11 +198,12 @@ let DependenceService = class DependenceService {
|
|
|
197
198
|
if (!osType) {
|
|
198
199
|
await dependence_1.DependenceModel.update({ status: dependence_1.DependenceStatus.installFailed }, { where: { id: depIds } });
|
|
199
200
|
const startTime = (0, dayjs_1.default)();
|
|
200
|
-
const message =
|
|
201
|
+
const message = (0, i18n_1.tf)('开始%s依赖 %s,开始时间 %s\n\n当前系统不支持\n\n依赖%s失败,结束时间 %s,耗时 %s 秒', actionText, depName, startTime.format('YYYY-MM-DD HH:mm:ss'), actionText, startTime.format('YYYY-MM-DD HH:mm:ss'), String(startTime.diff(startTime, 'second')));
|
|
201
202
|
this.sockService.sendMessage({
|
|
202
203
|
type: socketMessageType,
|
|
203
204
|
message,
|
|
204
205
|
references: depIds,
|
|
206
|
+
status: dependence_1.DependenceStatus.installFailed,
|
|
205
207
|
});
|
|
206
208
|
this.updateLog(depIds, message);
|
|
207
209
|
return resolve(null);
|
|
@@ -221,11 +223,12 @@ let DependenceService = class DependenceService {
|
|
|
221
223
|
: `${linuxCommand.uninstall} ${depName.trim()}`;
|
|
222
224
|
}
|
|
223
225
|
const startTime = (0, dayjs_1.default)();
|
|
224
|
-
const message =
|
|
226
|
+
const message = (0, i18n_1.tf)('开始%s依赖 %s,开始时间 %s\n\n', actionText, depName, startTime.format('YYYY-MM-DD HH:mm:ss'));
|
|
225
227
|
this.sockService.sendMessage({
|
|
226
228
|
type: socketMessageType,
|
|
227
229
|
message,
|
|
228
230
|
references: depIds,
|
|
231
|
+
status,
|
|
229
232
|
});
|
|
230
233
|
this.updateLog(depIds, message);
|
|
231
234
|
// 判断是否已经安装过依赖
|
|
@@ -254,11 +257,12 @@ let DependenceService = class DependenceService {
|
|
|
254
257
|
isPythonDependence) &&
|
|
255
258
|
(!depVersion || depInfo.includes(depVersion))) {
|
|
256
259
|
const endTime = (0, dayjs_1.default)();
|
|
257
|
-
const _message =
|
|
260
|
+
const _message = (0, i18n_1.tf)('检测到已经安装 %s\n\n%s\n\n跳过安装\n\n依赖%s成功,结束时间 %s,耗时 %s 秒', depName, depInfo, actionText, endTime.format('YYYY-MM-DD HH:mm:ss'), String(endTime.diff(startTime, 'second')));
|
|
258
261
|
this.sockService.sendMessage({
|
|
259
262
|
type: socketMessageType,
|
|
260
263
|
message: _message,
|
|
261
264
|
references: depIds,
|
|
265
|
+
status: dependence_1.DependenceStatus.installed,
|
|
262
266
|
});
|
|
263
267
|
this.updateLog(depIds, _message);
|
|
264
268
|
await dependence_1.DependenceModel.update({ status: dependence_1.DependenceStatus.installed }, { where: { id: depIds } });
|
|
@@ -277,6 +281,7 @@ let DependenceService = class DependenceService {
|
|
|
277
281
|
type: socketMessageType,
|
|
278
282
|
message: data.toString(),
|
|
279
283
|
references: depIds,
|
|
284
|
+
status,
|
|
280
285
|
});
|
|
281
286
|
this.updateLog(depIds, data.toString());
|
|
282
287
|
});
|
|
@@ -285,6 +290,7 @@ let DependenceService = class DependenceService {
|
|
|
285
290
|
type: socketMessageType,
|
|
286
291
|
message: data.toString(),
|
|
287
292
|
references: depIds,
|
|
293
|
+
status,
|
|
288
294
|
});
|
|
289
295
|
this.updateLog(depIds, data.toString());
|
|
290
296
|
});
|
|
@@ -293,37 +299,32 @@ let DependenceService = class DependenceService {
|
|
|
293
299
|
type: socketMessageType,
|
|
294
300
|
message: JSON.stringify(err),
|
|
295
301
|
references: depIds,
|
|
302
|
+
status,
|
|
296
303
|
});
|
|
297
304
|
this.updateLog(depIds, JSON.stringify(err));
|
|
298
305
|
});
|
|
299
306
|
cp.on('exit', async (code) => {
|
|
300
307
|
const endTime = (0, dayjs_1.default)();
|
|
301
308
|
const isSucceed = code === 0;
|
|
302
|
-
const resultText = isSucceed ? '成功' : '失败';
|
|
303
|
-
const message =
|
|
309
|
+
const resultText = isSucceed ? (0, i18n_1.t)('成功') : (0, i18n_1.t)('失败');
|
|
310
|
+
const message = '\n' +
|
|
311
|
+
(0, i18n_1.tf)('依赖%s%s,结束时间 %s,耗时 %s 秒', actionText, resultText, endTime.format('YYYY-MM-DD HH:mm:ss'), String(endTime.diff(startTime, 'second')));
|
|
312
|
+
const exitStatus = isSucceed
|
|
313
|
+
? (isInstall ? dependence_1.DependenceStatus.installed : dependence_1.DependenceStatus.removed)
|
|
314
|
+
: (isInstall ? dependence_1.DependenceStatus.installFailed : dependence_1.DependenceStatus.removeFailed);
|
|
304
315
|
this.sockService.sendMessage({
|
|
305
316
|
type: socketMessageType,
|
|
306
317
|
message,
|
|
307
318
|
references: depIds,
|
|
319
|
+
status: exitStatus,
|
|
308
320
|
});
|
|
309
321
|
this.updateLog(depIds, message);
|
|
310
|
-
let status;
|
|
311
|
-
if (isSucceed) {
|
|
312
|
-
status = isInstall
|
|
313
|
-
? dependence_1.DependenceStatus.installed
|
|
314
|
-
: dependence_1.DependenceStatus.removed;
|
|
315
|
-
}
|
|
316
|
-
else {
|
|
317
|
-
status = isInstall
|
|
318
|
-
? dependence_1.DependenceStatus.installFailed
|
|
319
|
-
: dependence_1.DependenceStatus.removeFailed;
|
|
320
|
-
}
|
|
321
322
|
const docs = await dependence_1.DependenceModel.findAll({ where: { id: depIds } });
|
|
322
323
|
const _docIds = docs
|
|
323
324
|
.filter((x) => x.status !== dependence_1.DependenceStatus.cancelled)
|
|
324
325
|
.map((x) => x.id);
|
|
325
326
|
if (_docIds.length > 0) {
|
|
326
|
-
await dependence_1.DependenceModel.update({ status }, { where: { id: _docIds } });
|
|
327
|
+
await dependence_1.DependenceModel.update({ status: exitStatus }, { where: { id: _docIds } });
|
|
327
328
|
}
|
|
328
329
|
// 如果删除依赖成功或者强制删除
|
|
329
330
|
if ((isSucceed || force) && !isInstall) {
|
|
@@ -75,7 +75,7 @@ let GrpcServerService = class GrpcServerService {
|
|
|
75
75
|
try {
|
|
76
76
|
const address = this.formatGrpcAddress(host, grpcPort);
|
|
77
77
|
await bindAsync(address, credentials);
|
|
78
|
-
logger_1.default.debug(
|
|
78
|
+
logger_1.default.debug(`[boot] gRPC service started successfully on ${address}`);
|
|
79
79
|
metrics_1.metricsService.record('grpc_service_start', 1, {
|
|
80
80
|
port: grpcPort.toString(),
|
|
81
81
|
host
|
|
@@ -27,7 +27,7 @@ let HttpServerService = class HttpServerService {
|
|
|
27
27
|
for (const host of hostsToTry) {
|
|
28
28
|
try {
|
|
29
29
|
const server = await this.tryListen(expressApp, port, host);
|
|
30
|
-
logger_1.default.debug(
|
|
30
|
+
logger_1.default.debug(`[boot] HTTP service started successfully on ${host}:${port}`);
|
|
31
31
|
metrics_1.metricsService.record('http_service_start', 1, {
|
|
32
32
|
port: port.toString(),
|
|
33
33
|
host
|
|
@@ -55,6 +55,7 @@ let NotificationService = class NotificationService {
|
|
|
55
55
|
['chronocat', this.chronocat],
|
|
56
56
|
['ntfy', this.ntfy],
|
|
57
57
|
['wxPusherBot', this.wxPusherBot],
|
|
58
|
+
['wxPusherSpt', this.wxPusherSpt],
|
|
58
59
|
['openiLink', this.openiLink],
|
|
59
60
|
]);
|
|
60
61
|
this.title = '';
|
|
@@ -306,7 +307,7 @@ let NotificationService = class NotificationService {
|
|
|
306
307
|
{
|
|
307
308
|
title: `${this.title}`,
|
|
308
309
|
thumb_media_id,
|
|
309
|
-
author:
|
|
310
|
+
author: (0, i18n_1.t)('智能助手'),
|
|
310
311
|
content_source_url: ``,
|
|
311
312
|
content: `${this.content.replace(/\n/g, '<br/>')}`,
|
|
312
313
|
digest: `${this.content}`,
|
|
@@ -322,7 +323,7 @@ let NotificationService = class NotificationService {
|
|
|
322
323
|
title: `${this.title}`,
|
|
323
324
|
description: `${this.content}`,
|
|
324
325
|
url: 'https://github.com/whyour/qinglong',
|
|
325
|
-
btntxt: '更多',
|
|
326
|
+
btntxt: (0, i18n_1.t)('更多'),
|
|
326
327
|
},
|
|
327
328
|
};
|
|
328
329
|
break;
|
|
@@ -361,7 +362,7 @@ let NotificationService = class NotificationService {
|
|
|
361
362
|
roomName: `${aibotkName}`,
|
|
362
363
|
message: {
|
|
363
364
|
type: 1,
|
|
364
|
-
content:
|
|
365
|
+
content: `【${(0, i18n_1.t)('青龙快讯')}】\n\n${this.title}\n${this.content}`,
|
|
365
366
|
},
|
|
366
367
|
};
|
|
367
368
|
break;
|
|
@@ -372,7 +373,7 @@ let NotificationService = class NotificationService {
|
|
|
372
373
|
name: `${aibotkName}`,
|
|
373
374
|
message: {
|
|
374
375
|
type: 1,
|
|
375
|
-
content:
|
|
376
|
+
content: `【${(0, i18n_1.t)('青龙快讯')}】\n\n${this.title}\n${this.content}`,
|
|
376
377
|
},
|
|
377
378
|
};
|
|
378
379
|
break;
|
|
@@ -507,7 +508,7 @@ let NotificationService = class NotificationService {
|
|
|
507
508
|
},
|
|
508
509
|
});
|
|
509
510
|
const info = await transporter.sendMail({
|
|
510
|
-
from: `"青龙快讯" <${emailUser}>`,
|
|
511
|
+
from: `"${(0, i18n_1.t)('青龙快讯')}" <${emailUser}>`,
|
|
511
512
|
to: recipients,
|
|
512
513
|
subject: `${this.title}`,
|
|
513
514
|
html: `${this.content.replace(/\n/g, '<br/>')}`,
|
|
@@ -620,6 +621,47 @@ let NotificationService = class NotificationService {
|
|
|
620
621
|
throw new Error(error.response ? error.response.body : error);
|
|
621
622
|
}
|
|
622
623
|
}
|
|
624
|
+
async wxPusherSpt() {
|
|
625
|
+
const { wxPusherSptList } = this.params;
|
|
626
|
+
// 处理 SPT,将逗号分隔的字符串转为数组
|
|
627
|
+
const spts = wxPusherSptList
|
|
628
|
+
? wxPusherSptList
|
|
629
|
+
.split(',')
|
|
630
|
+
.map((spt) => spt.trim())
|
|
631
|
+
.filter((spt) => spt)
|
|
632
|
+
: [];
|
|
633
|
+
if (!spts.length) {
|
|
634
|
+
throw new Error((0, i18n_1.t)('wxPusher SPT 不能为空'));
|
|
635
|
+
}
|
|
636
|
+
if (spts.length > 10) {
|
|
637
|
+
throw new Error((0, i18n_1.t)('wxPusher SPT 最多支持 10 个'));
|
|
638
|
+
}
|
|
639
|
+
const url = `https://wxpusher.zjiecode.com/api/send/message/simple-push`;
|
|
640
|
+
const json = {
|
|
641
|
+
content: `<h1>${this.title}</h1><br/><div style='white-space: pre-wrap;'>${this.content}</div>`,
|
|
642
|
+
summary: this.title,
|
|
643
|
+
contentType: 2,
|
|
644
|
+
};
|
|
645
|
+
// 单个 SPT 用 spt,多个用 sptList
|
|
646
|
+
if (spts.length === 1) {
|
|
647
|
+
json.spt = spts[0];
|
|
648
|
+
}
|
|
649
|
+
else {
|
|
650
|
+
json.sptList = spts;
|
|
651
|
+
}
|
|
652
|
+
try {
|
|
653
|
+
const res = await http_1.httpClient.post(url, Object.assign(Object.assign({}, this.gotOption), { json }));
|
|
654
|
+
if (res.code === 1000) {
|
|
655
|
+
return true;
|
|
656
|
+
}
|
|
657
|
+
else {
|
|
658
|
+
throw new Error(JSON.stringify(res));
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
catch (error) {
|
|
662
|
+
throw new Error(error.response ? error.response.body : error);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
623
665
|
async chronocat() {
|
|
624
666
|
var _a, _b;
|
|
625
667
|
const { chronocatURL, chronocatQQ, chronocatToken } = this.params;
|
|
@@ -126,12 +126,12 @@ let SubscriptionService = class SubscriptionService {
|
|
|
126
126
|
status: subscription_1.SubscriptionStatus.running,
|
|
127
127
|
log_path: logPath,
|
|
128
128
|
}, { where: { id: doc.id } });
|
|
129
|
-
const absolutePath = await (0, util_1.handleLogPath)(logPath,
|
|
129
|
+
const absolutePath = await (0, util_1.handleLogPath)(logPath, (0, i18n_1.tf)('## 开始执行... %s\n', startTime.format('YYYY-MM-DD HH:mm:ss')));
|
|
130
130
|
// 执行sub_before
|
|
131
131
|
let beforeStr = '';
|
|
132
132
|
try {
|
|
133
133
|
if (doc.sub_before) {
|
|
134
|
-
await logStreamManager_1.logStreamManager.write(absolutePath, `\n## 执行before
|
|
134
|
+
await logStreamManager_1.logStreamManager.write(absolutePath, `\n## ${(0, i18n_1.t)('执行before命令...')}\n\n`);
|
|
135
135
|
beforeStr = await (0, util_1.promiseExec)(doc.sub_before);
|
|
136
136
|
}
|
|
137
137
|
}
|
|
@@ -155,7 +155,7 @@ let SubscriptionService = class SubscriptionService {
|
|
|
155
155
|
let afterStr = '';
|
|
156
156
|
try {
|
|
157
157
|
if (sub.sub_after) {
|
|
158
|
-
await logStreamManager_1.logStreamManager.write(absolutePath, `\n\n## 执行after
|
|
158
|
+
await logStreamManager_1.logStreamManager.write(absolutePath, `\n\n## ${(0, i18n_1.t)('执行after命令...')}\n\n`);
|
|
159
159
|
afterStr = await (0, util_1.promiseExec)(sub.sub_after);
|
|
160
160
|
}
|
|
161
161
|
}
|
|
@@ -166,7 +166,9 @@ let SubscriptionService = class SubscriptionService {
|
|
|
166
166
|
if (afterStr) {
|
|
167
167
|
await logStreamManager_1.logStreamManager.write(absolutePath, `${afterStr}\n`);
|
|
168
168
|
}
|
|
169
|
-
await logStreamManager_1.logStreamManager.write(absolutePath,
|
|
169
|
+
await logStreamManager_1.logStreamManager.write(absolutePath, '\n' +
|
|
170
|
+
(0, i18n_1.tf)('## 执行结束... %s 耗时 %s 秒', endTime.format('YYYY-MM-DD HH:mm:ss'), String(diff)) +
|
|
171
|
+
const_1.LOG_END_SYMBOL);
|
|
170
172
|
// Close the stream after task completion
|
|
171
173
|
await logStreamManager_1.logStreamManager.closeStream(absolutePath);
|
|
172
174
|
await subscription_1.SubscriptionModel.update({ status: subscription_1.SubscriptionStatus.idle, pid: undefined }, { where: { id: sub.id } });
|
|
@@ -72,7 +72,7 @@ let SystemService = class SystemService {
|
|
|
72
72
|
}
|
|
73
73
|
async updateNotificationMode(notificationInfo) {
|
|
74
74
|
const code = Math.random().toString().slice(-6);
|
|
75
|
-
const isSuccess = await this.notificationService.testNotify(notificationInfo, '青龙',
|
|
75
|
+
const isSuccess = await this.notificationService.testNotify(notificationInfo, (0, i18n_1.t)('青龙'), (0, i18n_1.t)('【蛟龙】测试通知 https://t.me/jiao_long'));
|
|
76
76
|
if (isSuccess) {
|
|
77
77
|
const result = await this.updateAuthDb({
|
|
78
78
|
type: system_1.AuthDataType.notification,
|
|
@@ -90,7 +90,7 @@ let SystemService = class SystemService {
|
|
|
90
90
|
const result = await this.updateAuthDb(Object.assign(Object.assign({}, oDoc), { info: Object.assign(Object.assign({}, oDoc.info), info) }));
|
|
91
91
|
const cron = {
|
|
92
92
|
id: result.id,
|
|
93
|
-
name: '删除日志',
|
|
93
|
+
name: (0, i18n_1.t)('删除日志'),
|
|
94
94
|
command: `ql rmlog ${info.logRemoveFrequency}`,
|
|
95
95
|
runOrigin: 'system',
|
|
96
96
|
};
|
|
@@ -149,6 +149,7 @@ let SystemService = class SystemService {
|
|
|
149
149
|
this.sockService.sendMessage({
|
|
150
150
|
type: 'updateNodeMirror',
|
|
151
151
|
message: 'update node mirror end',
|
|
152
|
+
status: 'completed',
|
|
152
153
|
});
|
|
153
154
|
},
|
|
154
155
|
onError: async (message) => {
|
|
@@ -189,6 +190,7 @@ let SystemService = class SystemService {
|
|
|
189
190
|
this.sockService.sendMessage({
|
|
190
191
|
type: 'updateLinuxMirror',
|
|
191
192
|
message: 'update linux mirror end',
|
|
193
|
+
status: 'completed',
|
|
192
194
|
});
|
|
193
195
|
onEnd === null || onEnd === void 0 ? void 0 : onEnd();
|
|
194
196
|
if (!hasError) {
|
|
@@ -277,6 +279,14 @@ let SystemService = class SystemService {
|
|
|
277
279
|
this.sockService.sendMessage({
|
|
278
280
|
type: 'updateSystemVersion',
|
|
279
281
|
message: JSON.stringify(err),
|
|
282
|
+
status: 'failed',
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
cp.on('exit', (code) => {
|
|
286
|
+
this.sockService.sendMessage({
|
|
287
|
+
type: 'updateSystemVersion',
|
|
288
|
+
message: '',
|
|
289
|
+
status: code === 0 ? 'success' : 'failed',
|
|
280
290
|
});
|
|
281
291
|
});
|
|
282
292
|
return { code: 200 };
|