@whyour/qinglong 2.19.2-2 → 2.20.0-2
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 +1 -2
- package/README-en.md +4 -2
- package/README.md +4 -2
- package/back/protos/api.proto +17 -0
- package/docker/310.Dockerfile +23 -6
- package/docker/Dockerfile +22 -6
- package/docker/docker-entrypoint.sh +27 -14
- package/package.json +8 -9
- package/sample/notify.js +18 -2
- package/sample/notify.py +15 -0
- package/sample/ql_sample.js +28 -0
- package/shell/api.sh +8 -48
- package/shell/check.sh +5 -22
- package/shell/preload/client.js +6 -1
- package/shell/pub.sh +4 -4
- package/shell/share.sh +32 -55
- package/shell/start.sh +2 -3
- package/shell/task.sh +19 -10
- package/shell/update.sh +1 -0
- package/static/build/api/dependence.js +7 -1
- package/static/build/api/env.js +30 -4
- package/static/build/api/script.js +48 -8
- package/static/build/api/subscription.js +3 -3
- package/static/build/api/system.js +19 -26
- package/static/build/api/user.js +2 -1
- package/static/build/app.js +96 -18
- package/static/build/config/index.js +2 -2
- package/static/build/config/util.js +24 -1
- package/static/build/data/cron.js +4 -0
- package/static/build/data/env.js +3 -1
- package/static/build/data/notify.js +1 -0
- package/static/build/loaders/db.js +29 -35
- package/static/build/loaders/deps.js +22 -5
- package/static/build/loaders/express.js +19 -10
- package/static/build/loaders/initData.js +25 -1
- package/static/build/loaders/initTask.js +6 -0
- package/static/build/loaders/sock.js +10 -12
- package/static/build/protos/api.js +336 -1
- package/static/build/schedule/addCron.js +2 -2
- package/static/build/schedule/api.js +100 -1
- package/static/build/schedule/delCron.js +1 -1
- package/static/build/schedule/health.js +2 -3
- package/static/build/services/cron.js +54 -20
- package/static/build/services/dependence.js +6 -5
- package/static/build/services/env.js +9 -2
- package/static/build/services/notify.js +17 -5
- package/static/build/services/schedule.js +4 -4
- package/static/build/services/sshKey.js +24 -4
- package/static/build/services/subscription.js +11 -8
- package/static/build/services/system.js +15 -0
- package/static/build/services/user.js +83 -4
- package/static/build/shared/auth.js +40 -0
- package/static/build/shared/logStreamManager.js +104 -0
- package/static/build/shared/runCron.js +23 -0
- package/static/build/validation/schedule.js +39 -2
- package/static/dist/1147.856bb861.async.js +1 -0
- package/static/dist/1379.f91563a1.async.js +1 -0
- package/static/dist/{2208.3bc521b1.async.js → 2208.7bf7e296.async.js} +1 -1
- package/static/dist/3191.da7f3e07.async.js +1 -0
- package/static/dist/5691.931f59c5.async.js +1 -0
- package/static/dist/7571.4f6240b1.async.js +1 -0
- package/static/dist/{8826.3ab4ad84.async.js → 8826.5f289c4d.async.js} +1 -1
- package/static/dist/index.html +2 -2
- package/static/dist/preload_helper.0fb920eb.js +1 -0
- package/static/dist/{src__pages__crontab__detail.ee431270.async.js → src__pages__crontab__detail.b07f0c0a.async.js} +1 -1
- package/static/dist/src__pages__crontab__index.6b90d8c5.async.js +1 -0
- package/static/dist/{src__pages__crontab__logModal.57501983.async.js → src__pages__crontab__logModal.5e6a4bf2.async.js} +1 -1
- package/static/dist/src__pages__crontab__modal.2d3d4953.async.js +1 -0
- package/static/dist/src__pages__dependence__modal.86604072.async.js +1 -0
- package/static/dist/{src__pages__env__editNameModal.665393cd.async.js → src__pages__env__editNameModal.79b7cf83.async.js} +1 -1
- package/static/dist/src__pages__env__index.a0a2fece.async.js +1 -0
- package/static/dist/{src__pages__env__modal.168498f9.async.js → src__pages__env__modal.b84c1173.async.js} +1 -1
- package/static/dist/{src__pages__error__index.d9beeda3.async.js → src__pages__error__index.01fac00e.async.js} +1 -1
- package/static/dist/{src__pages__initialization__index.2403c031.async.js → src__pages__initialization__index.2e49cf43.async.js} +1 -1
- package/static/dist/src__pages__script__editModal.cbf4ec0e.async.js +1 -0
- package/static/dist/{src__pages__script__editNameModal.e36cd111.async.js → src__pages__script__editNameModal.05441c89.async.js} +1 -1
- package/static/dist/src__pages__script__index.d6e9cb23.async.js +1 -0
- package/static/dist/{src__pages__script__renameModal.f9756f26.async.js → src__pages__script__renameModal.3bb00014.async.js} +1 -1
- package/static/dist/src__pages__script__saveModal.8417503a.async.js +1 -0
- package/static/dist/{src__pages__script__setting.8c2727b4.async.js → src__pages__script__setting.5a2a2a2c.async.js} +1 -1
- package/static/dist/{src__pages__setting__appModal.5a39121e.async.js → src__pages__setting__appModal.7f763fa7.async.js} +1 -1
- package/static/dist/src__pages__setting__dependence.e64c4554.async.js +1 -0
- package/static/dist/src__pages__setting__index.3a220288.async.js +1 -0
- package/static/dist/src__pages__setting__notification.49003b2f.async.js +1 -0
- package/static/dist/src__pages__setting__other.0d931d6f.async.js +1 -0
- package/static/dist/src__pages__setting__security.a916e056.async.js +1 -0
- package/static/dist/{src__pages__setting__systemLog.fc5bdc78.async.js → src__pages__setting__systemLog.cbb0a3bb.async.js} +1 -1
- package/static/dist/src__pages__subscription__modal.ade477c1.async.js +1 -0
- package/static/dist/umi.e7cba995.js +1 -0
- package/version.yaml +46 -9
- package/docker/front.conf +0 -61
- package/docker/nginx.conf +0 -45
- package/static/dist/2995.2eb218b3.async.js +0 -1
- package/static/dist/3191.cc1e31cd.async.js +0 -1
- package/static/dist/4046.7fbcfa02.async.js +0 -1
- package/static/dist/5713.8519f547.async.js +0 -1
- package/static/dist/8851.503b1e64.async.js +0 -1
- package/static/dist/preload_helper.9c086410.js +0 -1
- package/static/dist/src__pages__crontab__index.af4cb04a.async.js +0 -1
- package/static/dist/src__pages__crontab__modal.21258e08.async.js +0 -1
- package/static/dist/src__pages__dependence__modal.6639424a.async.js +0 -1
- package/static/dist/src__pages__env__index.70340ba7.async.js +0 -1
- package/static/dist/src__pages__script__editModal.f1741417.async.js +0 -1
- package/static/dist/src__pages__script__index.82b42e11.async.js +0 -1
- package/static/dist/src__pages__script__saveModal.e885e133.async.js +0 -1
- package/static/dist/src__pages__setting__dependence.a46e873d.async.js +0 -1
- package/static/dist/src__pages__setting__index.9be4775c.async.js +0 -1
- package/static/dist/src__pages__setting__notification.299f6b96.async.js +0 -1
- package/static/dist/src__pages__setting__other.60924a56.async.js +0 -1
- package/static/dist/src__pages__setting__security.e7371daa.async.js +0 -1
- package/static/dist/src__pages__subscription__modal.a7fd6a3c.async.js +0 -1
- package/static/dist/umi.5b8ae363.js +0 -1
package/static/build/app.js
CHANGED
|
@@ -41,6 +41,13 @@ class Application {
|
|
|
41
41
|
this.isShuttingDown = false;
|
|
42
42
|
this.workerMetadataMap = new Map();
|
|
43
43
|
this.app = (0, express_1.default)();
|
|
44
|
+
// 创建一个全局中间件,删除查询参数中的t
|
|
45
|
+
this.app.use((req, res, next) => {
|
|
46
|
+
if (req.query.t) {
|
|
47
|
+
delete req.query.t;
|
|
48
|
+
}
|
|
49
|
+
next();
|
|
50
|
+
});
|
|
44
51
|
}
|
|
45
52
|
async start() {
|
|
46
53
|
try {
|
|
@@ -60,21 +67,74 @@ class Application {
|
|
|
60
67
|
}
|
|
61
68
|
}
|
|
62
69
|
startMasterProcess() {
|
|
63
|
-
|
|
64
|
-
this.forkWorker('grpc');
|
|
70
|
+
// Fork gRPC worker first and wait for it to be ready
|
|
71
|
+
const grpcWorker = this.forkWorker('grpc');
|
|
72
|
+
// Wait for gRPC worker to signal it's ready before starting HTTP worker
|
|
73
|
+
this.waitForWorkerReady(grpcWorker, 30000)
|
|
74
|
+
.then(() => {
|
|
75
|
+
logger_1.default.info('✌️ gRPC worker is ready, starting HTTP worker');
|
|
76
|
+
this.httpWorker = this.forkWorker('http');
|
|
77
|
+
})
|
|
78
|
+
.catch((error) => {
|
|
79
|
+
logger_1.default.error('✌️ Failed to wait for gRPC worker:', error);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
});
|
|
65
82
|
cluster_1.default.on('exit', (worker, code, signal) => {
|
|
66
83
|
const metadata = this.workerMetadataMap.get(worker.id);
|
|
67
84
|
if (metadata) {
|
|
68
85
|
if (!this.isShuttingDown) {
|
|
69
|
-
logger_1.default.error(
|
|
70
|
-
|
|
71
|
-
|
|
86
|
+
logger_1.default.error(`✌️ ${metadata.serviceType} worker ${worker.process.pid} died (${signal || code}). Restarting...`);
|
|
87
|
+
// If gRPC worker died, restart it and wait for it to be ready
|
|
88
|
+
if (metadata.serviceType === 'grpc') {
|
|
89
|
+
const newGrpcWorker = this.forkWorker('grpc');
|
|
90
|
+
this.waitForWorkerReady(newGrpcWorker, 30000)
|
|
91
|
+
.then(() => {
|
|
92
|
+
logger_1.default.info('✌️ gRPC worker restarted and ready');
|
|
93
|
+
// Re-register cron jobs by notifying the HTTP worker
|
|
94
|
+
if (this.httpWorker) {
|
|
95
|
+
try {
|
|
96
|
+
this.httpWorker.send('reregister-crons');
|
|
97
|
+
logger_1.default.info('✌️ Sent reregister-crons message to HTTP worker');
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
logger_1.default.error('✌️ Failed to send reregister-crons message:', error);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
.catch((error) => {
|
|
105
|
+
logger_1.default.error('✌️ Failed to restart gRPC worker:', error);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// For HTTP worker, just restart it
|
|
111
|
+
const newWorker = this.forkWorker(metadata.serviceType);
|
|
112
|
+
this.httpWorker = newWorker;
|
|
113
|
+
logger_1.default.info(`✌️ Restarted ${metadata.serviceType} worker (PID: ${newWorker.process.pid})`);
|
|
114
|
+
}
|
|
72
115
|
}
|
|
73
116
|
this.workerMetadataMap.delete(worker.id);
|
|
74
117
|
}
|
|
75
118
|
});
|
|
76
119
|
this.setupMasterShutdown();
|
|
77
120
|
}
|
|
121
|
+
waitForWorkerReady(worker, timeoutMs) {
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
const messageHandler = (msg) => {
|
|
124
|
+
if (msg === 'ready') {
|
|
125
|
+
worker.removeListener('message', messageHandler);
|
|
126
|
+
clearTimeout(timeoutId);
|
|
127
|
+
resolve();
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
worker.on('message', messageHandler);
|
|
131
|
+
// Timeout after specified milliseconds
|
|
132
|
+
const timeoutId = setTimeout(() => {
|
|
133
|
+
worker.removeListener('message', messageHandler);
|
|
134
|
+
reject(new Error(`Worker failed to start within ${timeoutMs / 1000} seconds`));
|
|
135
|
+
}, timeoutMs);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
78
138
|
forkWorker(serviceType) {
|
|
79
139
|
const worker = cluster_1.default.fork({ SERVICE_TYPE: serviceType });
|
|
80
140
|
this.workerMetadataMap.set(worker.id, {
|
|
@@ -86,10 +146,13 @@ class Application {
|
|
|
86
146
|
return worker;
|
|
87
147
|
}
|
|
88
148
|
async initializeDatabase() {
|
|
89
|
-
await require('./loaders/db')
|
|
149
|
+
const dbLoader = await Promise.resolve().then(() => __importStar(require('./loaders/db')));
|
|
150
|
+
await dbLoader.default();
|
|
90
151
|
}
|
|
91
152
|
setupMiddlewares() {
|
|
92
|
-
this.app.use((0, helmet_1.default)(
|
|
153
|
+
this.app.use((0, helmet_1.default)({
|
|
154
|
+
contentSecurityPolicy: false,
|
|
155
|
+
}));
|
|
93
156
|
this.app.use((0, cors_1.default)(config_1.default.cors));
|
|
94
157
|
this.app.use((0, compression_1.default)());
|
|
95
158
|
this.app.use(monitoring_1.monitoringMiddleware);
|
|
@@ -105,14 +168,14 @@ class Application {
|
|
|
105
168
|
if (worker) {
|
|
106
169
|
const exitPromise = new Promise((resolve) => {
|
|
107
170
|
worker.once('exit', () => {
|
|
108
|
-
logger_1.default.info(
|
|
171
|
+
logger_1.default.info(`✌️ Worker ${worker.process.pid} exited`);
|
|
109
172
|
resolve();
|
|
110
173
|
});
|
|
111
174
|
try {
|
|
112
175
|
worker.send('shutdown');
|
|
113
176
|
}
|
|
114
177
|
catch (error) {
|
|
115
|
-
logger_1.default.warn(
|
|
178
|
+
logger_1.default.warn(`✌️ Failed to send shutdown to worker ${worker.process.pid}:`, error);
|
|
116
179
|
}
|
|
117
180
|
});
|
|
118
181
|
workerPromises.push(exitPromise);
|
|
@@ -123,7 +186,7 @@ class Application {
|
|
|
123
186
|
Promise.all(workerPromises),
|
|
124
187
|
new Promise((resolve) => {
|
|
125
188
|
setTimeout(() => {
|
|
126
|
-
logger_1.default.warn('Worker shutdown timeout reached');
|
|
189
|
+
logger_1.default.warn('✌️ Worker shutdown timeout reached');
|
|
127
190
|
resolve();
|
|
128
191
|
}, 10000);
|
|
129
192
|
}),
|
|
@@ -131,7 +194,7 @@ class Application {
|
|
|
131
194
|
process.exit(0);
|
|
132
195
|
}
|
|
133
196
|
catch (error) {
|
|
134
|
-
logger_1.default.error('Error during worker shutdown:', error);
|
|
197
|
+
logger_1.default.error('✌️ Error during worker shutdown:', error);
|
|
135
198
|
process.exit(1);
|
|
136
199
|
}
|
|
137
200
|
};
|
|
@@ -142,7 +205,7 @@ class Application {
|
|
|
142
205
|
var _a;
|
|
143
206
|
const serviceType = process.env.SERVICE_TYPE;
|
|
144
207
|
if (!serviceType || !['http', 'grpc'].includes(serviceType)) {
|
|
145
|
-
logger_1.default.error('Invalid SERVICE_TYPE:', serviceType);
|
|
208
|
+
logger_1.default.error('✌️ Invalid SERVICE_TYPE:', serviceType);
|
|
146
209
|
process.exit(1);
|
|
147
210
|
}
|
|
148
211
|
logger_1.default.info(`✌️ ${serviceType} worker started (PID: ${process.pid})`);
|
|
@@ -156,7 +219,7 @@ class Application {
|
|
|
156
219
|
(_a = process.send) === null || _a === void 0 ? void 0 : _a.call(process, 'ready');
|
|
157
220
|
}
|
|
158
221
|
catch (error) {
|
|
159
|
-
logger_1.default.error(
|
|
222
|
+
logger_1.default.error(`✌️ ${serviceType} worker failed:`, error);
|
|
160
223
|
process.exit(1);
|
|
161
224
|
}
|
|
162
225
|
}
|
|
@@ -164,9 +227,11 @@ class Application {
|
|
|
164
227
|
this.setupMiddlewares();
|
|
165
228
|
const { HttpServerService } = await Promise.resolve().then(() => __importStar(require('./services/http')));
|
|
166
229
|
this.httpServerService = typedi_1.Container.get(HttpServerService);
|
|
167
|
-
await require('./loaders/app')
|
|
230
|
+
const appLoader = await Promise.resolve().then(() => __importStar(require('./loaders/app')));
|
|
231
|
+
await appLoader.default({ app: this.app });
|
|
168
232
|
const server = await this.httpServerService.initialize(this.app, config_1.default.port);
|
|
169
|
-
await require('./loaders/server')
|
|
233
|
+
const serverLoader = await Promise.resolve().then(() => __importStar(require('./loaders/server')));
|
|
234
|
+
await serverLoader.default({ server });
|
|
170
235
|
this.setupWorkerShutdown('http');
|
|
171
236
|
}
|
|
172
237
|
async startGrpcService() {
|
|
@@ -176,10 +241,23 @@ class Application {
|
|
|
176
241
|
this.setupWorkerShutdown('grpc');
|
|
177
242
|
}
|
|
178
243
|
setupWorkerShutdown(serviceType) {
|
|
179
|
-
process.on('message', (msg) => {
|
|
244
|
+
process.on('message', async (msg) => {
|
|
180
245
|
if (msg === 'shutdown') {
|
|
181
246
|
this.gracefulShutdown(serviceType);
|
|
182
247
|
}
|
|
248
|
+
else if (msg === 'reregister-crons' && serviceType === 'http') {
|
|
249
|
+
// Re-register cron jobs when gRPC worker restarts
|
|
250
|
+
try {
|
|
251
|
+
logger_1.default.info('✌️ Received reregister-crons message, re-registering cron jobs...');
|
|
252
|
+
const CronService = (await Promise.resolve().then(() => __importStar(require('./services/cron')))).default;
|
|
253
|
+
const cronService = typedi_1.Container.get(CronService);
|
|
254
|
+
await cronService.autosave_crontab();
|
|
255
|
+
logger_1.default.info('✌️ Cron jobs re-registered successfully');
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
logger_1.default.error('✌️ Failed to re-register cron jobs:', error);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
183
261
|
});
|
|
184
262
|
const shutdown = () => this.gracefulShutdown(serviceType);
|
|
185
263
|
process.on('SIGTERM', shutdown);
|
|
@@ -200,14 +278,14 @@ class Application {
|
|
|
200
278
|
process.exit(0);
|
|
201
279
|
}
|
|
202
280
|
catch (error) {
|
|
203
|
-
logger_1.default.error(
|
|
281
|
+
logger_1.default.error(`✌️ [${serviceType}] Error during shutdown:`, error);
|
|
204
282
|
process.exit(1);
|
|
205
283
|
}
|
|
206
284
|
}
|
|
207
285
|
}
|
|
208
286
|
const app = new Application();
|
|
209
287
|
app.start().catch((error) => {
|
|
210
|
-
logger_1.default.error('Application failed to start:', error);
|
|
288
|
+
logger_1.default.error('🙅♀️ Application failed to start:', error);
|
|
211
289
|
process.exit(1);
|
|
212
290
|
});
|
|
213
291
|
//# sourceMappingURL=app.js.map
|
|
@@ -9,7 +9,7 @@ dotenv_1.default.config({
|
|
|
9
9
|
path: path_1.default.join(__dirname, '../../.env'),
|
|
10
10
|
});
|
|
11
11
|
const config = {
|
|
12
|
-
port: parseInt(process.env.BACK_PORT || '
|
|
12
|
+
port: parseInt(process.env.BACK_PORT || '5700', 10),
|
|
13
13
|
grpcPort: parseInt(process.env.GRPC_PORT || '5500', 10),
|
|
14
14
|
nodeEnv: process.env.NODE_ENV || 'development',
|
|
15
15
|
isDevelopment: process.env.NODE_ENV === 'development',
|
|
@@ -136,5 +136,5 @@ exports.default = Object.assign(Object.assign({}, config), { jwt: config.jwt, ro
|
|
|
136
136
|
sqliteFile,
|
|
137
137
|
sshdPath,
|
|
138
138
|
systemLogPath,
|
|
139
|
-
dependenceCachePath });
|
|
139
|
+
dependenceCachePath, maxTokensPerPlatform: 10 });
|
|
140
140
|
//# sourceMappingURL=index.js.map
|
|
@@ -29,7 +29,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
29
29
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
30
30
|
};
|
|
31
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
-
exports.updateLinuxMirrorFile = exports.detectOS = exports.isDemoEnv = exports.getUninstallCommand = exports.getInstallCommand = exports.getGetCommand = exports.setSystemTimezone = exports.rmPath = exports.safeJSONParse = exports.getUniqPath = exports.parseContentVersion = exports.parseVersion = exports.getPid = exports.killTask = exports.psTree = exports.parseBody = exports.parseHeaders = exports.promiseExecSuccess = exports.promiseExec = exports.readDir = exports.readDirs = exports.dirSort = exports.concurrentRun = exports.handleLogPath = exports.createFile = exports.fileExist = exports.getPlatform = exports.getToken = exports.getLastModifyFilePath = exports.removeAnsi = exports.getFileContentByName = void 0;
|
|
32
|
+
exports.updateLinuxMirrorFile = exports.detectOS = exports.isDemoEnv = exports.getUninstallCommand = exports.getInstallCommand = exports.getGetCommand = exports.setSystemTimezone = exports.rmPath = exports.safeJSONParse = exports.getUniqPath = exports.parseContentVersion = exports.parseVersion = exports.killAllTasks = exports.getAllPids = exports.getPid = exports.killTask = exports.psTree = exports.parseBody = exports.parseHeaders = exports.promiseExecSuccess = exports.promiseExec = exports.readDir = exports.readDirs = exports.dirSort = exports.concurrentRun = exports.handleLogPath = exports.createFile = exports.fileExist = exports.getPlatform = exports.getToken = exports.getLastModifyFilePath = exports.removeAnsi = exports.getFileContentByName = void 0;
|
|
33
33
|
const fs = __importStar(require("fs/promises"));
|
|
34
34
|
const path = __importStar(require("path"));
|
|
35
35
|
const child_process_1 = require("child_process");
|
|
@@ -395,6 +395,29 @@ async function getPid(cmd) {
|
|
|
395
395
|
return pid ? Number(pid) : undefined;
|
|
396
396
|
}
|
|
397
397
|
exports.getPid = getPid;
|
|
398
|
+
async function getAllPids(cmd) {
|
|
399
|
+
const taskCommand = `ps -eo pid,command | grep "${cmd}" | grep -v grep | awk '{print $1}'`;
|
|
400
|
+
const pidsStr = await promiseExec(taskCommand);
|
|
401
|
+
if (!pidsStr)
|
|
402
|
+
return [];
|
|
403
|
+
return pidsStr
|
|
404
|
+
.split('\n')
|
|
405
|
+
.map((p) => Number(p.trim()))
|
|
406
|
+
.filter((p) => !isNaN(p) && p > 0);
|
|
407
|
+
}
|
|
408
|
+
exports.getAllPids = getAllPids;
|
|
409
|
+
async function killAllTasks(cmd) {
|
|
410
|
+
const pids = await getAllPids(cmd);
|
|
411
|
+
for (const pid of pids) {
|
|
412
|
+
try {
|
|
413
|
+
await killTask(pid);
|
|
414
|
+
}
|
|
415
|
+
catch (error) {
|
|
416
|
+
// Ignore errors if process already terminated
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
exports.killAllTasks = killAllTasks;
|
|
398
421
|
async function parseVersion(path) {
|
|
399
422
|
return (0, js_yaml_1.load)(await fs.readFile(path, 'utf8'));
|
|
400
423
|
}
|
|
@@ -27,6 +27,8 @@ class Crontab {
|
|
|
27
27
|
this.extra_schedules = options.extra_schedules;
|
|
28
28
|
this.task_before = options.task_before;
|
|
29
29
|
this.task_after = options.task_after;
|
|
30
|
+
this.log_name = options.log_name;
|
|
31
|
+
this.allow_multiple_instances = options.allow_multiple_instances || 0;
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
exports.Crontab = Crontab;
|
|
@@ -65,5 +67,7 @@ exports.CrontabModel = _1.sequelize.define('Crontab', {
|
|
|
65
67
|
extra_schedules: sequelize_1.DataTypes.JSON,
|
|
66
68
|
task_before: sequelize_1.DataTypes.STRING,
|
|
67
69
|
task_after: sequelize_1.DataTypes.STRING,
|
|
70
|
+
log_name: sequelize_1.DataTypes.STRING,
|
|
71
|
+
allow_multiple_instances: sequelize_1.DataTypes.NUMBER,
|
|
68
72
|
});
|
|
69
73
|
//# sourceMappingURL=cron.js.map
|
package/static/build/data/env.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.EnvModel = exports.minPosition = exports.stepPosition = exports.initPosition = exports.maxPosition = exports.EnvStatus = exports.Env = void 0;
|
|
4
|
-
const _1 = require(".");
|
|
5
4
|
const sequelize_1 = require("sequelize");
|
|
5
|
+
const _1 = require(".");
|
|
6
6
|
class Env {
|
|
7
7
|
constructor(options) {
|
|
8
8
|
this.value = options.value;
|
|
@@ -15,6 +15,7 @@ class Env {
|
|
|
15
15
|
this.position = options.position;
|
|
16
16
|
this.name = options.name;
|
|
17
17
|
this.remarks = options.remarks || '';
|
|
18
|
+
this.isPinned = options.isPinned || 0;
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
exports.Env = Env;
|
|
@@ -34,5 +35,6 @@ exports.EnvModel = _1.sequelize.define('Env', {
|
|
|
34
35
|
position: sequelize_1.DataTypes.NUMBER,
|
|
35
36
|
name: { type: sequelize_1.DataTypes.STRING, unique: 'compositeIndex' },
|
|
36
37
|
remarks: sequelize_1.DataTypes.STRING,
|
|
38
|
+
isPinned: sequelize_1.DataTypes.NUMBER,
|
|
37
39
|
});
|
|
38
40
|
//# sourceMappingURL=env.js.map
|
|
@@ -22,42 +22,36 @@ exports.default = async () => {
|
|
|
22
22
|
await subscription_1.SubscriptionModel.sync();
|
|
23
23
|
await cronView_1.CrontabViewModel.sync();
|
|
24
24
|
// 初始化新增字段
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const migrations = [
|
|
26
|
+
{
|
|
27
|
+
table: 'CrontabViews',
|
|
28
|
+
column: 'filterRelation',
|
|
29
|
+
type: 'VARCHAR(255)',
|
|
30
|
+
},
|
|
31
|
+
{ table: 'Subscriptions', column: 'proxy', type: 'VARCHAR(255)' },
|
|
32
|
+
{ table: 'CrontabViews', column: 'type', type: 'NUMBER' },
|
|
33
|
+
{ table: 'Subscriptions', column: 'autoAddCron', type: 'NUMBER' },
|
|
34
|
+
{ table: 'Subscriptions', column: 'autoDelCron', type: 'NUMBER' },
|
|
35
|
+
{ table: 'Crontabs', column: 'sub_id', type: 'NUMBER' },
|
|
36
|
+
{ table: 'Crontabs', column: 'extra_schedules', type: 'JSON' },
|
|
37
|
+
{ table: 'Crontabs', column: 'task_before', type: 'TEXT' },
|
|
38
|
+
{ table: 'Crontabs', column: 'task_after', type: 'TEXT' },
|
|
39
|
+
{ table: 'Crontabs', column: 'log_name', type: 'VARCHAR(255)' },
|
|
40
|
+
{
|
|
41
|
+
table: 'Crontabs',
|
|
42
|
+
column: 'allow_multiple_instances',
|
|
43
|
+
type: 'NUMBER',
|
|
44
|
+
},
|
|
45
|
+
{ table: 'Envs', column: 'isPinned', type: 'NUMBER' },
|
|
46
|
+
];
|
|
47
|
+
for (const migration of migrations) {
|
|
48
|
+
try {
|
|
49
|
+
await data_1.sequelize.query(`alter table ${migration.table} add column ${migration.column} ${migration.type}`);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
// Column already exists or other error, continue
|
|
53
|
+
}
|
|
27
54
|
}
|
|
28
|
-
catch (error) { }
|
|
29
|
-
try {
|
|
30
|
-
await data_1.sequelize.query('alter table Subscriptions add column proxy VARCHAR(255)');
|
|
31
|
-
}
|
|
32
|
-
catch (error) { }
|
|
33
|
-
try {
|
|
34
|
-
await data_1.sequelize.query('alter table CrontabViews add column type NUMBER');
|
|
35
|
-
}
|
|
36
|
-
catch (error) { }
|
|
37
|
-
try {
|
|
38
|
-
await data_1.sequelize.query('alter table Subscriptions add column autoAddCron NUMBER');
|
|
39
|
-
}
|
|
40
|
-
catch (error) { }
|
|
41
|
-
try {
|
|
42
|
-
await data_1.sequelize.query('alter table Subscriptions add column autoDelCron NUMBER');
|
|
43
|
-
}
|
|
44
|
-
catch (error) { }
|
|
45
|
-
try {
|
|
46
|
-
await data_1.sequelize.query('alter table Crontabs add column sub_id NUMBER');
|
|
47
|
-
}
|
|
48
|
-
catch (error) { }
|
|
49
|
-
try {
|
|
50
|
-
await data_1.sequelize.query('alter table Crontabs add column extra_schedules JSON');
|
|
51
|
-
}
|
|
52
|
-
catch (error) { }
|
|
53
|
-
try {
|
|
54
|
-
await data_1.sequelize.query('alter table Crontabs add column task_before TEXT');
|
|
55
|
-
}
|
|
56
|
-
catch (error) { }
|
|
57
|
-
try {
|
|
58
|
-
await data_1.sequelize.query('alter table Crontabs add column task_after TEXT');
|
|
59
|
-
}
|
|
60
|
-
catch (error) { }
|
|
61
55
|
logger_1.default.info('✌️ DB loaded');
|
|
62
56
|
}
|
|
63
57
|
catch (error) {
|
|
@@ -5,9 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const path_1 = __importDefault(require("path"));
|
|
7
7
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
|
+
const os_1 = __importDefault(require("os"));
|
|
8
9
|
const chokidar_1 = __importDefault(require("chokidar"));
|
|
9
10
|
const index_1 = __importDefault(require("../config/index"));
|
|
10
|
-
const
|
|
11
|
+
const logger_1 = __importDefault(require("./logger"));
|
|
11
12
|
async function linkToNodeModule(src, dst) {
|
|
12
13
|
const target = path_1.default.join(index_1.default.rootPath, 'node_modules', dst || src);
|
|
13
14
|
const source = path_1.default.join(index_1.default.rootPath, src);
|
|
@@ -20,8 +21,17 @@ async function linkToNodeModule(src, dst) {
|
|
|
20
21
|
catch (error) { }
|
|
21
22
|
}
|
|
22
23
|
async function linkCommand() {
|
|
23
|
-
const
|
|
24
|
-
|
|
24
|
+
const homeDir = os_1.default.homedir();
|
|
25
|
+
let userBinDir = path_1.default.join(homeDir, 'bin');
|
|
26
|
+
try {
|
|
27
|
+
await promises_1.default.mkdir(userBinDir, { recursive: true });
|
|
28
|
+
await linkCommandToDir(userBinDir);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
logger_1.default.error('Linking command failed:', error);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function linkCommandToDir(commandDir) {
|
|
25
35
|
const linkShell = [
|
|
26
36
|
{
|
|
27
37
|
src: 'update.sh',
|
|
@@ -38,6 +48,13 @@ async function linkCommand() {
|
|
|
38
48
|
const source = path_1.default.join(index_1.default.rootPath, 'shell', link.src);
|
|
39
49
|
const target = path_1.default.join(commandDir, link.dest);
|
|
40
50
|
const tmpTarget = path_1.default.join(commandDir, link.tmp);
|
|
51
|
+
try {
|
|
52
|
+
const stats = await promises_1.default.lstat(tmpTarget);
|
|
53
|
+
if (stats) {
|
|
54
|
+
await promises_1.default.unlink(tmpTarget);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) { }
|
|
41
58
|
await promises_1.default.symlink(source, tmpTarget);
|
|
42
59
|
await promises_1.default.rename(tmpTarget, target);
|
|
43
60
|
}
|
|
@@ -51,7 +68,7 @@ exports.default = async (src = 'deps') => {
|
|
|
51
68
|
persistent: true,
|
|
52
69
|
});
|
|
53
70
|
watcher
|
|
54
|
-
.on('add', (
|
|
55
|
-
.on('change', (
|
|
71
|
+
.on('add', () => linkToNodeModule(src))
|
|
72
|
+
.on('change', () => linkToNodeModule(src));
|
|
56
73
|
};
|
|
57
74
|
//# sourceMappingURL=deps.js.map
|
|
@@ -14,6 +14,8 @@ const express_urlrewrite_1 = __importDefault(require("express-urlrewrite"));
|
|
|
14
14
|
const celebrate_1 = require("celebrate");
|
|
15
15
|
const serverEnv_1 = require("../config/serverEnv");
|
|
16
16
|
const store_1 = require("../shared/store");
|
|
17
|
+
const auth_1 = require("../shared/auth");
|
|
18
|
+
const path_1 = __importDefault(require("path"));
|
|
17
19
|
exports.default = ({ app }) => {
|
|
18
20
|
app.set('trust proxy', 'loopback');
|
|
19
21
|
app.use((0, cors_1.default)());
|
|
@@ -21,11 +23,13 @@ exports.default = ({ app }) => {
|
|
|
21
23
|
app.use(`${config_1.default.api.prefix}/static`, express_1.default.static(config_1.default.uploadPath));
|
|
22
24
|
app.use(body_parser_1.default.json({ limit: '50mb' }));
|
|
23
25
|
app.use(body_parser_1.default.urlencoded({ limit: '50mb', extended: true }));
|
|
26
|
+
const frontendPath = path_1.default.join(config_1.default.rootPath, 'static/dist');
|
|
27
|
+
app.use(express_1.default.static(frontendPath));
|
|
24
28
|
app.use((0, express_jwt_1.expressjwt)({
|
|
25
29
|
secret: config_1.default.jwt.secret,
|
|
26
30
|
algorithms: ['HS384'],
|
|
27
31
|
}).unless({
|
|
28
|
-
path: [...config_1.default.apiWhiteList, /^\/
|
|
32
|
+
path: [...config_1.default.apiWhiteList, /^\/(?!api\/).*/],
|
|
29
33
|
}));
|
|
30
34
|
app.use((req, res, next) => {
|
|
31
35
|
if (!req.headers) {
|
|
@@ -39,6 +43,9 @@ exports.default = ({ app }) => {
|
|
|
39
43
|
});
|
|
40
44
|
app.use(async (req, res, next) => {
|
|
41
45
|
var _a;
|
|
46
|
+
if (!['/open/', '/api/'].some((x) => req.path.startsWith(x))) {
|
|
47
|
+
return next();
|
|
48
|
+
}
|
|
42
49
|
const headerToken = (0, util_1.getToken)(req);
|
|
43
50
|
if (req.path.startsWith('/open/')) {
|
|
44
51
|
const apps = await store_1.shareStore.getApps();
|
|
@@ -61,11 +68,8 @@ exports.default = ({ app }) => {
|
|
|
61
68
|
return next();
|
|
62
69
|
}
|
|
63
70
|
const authInfo = await store_1.shareStore.getAuthInfo();
|
|
64
|
-
if (authInfo
|
|
65
|
-
|
|
66
|
-
if (headerToken === token || tokens[req.platform] === headerToken) {
|
|
67
|
-
return next();
|
|
68
|
-
}
|
|
71
|
+
if ((0, auth_1.isValidToken)(authInfo, headerToken, req.platform)) {
|
|
72
|
+
return next();
|
|
69
73
|
}
|
|
70
74
|
const errorCode = headerToken ? 'invalid_token' : 'credentials_required';
|
|
71
75
|
const errorMessage = headerToken
|
|
@@ -94,10 +98,15 @@ exports.default = ({ app }) => {
|
|
|
94
98
|
});
|
|
95
99
|
app.use((0, express_urlrewrite_1.default)('/open/*', '/api/$1'));
|
|
96
100
|
app.use(config_1.default.api.prefix, (0, api_1.default)());
|
|
97
|
-
app.
|
|
98
|
-
const
|
|
99
|
-
err
|
|
100
|
-
|
|
101
|
+
app.get('*', (_, res, next) => {
|
|
102
|
+
const indexPath = path_1.default.join(frontendPath, 'index.html');
|
|
103
|
+
res.sendFile(indexPath, (err) => {
|
|
104
|
+
if (err) {
|
|
105
|
+
const err = new Error('Not Found');
|
|
106
|
+
err['status'] = 404;
|
|
107
|
+
next(err);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
101
110
|
});
|
|
102
111
|
app.use((0, celebrate_1.errors)());
|
|
103
112
|
app.use((err, req, res, next) => {
|
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
@@ -85,7 +108,8 @@ exports.default = async () => {
|
|
|
85
108
|
await dependence_2.DependenceModel.update({ status: dependence_2.DependenceStatus.queued, log: [] }, { where: { id: docs.map((x) => x.id) } });
|
|
86
109
|
setTimeout(async () => {
|
|
87
110
|
await dependenceService.installDependenceOneByOne(docs);
|
|
88
|
-
require('./bootAfter')
|
|
111
|
+
const bootAfterLoader = await Promise.resolve().then(() => __importStar(require('./bootAfter')));
|
|
112
|
+
bootAfterLoader.default();
|
|
89
113
|
}, 5000);
|
|
90
114
|
};
|
|
91
115
|
// 初始化更新 linux/python/nodejs 镜像源配置
|
|
@@ -7,6 +7,7 @@ const typedi_1 = require("typedi");
|
|
|
7
7
|
const system_1 = __importDefault(require("../services/system"));
|
|
8
8
|
const schedule_1 = __importDefault(require("../services/schedule"));
|
|
9
9
|
const subscription_1 = __importDefault(require("../services/subscription"));
|
|
10
|
+
const sshKey_1 = __importDefault(require("../services/sshKey"));
|
|
10
11
|
const config_1 = __importDefault(require("../config"));
|
|
11
12
|
const util_1 = require("../config/util");
|
|
12
13
|
const path_1 = require("path");
|
|
@@ -14,6 +15,7 @@ exports.default = async () => {
|
|
|
14
15
|
const systemService = typedi_1.Container.get(system_1.default);
|
|
15
16
|
const scheduleService = typedi_1.Container.get(schedule_1.default);
|
|
16
17
|
const subscriptionService = typedi_1.Container.get(subscription_1.default);
|
|
18
|
+
const sshKeyService = typedi_1.Container.get(sshKey_1.default);
|
|
17
19
|
// 生成内置token
|
|
18
20
|
let tokenCommand = `ts-node-transpile-only ${(0, path_1.join)(config_1.default.rootPath, 'back/token.ts')}`;
|
|
19
21
|
const tokenFile = (0, path_1.join)(config_1.default.rootPath, 'static/build/token.js');
|
|
@@ -46,6 +48,10 @@ exports.default = async () => {
|
|
|
46
48
|
}, true);
|
|
47
49
|
}
|
|
48
50
|
systemService.updateTimezone(data.info);
|
|
51
|
+
// Apply global SSH key if configured
|
|
52
|
+
if (data.info.globalSshKey) {
|
|
53
|
+
await sshKeyService.addGlobalSSHKey(data.info.globalSshKey, 'global');
|
|
54
|
+
}
|
|
49
55
|
}
|
|
50
56
|
await subscriptionService.setSshConfig();
|
|
51
57
|
const subs = await subscriptionService.list();
|
|
@@ -8,6 +8,7 @@ const typedi_1 = require("typedi");
|
|
|
8
8
|
const sock_1 = __importDefault(require("../services/sock"));
|
|
9
9
|
const util_1 = require("../config/util");
|
|
10
10
|
const store_1 = require("../shared/store");
|
|
11
|
+
const auth_1 = require("../shared/auth");
|
|
11
12
|
exports.default = async ({ server }) => {
|
|
12
13
|
const echo = sockjs_1.default.createServer({ prefix: '/api/ws', log: () => { } });
|
|
13
14
|
const sockService = typedi_1.Container.get(sock_1.default);
|
|
@@ -18,18 +19,15 @@ exports.default = async ({ server }) => {
|
|
|
18
19
|
const authInfo = await store_1.shareStore.getAuthInfo();
|
|
19
20
|
const platform = (0, util_1.getPlatform)(conn.headers['user-agent'] || '') || 'desktop';
|
|
20
21
|
const headerToken = conn.url.replace(`${conn.pathname}?token=`, '');
|
|
21
|
-
if (authInfo) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
});
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
22
|
+
if ((0, auth_1.isValidToken)(authInfo, headerToken, platform)) {
|
|
23
|
+
sockService.addClient(conn);
|
|
24
|
+
conn.on('data', (message) => {
|
|
25
|
+
conn.write(message);
|
|
26
|
+
});
|
|
27
|
+
conn.on('close', function () {
|
|
28
|
+
sockService.removeClient(conn);
|
|
29
|
+
});
|
|
30
|
+
return;
|
|
33
31
|
}
|
|
34
32
|
conn.close('404');
|
|
35
33
|
});
|