jsir 2.4.5 → 2.4.8
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/cmd/oaa.js +28 -33
- package/deps/room.js +128 -49
- package/deps/server.js +26 -14
- package/deps/setting.js +1 -1
- package/deps/util.js +39 -19
- package/package.json +1 -1
package/cmd/oaa.js
CHANGED
|
@@ -30,9 +30,8 @@ const _libDataDir = getLibDataDir()
|
|
|
30
30
|
const _fileWatcherMap = {}
|
|
31
31
|
const _types = setting.fileType
|
|
32
32
|
const console = createConsole();
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
const {reqNode} = require("../deps/room");
|
|
33
|
+
const Room = require('../deps/room');
|
|
34
|
+
const Server = require('../deps/server')
|
|
36
35
|
|
|
37
36
|
let lastFilterArg = '';
|
|
38
37
|
let _cmdMapFile = setting.name + 'CmdMap.json'
|
|
@@ -675,9 +674,12 @@ async function joinServer(uniqueName) {
|
|
|
675
674
|
let pair = parseUniqueName(uniqueName)
|
|
676
675
|
for (let key of Object.keys(exportLib)) {
|
|
677
676
|
let val = exportLib[key];
|
|
678
|
-
|
|
677
|
+
Server.setRoute('get', `/${pair[0]}/${trimJsirFileName(pair[1])}/${key}`,async (req, res) => {
|
|
679
678
|
res.result = await val(...req);
|
|
680
|
-
}
|
|
679
|
+
})
|
|
680
|
+
Server.setRoute('post', `/${pair[0]}/${trimJsirFileName(pair[1])}/${key}`,async (req, res) => {
|
|
681
|
+
res.result = await val(...req);
|
|
682
|
+
})
|
|
681
683
|
}
|
|
682
684
|
console.msg(uniqueName, 'has become a service.');
|
|
683
685
|
}
|
|
@@ -1032,7 +1034,6 @@ async function showRooms() {
|
|
|
1032
1034
|
let room = setting.rooms[i]
|
|
1033
1035
|
let isLocal = setting.selfRoom.selfNode === room.selfNode;
|
|
1034
1036
|
results.push({
|
|
1035
|
-
mid: i,
|
|
1036
1037
|
name: (isLocal ? "*" : " ") + room.name,
|
|
1037
1038
|
node: room.selfNode,
|
|
1038
1039
|
active: room.active,
|
|
@@ -1041,17 +1042,18 @@ async function showRooms() {
|
|
|
1041
1042
|
let jsir = room.jsirs[key]
|
|
1042
1043
|
let pidStr = (process.pid === jsir.pid ? "*" : " ") + jsir.pid;
|
|
1043
1044
|
results.push({
|
|
1044
|
-
mid: i,
|
|
1045
1045
|
name: (isLocal ? "*" : " ") + room.name,
|
|
1046
1046
|
node: room.selfNode,
|
|
1047
1047
|
active: room.active,
|
|
1048
1048
|
pid: jsir.newError ? errorStr(pidStr):pidStr,
|
|
1049
|
+
up: jsir.upTime || '',
|
|
1050
|
+
version: jsir.version || '',
|
|
1049
1051
|
space: jsir.space,
|
|
1050
1052
|
running: jsir.active,
|
|
1051
1053
|
port: jsir.port,
|
|
1052
1054
|
back: jsir.back,
|
|
1053
1055
|
busy: jsir.busy,
|
|
1054
|
-
tips: Object.keys(jsir.tips).map(i => i + ': ' + jsir.tips[i]).join('\n'),
|
|
1056
|
+
tips: Object.keys(jsir.tips).map(i => infoStr(i) + ': ' + jsir.tips[i]).join('\n'),
|
|
1055
1057
|
services: Object.keys(jsir.services || []).map(msgStr).join('\n')
|
|
1056
1058
|
});
|
|
1057
1059
|
}
|
|
@@ -1187,11 +1189,13 @@ const keywordDef = {
|
|
|
1187
1189
|
setting: {
|
|
1188
1190
|
comment: 'Global settings',
|
|
1189
1191
|
exeFn: async (args) => {
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1192
|
+
if (args[0]) {
|
|
1193
|
+
if (_cmdMap[args[0]]){
|
|
1194
|
+
let uniqueName = _cmdMap[args[0]];
|
|
1195
|
+
await eia(getEditor(), [`${getConfigDir()}/${md5(uniqueName)}.json`])
|
|
1196
|
+
} else {
|
|
1197
|
+
console.warn('invalid args')
|
|
1198
|
+
}
|
|
1195
1199
|
} else {
|
|
1196
1200
|
await eia(getEditor(), [`${getLibDataDir()}/config.json`])
|
|
1197
1201
|
}
|
|
@@ -1428,7 +1432,7 @@ const keywordDef = {
|
|
|
1428
1432
|
quit: {
|
|
1429
1433
|
comment: 'Exit',
|
|
1430
1434
|
exeFn: (args) => {
|
|
1431
|
-
|
|
1435
|
+
Room.offRoom();
|
|
1432
1436
|
delTips();
|
|
1433
1437
|
console.log(infoStr("Bye!"));
|
|
1434
1438
|
_noAppendNextLine = true;
|
|
@@ -1483,14 +1487,18 @@ const keywordDef = {
|
|
|
1483
1487
|
suffix = 'error'
|
|
1484
1488
|
}
|
|
1485
1489
|
if (type.indexOf("t") !== -1) {
|
|
1486
|
-
cmdStr = '
|
|
1490
|
+
cmdStr = 'tail -n 50 -f'
|
|
1487
1491
|
}
|
|
1488
1492
|
path = path + '.' + suffix;
|
|
1489
1493
|
if (!fs.existsSync(path)) {
|
|
1490
1494
|
console.warn('log file not found')
|
|
1491
1495
|
return;
|
|
1492
1496
|
}
|
|
1493
|
-
|
|
1497
|
+
if (isRunningInBackground()) {
|
|
1498
|
+
console.log(await e(`tail -n 500 "${path}"`))
|
|
1499
|
+
} else {
|
|
1500
|
+
await eia(cmdStr, [`"${path}"`], true)
|
|
1501
|
+
}
|
|
1494
1502
|
},
|
|
1495
1503
|
short: 'l'
|
|
1496
1504
|
},
|
|
@@ -1509,7 +1517,7 @@ const keywordDef = {
|
|
|
1509
1517
|
room: {
|
|
1510
1518
|
comment: 'manage room ([node])',
|
|
1511
1519
|
exeFn: async (args) => {
|
|
1512
|
-
await
|
|
1520
|
+
await Room.syncSetting();
|
|
1513
1521
|
if (args.length > 0) {
|
|
1514
1522
|
let have = false;
|
|
1515
1523
|
let tasks = []
|
|
@@ -1525,7 +1533,7 @@ const keywordDef = {
|
|
|
1525
1533
|
tasks.push(async (input) => {
|
|
1526
1534
|
let jsir = room.jsirs[pid];
|
|
1527
1535
|
console.log(infoStr(`[${pid}]`))
|
|
1528
|
-
let resp = await reqNode(room.selfNode, "post", "/enter", jsir.port, JSON.stringify({input}))
|
|
1536
|
+
let resp = await Room.reqNode(room.selfNode, "post", "/enter", jsir.port, JSON.stringify({input}))
|
|
1529
1537
|
console.log(JSON.parse(resp).output)
|
|
1530
1538
|
})
|
|
1531
1539
|
}
|
|
@@ -2162,20 +2170,7 @@ async function _requireSource(currSpace, cmdMatchStr, force = false) {
|
|
|
2162
2170
|
let serviceObj = {};
|
|
2163
2171
|
for (let fn of setting.services[serviceKey]) {
|
|
2164
2172
|
serviceObj[fn] = async (...args) => {
|
|
2165
|
-
|
|
2166
|
-
let targets = setting.serviceFns[key] || []
|
|
2167
|
-
targets = targets
|
|
2168
|
-
.filter(i => i.active)
|
|
2169
|
-
.filter(i => !room.isDisableConnect(i.node, i.port));
|
|
2170
|
-
let target = null;
|
|
2171
|
-
if (targets.length > 0) {
|
|
2172
|
-
target = room.busyPick(targets);
|
|
2173
|
-
} else {
|
|
2174
|
-
throw `service function ${key} not found`;
|
|
2175
|
-
}
|
|
2176
|
-
let resp = await room.reqNode(target.node, 'post',
|
|
2177
|
-
`/${pair[0]}/${encodeURIComponent(trimJsirFileName(pair[1]))}/${fn}`, target.port, JSON.stringify(args))
|
|
2178
|
-
return JSON.parse(resp).result;
|
|
2173
|
+
return await Room.reqFn(`${serviceKey}/${fn}`, args);
|
|
2179
2174
|
}
|
|
2180
2175
|
}
|
|
2181
2176
|
return serviceObj
|
|
@@ -2271,7 +2266,7 @@ process.on('beforeExit', function () {
|
|
|
2271
2266
|
delTips();
|
|
2272
2267
|
} else {
|
|
2273
2268
|
nextLine();
|
|
2274
|
-
|
|
2269
|
+
Room.onRoom(wrapperInput)
|
|
2275
2270
|
}
|
|
2276
2271
|
});
|
|
2277
2272
|
|
package/deps/room.js
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
const os = require('os');
|
|
2
2
|
const {fileJson, fileLock, vl, createConsole, getKeyTips, getValTips,
|
|
3
3
|
getRoomsDir, e, regEach, isRunningInBackground,
|
|
4
|
-
batchAsync, debugStr, trim, getOr, errorTag, warnStr, getConfig
|
|
4
|
+
batchAsync, debugStr, trim, getOr, errorTag, warnStr, getConfig, getConfigDir,
|
|
5
|
+
fileExist, formatUptime
|
|
5
6
|
} = require('./util');
|
|
6
7
|
const {setRoute, createSign} = require('../deps/server')
|
|
7
8
|
const roomDataFile = "jsirRoom.json"
|
|
8
9
|
const roomsDirLockKey = "RW_" + getRoomsDir();
|
|
9
10
|
const syncRoomsLockKey = "SyncRooms_" + getRoomsDir();
|
|
11
|
+
const syncConfigsLockKey = "SyncConfigs_" + getConfigDir();
|
|
10
12
|
const updateRoomInfoLockKey = "UPDATE_" + roomDataFile
|
|
11
13
|
const console = createConsole();
|
|
12
|
-
const net = require("net");
|
|
13
14
|
const setting = require('../deps/setting')
|
|
14
15
|
const fp = require('fs').promises
|
|
15
16
|
const http = require('http');
|
|
16
|
-
|
|
17
|
+
const tailscalePath = os.platform() === 'darwin' ?
|
|
17
18
|
'/Applications/Tailscale.app/Contents/MacOS/Tailscale':'tailscale';
|
|
19
|
+
const configMain = getConfig("configMain");
|
|
20
|
+
const packageJson = require("../package.json");
|
|
18
21
|
|
|
19
22
|
function debug(...args) {
|
|
20
23
|
if (global.$DEBUG) {
|
|
@@ -35,6 +38,19 @@ function isPidAlive(pid) {
|
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
async function localConfigs() {
|
|
42
|
+
let configDir = getConfigDir();
|
|
43
|
+
let configFiles = await fp.readdir(configDir)
|
|
44
|
+
let fns = configFiles
|
|
45
|
+
.map(i => () => fp.readFile(`${configDir}/${i}`));
|
|
46
|
+
let buffers = await batchAsync(fns, 33);
|
|
47
|
+
let configs = {}
|
|
48
|
+
for (let i = 0; i < configFiles.length; i++) {
|
|
49
|
+
configs[configFiles[i]] = String(buffers[i]);
|
|
50
|
+
}
|
|
51
|
+
return configs;
|
|
52
|
+
}
|
|
53
|
+
|
|
38
54
|
function onRoom(wrapperInput) {
|
|
39
55
|
if (!setting.roomTid[0]) {
|
|
40
56
|
try {
|
|
@@ -42,12 +58,12 @@ function onRoom(wrapperInput) {
|
|
|
42
58
|
setRoute("get", "/", (req, res) => setting.selfRoom)
|
|
43
59
|
setRoute("post", "/enter", async (req, res) => {
|
|
44
60
|
if (!getConfig("enableRemote", true)) {
|
|
45
|
-
res.output = warnStr("Disable Remote
|
|
61
|
+
res.output = warnStr("Disable Remote")
|
|
46
62
|
return;
|
|
47
63
|
}
|
|
48
64
|
if (vl(req.input)) {
|
|
49
65
|
if (!isRunningInBackground() && ['.nsir', '.N'].indexOf(req.input.trim()) === -1) {
|
|
50
|
-
res.output = warnStr("Disable Remote
|
|
66
|
+
res.output = warnStr("Disable Remote")
|
|
51
67
|
return;
|
|
52
68
|
}
|
|
53
69
|
setting.enterOutputs = []
|
|
@@ -57,6 +73,11 @@ function onRoom(wrapperInput) {
|
|
|
57
73
|
res.output = outputs.join('');
|
|
58
74
|
}
|
|
59
75
|
})
|
|
76
|
+
if (configMain) {
|
|
77
|
+
setRoute("post", "/" + setting.configMainFnKey, async (req, res) => {
|
|
78
|
+
res.result = await localConfigs();
|
|
79
|
+
})
|
|
80
|
+
}
|
|
60
81
|
} catch (e) {
|
|
61
82
|
debug("initRoute failed", e)
|
|
62
83
|
}
|
|
@@ -252,17 +273,50 @@ async function initRoom() {
|
|
|
252
273
|
if (roomUpdateTouchTime) {
|
|
253
274
|
await fileLock(updateRoomInfoLockKey, updateRoomInfo, false)
|
|
254
275
|
fileLock(syncRoomsLockKey, syncRooms, false);
|
|
276
|
+
if (!configMain && setting.serviceFns.hasOwnProperty(setting.configMainFnKey)) {
|
|
277
|
+
fileLock(syncConfigsLockKey, syncConfigs, false);
|
|
278
|
+
}
|
|
255
279
|
}
|
|
256
280
|
|
|
257
281
|
await syncSetting();
|
|
258
282
|
}
|
|
259
283
|
|
|
284
|
+
async function syncConfigs() {
|
|
285
|
+
let configs;
|
|
286
|
+
try {
|
|
287
|
+
configs = await reqFn(setting.configMainFnKey);
|
|
288
|
+
} catch (e) {
|
|
289
|
+
debug("syncConfigs failed", e)
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
let configDir = getConfigDir();
|
|
293
|
+
let fns = [];
|
|
294
|
+
for (let key of Object.keys(configs)) {
|
|
295
|
+
let path = configDir + "/" + key;
|
|
296
|
+
let text = configs[key];
|
|
297
|
+
fns.push(async () => {
|
|
298
|
+
if (await fileExist(path)) {
|
|
299
|
+
let currText = String(await fp.readFile(path));
|
|
300
|
+
if (currText !== text) {
|
|
301
|
+
await fp.writeFile(path, text)
|
|
302
|
+
debug(`sync ${key} success`);
|
|
303
|
+
}
|
|
304
|
+
} else {
|
|
305
|
+
await fp.writeFile(path, text)
|
|
306
|
+
debug(`sync ${key} success`);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
await batchAsync(fns, 33)
|
|
311
|
+
debug('syncConfigs done')
|
|
312
|
+
}
|
|
313
|
+
|
|
260
314
|
async function cleanRoom(room) {
|
|
261
315
|
// 清理进程
|
|
262
316
|
for (let pid of Object.keys(room.jsirs || {})) {
|
|
263
317
|
let jsir = room.jsirs[pid]
|
|
264
318
|
let active = Date.now() - (jsir.lastUpdateTime || 0) <= setting.roomHeartbeatExpire;
|
|
265
|
-
if (!active && isPidAlive(pid)) {
|
|
319
|
+
if (jsir.back && !active && isPidAlive(pid)) {
|
|
266
320
|
try {
|
|
267
321
|
debug(`kill inactive jsir ${pid}`)
|
|
268
322
|
process.kill(parseInt(pid), 'SIGKILL'); // 强制终止进程
|
|
@@ -297,7 +351,11 @@ async function initRoomJsir(room) {
|
|
|
297
351
|
for (let key of Object.keys(setting.routes)) {
|
|
298
352
|
let ss = key.split("/").map(trim).filter(i => i);
|
|
299
353
|
if (ss.length > 3) {
|
|
354
|
+
// 脚本空间service
|
|
300
355
|
getOr(services, ss[1] + '/' + ss[2], []).push(ss[3])
|
|
356
|
+
} else if (ss.length > 2) {
|
|
357
|
+
// jsir service
|
|
358
|
+
getOr(services, ss[1], []).push(ss[2])
|
|
301
359
|
}
|
|
302
360
|
}
|
|
303
361
|
// 初始化jsir
|
|
@@ -314,7 +372,9 @@ async function initRoomJsir(room) {
|
|
|
314
372
|
lastUpdateTime: Date.now(),
|
|
315
373
|
port: setting.server ? setting.server.address().port:null,
|
|
316
374
|
services: services,
|
|
317
|
-
newError: global.$newError
|
|
375
|
+
newError: global.$newError,
|
|
376
|
+
version: packageJson.version,
|
|
377
|
+
upTime: formatUptime()
|
|
318
378
|
}
|
|
319
379
|
}
|
|
320
380
|
|
|
@@ -374,53 +434,57 @@ async function reqNode(node, method, url, port, body) {
|
|
|
374
434
|
'sign': createSign()
|
|
375
435
|
}
|
|
376
436
|
};
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
data
|
|
437
|
+
let time = Date.now();
|
|
438
|
+
try {
|
|
439
|
+
return await new Promise((resolve, reject) => {
|
|
440
|
+
try {
|
|
441
|
+
let timeoutMs = setting.reqNodeTimeouts[url] || setting.reqNodeDefaultTimeout;
|
|
442
|
+
let timeout = null
|
|
443
|
+
|
|
444
|
+
const req = http.request(opt, (res) => {
|
|
445
|
+
let data = '';
|
|
446
|
+
// 数据块接收
|
|
447
|
+
res.on('data', (chunk) => {
|
|
448
|
+
data += chunk;
|
|
449
|
+
});
|
|
450
|
+
// 响应结束
|
|
451
|
+
res.on('end', () => {
|
|
452
|
+
clearTimeout(timeout)
|
|
453
|
+
// 检查响应状态码
|
|
454
|
+
if (res.statusCode !== 200) {
|
|
455
|
+
reject(errorTag(new Error(data), decodeURIComponent(url)));
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
resolve(data)
|
|
459
|
+
});
|
|
388
460
|
});
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
//
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
461
|
+
|
|
462
|
+
// 设置超时逻辑
|
|
463
|
+
timeout = setTimeout(() => {
|
|
464
|
+
req.destroy(); // 中断请求
|
|
465
|
+
}, timeoutMs); // 10秒超时
|
|
466
|
+
|
|
467
|
+
// 错误处理
|
|
468
|
+
req.on('error', (e) => {
|
|
469
|
+
clearTimeout(timeout); // 清除超时定时器
|
|
470
|
+
if (room) {
|
|
471
|
+
setting.disableConnect[node + ":" + port] = Date.now() + setting.disableConnectLimit
|
|
396
472
|
}
|
|
397
|
-
|
|
473
|
+
reject(e)
|
|
398
474
|
});
|
|
399
|
-
});
|
|
400
475
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
req.destroy(); // 中断请求
|
|
404
|
-
}, timeoutMs); // 10秒超时
|
|
405
|
-
|
|
406
|
-
// 错误处理
|
|
407
|
-
req.on('error', (e) => {
|
|
408
|
-
clearTimeout(timeout); // 清除超时定时器
|
|
409
|
-
if (room) {
|
|
410
|
-
setting.disableConnect[node + ":" + port] = Date.now() + setting.disableConnectLimit
|
|
476
|
+
if (body) {
|
|
477
|
+
req.write(body)
|
|
411
478
|
}
|
|
479
|
+
// 结束请求
|
|
480
|
+
req.end();
|
|
481
|
+
} catch (e) {
|
|
412
482
|
reject(e)
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
if (body) {
|
|
416
|
-
req.write(body)
|
|
417
483
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
423
|
-
})
|
|
484
|
+
});
|
|
485
|
+
} finally {
|
|
486
|
+
debug(`reqRoom cost ${Date.now() - time}ms`, JSON.stringify(opt), )
|
|
487
|
+
}
|
|
424
488
|
}
|
|
425
489
|
|
|
426
490
|
function busyPick(busyItems) {
|
|
@@ -441,11 +505,26 @@ function busyPick(busyItems) {
|
|
|
441
505
|
}
|
|
442
506
|
}
|
|
443
507
|
|
|
508
|
+
async function reqFn(fnKey, args = []) {
|
|
509
|
+
let targets = setting.serviceFns[fnKey] || []
|
|
510
|
+
targets = targets
|
|
511
|
+
.filter(i => i.active)
|
|
512
|
+
.filter(i => !isDisableConnect(i.node, i.port));
|
|
513
|
+
let target = null;
|
|
514
|
+
if (targets.length > 0) {
|
|
515
|
+
target = busyPick(targets);
|
|
516
|
+
} else {
|
|
517
|
+
throw `service function ${fnKey} not found`;
|
|
518
|
+
}
|
|
519
|
+
let resp = await reqNode(target.node, 'post',
|
|
520
|
+
`/${encodeURI(fnKey)}`, target.port, JSON.stringify(args || []))
|
|
521
|
+
return JSON.parse(resp).result;
|
|
522
|
+
}
|
|
523
|
+
|
|
444
524
|
module.exports = {
|
|
445
525
|
onRoom,
|
|
446
526
|
offRoom,
|
|
447
527
|
syncSetting,
|
|
448
528
|
reqNode,
|
|
449
|
-
|
|
450
|
-
busyPick
|
|
529
|
+
reqFn
|
|
451
530
|
}
|
package/deps/server.js
CHANGED
|
@@ -7,6 +7,7 @@ const preferredPort = setting.defaultPort;
|
|
|
7
7
|
// 路由存储
|
|
8
8
|
const routes = setting.routes;
|
|
9
9
|
let invokeStart = false;
|
|
10
|
+
const apiReg = /[^a-zA-Z]api[^a-zA-Z]|[^a-zA-Z]api$/i;
|
|
10
11
|
|
|
11
12
|
function debug(...args) {
|
|
12
13
|
if (global.$DEBUG) {
|
|
@@ -36,7 +37,15 @@ function createSign() {
|
|
|
36
37
|
async function createServer(port) {
|
|
37
38
|
const server = http.createServer(async (req, res) => {
|
|
38
39
|
const method = req.method.toLowerCase();
|
|
39
|
-
const
|
|
40
|
+
const originUrl = decodeURI(req.url);
|
|
41
|
+
|
|
42
|
+
let url = originUrl;
|
|
43
|
+
let params = '[]'
|
|
44
|
+
let sepIndex = originUrl.indexOf("?");
|
|
45
|
+
if (sepIndex !== -1) {
|
|
46
|
+
url = originUrl.substring(0, sepIndex).trim()
|
|
47
|
+
params = JSON.stringify([...new URLSearchParams(originUrl.substring(sepIndex).trim()).values()]);
|
|
48
|
+
}
|
|
40
49
|
|
|
41
50
|
// 获取客户端的 IP 地址
|
|
42
51
|
const clientIp = req.socket.remoteAddress || req.connection.remoteAddress;
|
|
@@ -45,22 +54,25 @@ async function createServer(port) {
|
|
|
45
54
|
debug(`Received ${routeKey} from ${clientIp}`);
|
|
46
55
|
|
|
47
56
|
if (routes[routeKey]) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
57
|
+
if (!apiReg.test(routeKey)) {
|
|
58
|
+
// 如果不是api接口,则校验签名
|
|
59
|
+
// 取header里的sign字段
|
|
60
|
+
const sign = req.headers['sign'];
|
|
61
|
+
if (sign) {
|
|
62
|
+
const decodedTime = verifySign(sign);
|
|
63
|
+
const currentTime = Date.now();
|
|
53
64
|
|
|
54
|
-
|
|
65
|
+
if (decodedTime === null || Math.abs(currentTime - decodedTime) > setting.serverSignExpire) {
|
|
66
|
+
res.writeHead(403, { 'Content-Type': 'text/plain' });
|
|
67
|
+
res.end('Forbidden: Invalid Sign');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
// 如果没有sign字段,返回403
|
|
55
72
|
res.writeHead(403, { 'Content-Type': 'text/plain' });
|
|
56
|
-
res.end('Forbidden:
|
|
73
|
+
res.end('Forbidden: Missing Sign');
|
|
57
74
|
return;
|
|
58
75
|
}
|
|
59
|
-
} else {
|
|
60
|
-
// 如果没有sign字段,返回403
|
|
61
|
-
res.writeHead(403, { 'Content-Type': 'text/plain' });
|
|
62
|
-
res.end('Forbidden: Missing Sign');
|
|
63
|
-
return;
|
|
64
76
|
}
|
|
65
77
|
// 如果签名通过,继续处理请求
|
|
66
78
|
try {
|
|
@@ -77,7 +89,7 @@ async function createServer(port) {
|
|
|
77
89
|
resolve()
|
|
78
90
|
})
|
|
79
91
|
})
|
|
80
|
-
await routes[routeKey](body, res);
|
|
92
|
+
await routes[routeKey](body || params, res);
|
|
81
93
|
} catch (e) {
|
|
82
94
|
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
83
95
|
res.end(String(isError(e) ? e.message:e));
|
package/deps/setting.js
CHANGED
package/deps/util.js
CHANGED
|
@@ -256,7 +256,7 @@ function createConsole(uniqueName) {
|
|
|
256
256
|
if ('debug' === key && !global.$DEBUG) {
|
|
257
257
|
return;
|
|
258
258
|
}
|
|
259
|
-
if (uniqueName &&
|
|
259
|
+
if (uniqueName && quite) {
|
|
260
260
|
if ((key === 'table' || key === 'nable') && typeof args[0] === "object") {
|
|
261
261
|
args = ['', ...args]
|
|
262
262
|
}
|
|
@@ -272,9 +272,6 @@ function createConsole(uniqueName) {
|
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
}
|
|
275
|
-
if (uniqueName) {
|
|
276
|
-
setting.consoleMap[uniqueName] = result;
|
|
277
|
-
}
|
|
278
275
|
return result;
|
|
279
276
|
}
|
|
280
277
|
|
|
@@ -1017,9 +1014,6 @@ function _getConfig(key, defaultVal, uniqueName) {
|
|
|
1017
1014
|
if (key === undefined) {
|
|
1018
1015
|
return config
|
|
1019
1016
|
}
|
|
1020
|
-
if (uniqueName && setting.consoleMap[uniqueName]) {
|
|
1021
|
-
setting.consoleMap[uniqueName].msg(`require ${uniqueName} config "${key}"`)
|
|
1022
|
-
}
|
|
1023
1017
|
let writeFlag = false
|
|
1024
1018
|
if (!(key in config)) {
|
|
1025
1019
|
writeFlag = true
|
|
@@ -1175,14 +1169,7 @@ async function _fileLock(key, fn, expireMs = 49000) {
|
|
|
1175
1169
|
const expireAt = expireMs > 0 ? now + expireMs : 0;
|
|
1176
1170
|
|
|
1177
1171
|
// 1. 尝试判断锁目录是否已存在
|
|
1178
|
-
let lockExists =
|
|
1179
|
-
try {
|
|
1180
|
-
await fp.access(lockKeyDir); // 若存在则不抛错
|
|
1181
|
-
lockExists = true;
|
|
1182
|
-
} catch (_) {
|
|
1183
|
-
// 不存在时会抛ENOENT错误,说明还没有锁
|
|
1184
|
-
lockExists = false;
|
|
1185
|
-
}
|
|
1172
|
+
let lockExists = await fileExist(lockKeyDir);
|
|
1186
1173
|
|
|
1187
1174
|
if (lockExists) {
|
|
1188
1175
|
// 目录存在时,读取文件名中的过期时间戳
|
|
@@ -1569,6 +1556,9 @@ async function eia(cmd, args = [], shell = false) {
|
|
|
1569
1556
|
`
|
|
1570
1557
|
当前进程不会卡住,输入输出由cmd进程持有
|
|
1571
1558
|
`
|
|
1559
|
+
if (isRunningInBackground()) {
|
|
1560
|
+
throw 'Unsupported Operation';
|
|
1561
|
+
}
|
|
1572
1562
|
setting.enableNextLine = false;
|
|
1573
1563
|
let child = spawn(cmd, args, {stdio:"inherit", shell});
|
|
1574
1564
|
return new Promise((resolve, reject) => {
|
|
@@ -1895,7 +1885,7 @@ function md5(message) {
|
|
|
1895
1885
|
return crypto.createHash('md5').update(message).digest('hex');
|
|
1896
1886
|
}
|
|
1897
1887
|
|
|
1898
|
-
async function batchAsync(fns = [], asyncNum =
|
|
1888
|
+
async function batchAsync(fns = [], asyncNum = 9, limitMs = 0) {
|
|
1899
1889
|
if (fns.length <= 0 || asyncNum < 1) {
|
|
1900
1890
|
return []
|
|
1901
1891
|
}
|
|
@@ -1905,7 +1895,12 @@ async function batchAsync(fns = [], asyncNum = 1, limitMs = 49000) {
|
|
|
1905
1895
|
for(let i = 0; i< fns.length; i++) {
|
|
1906
1896
|
let pro = new Promise(async (resolve, reject) => {
|
|
1907
1897
|
try {
|
|
1908
|
-
let resp
|
|
1898
|
+
let resp;
|
|
1899
|
+
if (limitMs) {
|
|
1900
|
+
resp = await timeLimit([fns[i]()], limitMs);
|
|
1901
|
+
} else {
|
|
1902
|
+
resp = [await fns[i]()];
|
|
1903
|
+
}
|
|
1909
1904
|
doneMap[i] = pro;
|
|
1910
1905
|
resolve(resp[0])
|
|
1911
1906
|
} catch (e) {
|
|
@@ -2053,7 +2048,7 @@ function getValTips() {
|
|
|
2053
2048
|
}
|
|
2054
2049
|
return item;
|
|
2055
2050
|
}).join("|");
|
|
2056
|
-
items.push(val)
|
|
2051
|
+
items.push(val || trim(key))
|
|
2057
2052
|
}
|
|
2058
2053
|
return items
|
|
2059
2054
|
}
|
|
@@ -2082,6 +2077,8 @@ function interceptStdStreams() {
|
|
|
2082
2077
|
process.stdout.write = (chunk, ...args) => {
|
|
2083
2078
|
if(setting.enterOutputs) {
|
|
2084
2079
|
setting.enterOutputs.push(chunk.toString());
|
|
2080
|
+
} else if (isRunningInBackground()) {
|
|
2081
|
+
console.$log(process.pid, "stdout", "\n" + chunk.toString().trimEnd());
|
|
2085
2082
|
} else {
|
|
2086
2083
|
originalStdoutWrite(chunk, ...args); // 保留原始行为
|
|
2087
2084
|
}
|
|
@@ -2091,13 +2088,35 @@ function interceptStdStreams() {
|
|
|
2091
2088
|
process.stderr.write = (chunk, ...args) => {
|
|
2092
2089
|
if(setting.enterOutputs) {
|
|
2093
2090
|
setting.enterOutputs.push(chunk.toString());
|
|
2091
|
+
} else if (isRunningInBackground()) {
|
|
2092
|
+
console.$error(process.pid, errorStr("stderr"), "\n" + chunk.toString().trimEnd());
|
|
2094
2093
|
} else {
|
|
2095
2094
|
originalStderrWrite(chunk, ...args); // 保留原始行为
|
|
2096
2095
|
}
|
|
2097
2096
|
};
|
|
2098
2097
|
}
|
|
2099
2098
|
|
|
2099
|
+
function formatUptime() {
|
|
2100
|
+
const uptimeSeconds = process.uptime();
|
|
2101
|
+
|
|
2102
|
+
const days = Math.floor(uptimeSeconds / (3600 * 24)); // 计算天数
|
|
2103
|
+
const hours = Math.floor((uptimeSeconds % (3600 * 24)) / 3600); // 计算小时
|
|
2104
|
+
const minutes = Math.floor((uptimeSeconds % 3600) / 60); // 计算分钟
|
|
2105
|
+
const seconds = Math.floor(uptimeSeconds % 60); // 计算秒数
|
|
2106
|
+
|
|
2107
|
+
if (days > 0) {
|
|
2108
|
+
return `${days}d${hours}h`;
|
|
2109
|
+
} else if (hours > 0) {
|
|
2110
|
+
return `${hours}h${minutes}m`;
|
|
2111
|
+
} else if (minutes > 0) {
|
|
2112
|
+
return `${minutes}m${seconds}s`;
|
|
2113
|
+
} else {
|
|
2114
|
+
return `${seconds}s`;
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2100
2118
|
module.exports = {
|
|
2119
|
+
formatUptime,
|
|
2101
2120
|
wrapperJsirText,
|
|
2102
2121
|
run,
|
|
2103
2122
|
reget,
|
|
@@ -2206,5 +2225,6 @@ module.exports = {
|
|
|
2206
2225
|
isRunningInBackground,
|
|
2207
2226
|
createDetachedProcess,
|
|
2208
2227
|
interceptStdStreams,
|
|
2209
|
-
draftModify
|
|
2228
|
+
draftModify,
|
|
2229
|
+
fileExist
|
|
2210
2230
|
}
|