jsir 2.3.8 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cmd/oaa.js +56 -41
- package/deps/evalCode.js +6 -2
- package/deps/room.js +49 -27
- package/deps/server.js +52 -7
- package/deps/setting.js +2 -1
- package/deps/util.js +79 -32
- package/package.json +1 -1
package/cmd/oaa.js
CHANGED
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
createConsole, setTips, delTips,
|
|
12
12
|
getEditor, errorStr, getConfigDir,
|
|
13
13
|
getFullPath, parseUniqueName, toUniqueName, isJsirFileName, toJsirFileName,
|
|
14
|
-
getAlias, wrapperJsirText, eia, getKeyTips, getValTips,
|
|
14
|
+
getAlias, wrapperJsirText, eia, getKeyTips, getValTips, getJsirTypeKey
|
|
15
15
|
} = $lib;
|
|
16
16
|
const _args = process.argv.slice(2).map(trim);
|
|
17
17
|
const evalCode = require('../deps/evalCode')
|
|
@@ -437,9 +437,10 @@ async function save(args) {
|
|
|
437
437
|
return
|
|
438
438
|
}
|
|
439
439
|
let resp;
|
|
440
|
-
|
|
440
|
+
let typeKey = getJsirTypeKey(args[0]);
|
|
441
|
+
if (typeKey === setting.exeKey) {
|
|
441
442
|
resp = example.exeFile;
|
|
442
|
-
} else if (
|
|
443
|
+
} else if (typeKey === setting.initKey) {
|
|
443
444
|
resp = example.initFile;
|
|
444
445
|
} else {
|
|
445
446
|
resp = await getCbText();
|
|
@@ -498,8 +499,8 @@ function listCmd(tmpMap) {
|
|
|
498
499
|
a = parseUniqueName(a)[1];
|
|
499
500
|
b = parseUniqueName(b)[1];
|
|
500
501
|
let typeKeys = Object.keys(_types);
|
|
501
|
-
let orderA = typeKeys.indexOf(a
|
|
502
|
-
let orderB = typeKeys.indexOf(b
|
|
502
|
+
let orderA = typeKeys.indexOf(getJsirTypeKey(a));
|
|
503
|
+
let orderB = typeKeys.indexOf(getJsirTypeKey(b));
|
|
503
504
|
orderA = orderA === -1 ? 999999:orderA;
|
|
504
505
|
orderB = orderB === -1 ? 999999:orderB;
|
|
505
506
|
return orderA - orderB
|
|
@@ -521,7 +522,7 @@ function listCmd(tmpMap) {
|
|
|
521
522
|
let item = {
|
|
522
523
|
key: ' ' + i,
|
|
523
524
|
name: pair[0] + '/' + name,
|
|
524
|
-
type: [_types[name
|
|
525
|
+
type: [_types[getJsirTypeKey(name)] || setting.defaultType, suffix].map(trim).join(".")
|
|
525
526
|
}
|
|
526
527
|
items.push(item)
|
|
527
528
|
|
|
@@ -620,7 +621,7 @@ async function _wrapperInput(str) {
|
|
|
620
621
|
let path = getFullPath(_cmdMap[strs[0]])
|
|
621
622
|
let uniqueName = trim(_cmdMap[strs[0]]);
|
|
622
623
|
let fileName = parseUniqueName(uniqueName)[1]
|
|
623
|
-
let firstName = fileName
|
|
624
|
+
let firstName = getJsirTypeKey(fileName)
|
|
624
625
|
if (firstName === setting.fileKey) {
|
|
625
626
|
await workFile(uniqueName)
|
|
626
627
|
} else if (firstName !== setting.exeKey) {
|
|
@@ -964,6 +965,41 @@ let compareMode = {
|
|
|
964
965
|
}
|
|
965
966
|
}
|
|
966
967
|
|
|
968
|
+
async function showRooms() {
|
|
969
|
+
let results = [];
|
|
970
|
+
for (let i = 0; i < setting.rooms.length; i++) {
|
|
971
|
+
let room = setting.rooms[i]
|
|
972
|
+
let isLocal = setting.selfRoom.selfNode === room.selfNode;
|
|
973
|
+
results.push({
|
|
974
|
+
mid: i,
|
|
975
|
+
name: (isLocal ? "*" : " ") + room.name,
|
|
976
|
+
node: room.selfNode,
|
|
977
|
+
active: room.active,
|
|
978
|
+
})
|
|
979
|
+
for (let key of Object.keys(room.jsirs)) {
|
|
980
|
+
let jsir = room.jsirs[key]
|
|
981
|
+
results.push({
|
|
982
|
+
mid: i,
|
|
983
|
+
name: (isLocal ? "*" : " ") + room.name,
|
|
984
|
+
node: room.selfNode,
|
|
985
|
+
active: room.active,
|
|
986
|
+
pid: (process.pid === jsir.pid ? "*" : " ") + jsir.pid,
|
|
987
|
+
space: jsir.space,
|
|
988
|
+
running: jsir.active,
|
|
989
|
+
port: jsir.port,
|
|
990
|
+
back: jsir.back,
|
|
991
|
+
busy: jsir.busy,
|
|
992
|
+
tips: Object.keys(jsir.tips).map(i => i + ': ' + jsir.tips[i]).join('\n')
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
if (results.length > 0) {
|
|
997
|
+
console.nable(results)
|
|
998
|
+
} else {
|
|
999
|
+
console.warn("no items")
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
967
1003
|
const keywordDef = {
|
|
968
1004
|
help: {
|
|
969
1005
|
comment: 'Help documentation',
|
|
@@ -1404,39 +1440,17 @@ const keywordDef = {
|
|
|
1404
1440
|
short: 'D'
|
|
1405
1441
|
},
|
|
1406
1442
|
room: {
|
|
1407
|
-
comment: 'manage room',
|
|
1443
|
+
comment: 'manage room ([node])',
|
|
1408
1444
|
exeFn: async (args) => {
|
|
1409
|
-
let results = [];
|
|
1410
1445
|
await room.syncSetting();
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
node: room.selfNode,
|
|
1417
|
-
active: room.active,
|
|
1418
|
-
})
|
|
1419
|
-
for (let key of Object.keys(room.jsirs)) {
|
|
1420
|
-
let jsir = room.jsirs[key]
|
|
1421
|
-
results.push({
|
|
1422
|
-
mid: i,
|
|
1423
|
-
name: (room.local ? "*":"") + room.name,
|
|
1424
|
-
node: room.selfNode,
|
|
1425
|
-
active: room.active,
|
|
1426
|
-
pid: (process.pid === jsir.pid ? "*":" ") + jsir.pid,
|
|
1427
|
-
space: jsir.space,
|
|
1428
|
-
running: jsir.active,
|
|
1429
|
-
port: jsir.port,
|
|
1430
|
-
back: jsir.back,
|
|
1431
|
-
busy: jsir.busy,
|
|
1432
|
-
tips: Object.keys(jsir.tips).map(i => i + ': ' + jsir.tips[i]).join('\n')
|
|
1433
|
-
});
|
|
1446
|
+
if (args[0]) {
|
|
1447
|
+
if (setting.selfRoom.nodes.indexOf(args[0]) !== -1) {
|
|
1448
|
+
await eia("ssh", [args[0]])
|
|
1449
|
+
} else {
|
|
1450
|
+
console.warn("invalid node")
|
|
1434
1451
|
}
|
|
1435
|
-
}
|
|
1436
|
-
if (results.length > 0) {
|
|
1437
|
-
console.nable(results)
|
|
1438
1452
|
} else {
|
|
1439
|
-
|
|
1453
|
+
await showRooms();
|
|
1440
1454
|
}
|
|
1441
1455
|
},
|
|
1442
1456
|
short: 'm'
|
|
@@ -1450,7 +1464,7 @@ function getQuickRunCmds(input, matchStr) {
|
|
|
1450
1464
|
} else if (input.startsWith("/")) {
|
|
1451
1465
|
matchStr = '/' + matchStr;
|
|
1452
1466
|
}
|
|
1453
|
-
return filterCmd(matchStr).filter(i => parseUniqueName(i)[1]
|
|
1467
|
+
return filterCmd(matchStr).filter(i => getJsirTypeKey(parseUniqueName(i)[1]) === setting.exeKey)
|
|
1454
1468
|
}
|
|
1455
1469
|
|
|
1456
1470
|
async function preLoad(text, fnNameMatch, fn, packages = [], space) {
|
|
@@ -1963,7 +1977,7 @@ function parseArgDef(inputString) {
|
|
|
1963
1977
|
}
|
|
1964
1978
|
|
|
1965
1979
|
function getArgDef(text, uniqueName) {
|
|
1966
|
-
if (uniqueName &&
|
|
1980
|
+
if (uniqueName && getJsirTypeKey(parseUniqueName(uniqueName)[1]) !== setting.exeKey) {
|
|
1967
1981
|
return {}
|
|
1968
1982
|
}
|
|
1969
1983
|
if (text.indexOf("$defArgs") === -1) {
|
|
@@ -2025,7 +2039,7 @@ function filterRequire(currSpace, cmdMatchStr) {
|
|
|
2025
2039
|
cmds = cmds.filter(cmd => parseUniqueName(cmd)[0] === (appointSpace || currSpace))
|
|
2026
2040
|
}
|
|
2027
2041
|
if (cmds.length > 0) {
|
|
2028
|
-
cmds = cmds.filter(cmd => parseUniqueName(cmd)[1]
|
|
2042
|
+
cmds = cmds.filter(cmd => getJsirTypeKey(parseUniqueName(cmd)[1]) === setting.initKey)
|
|
2029
2043
|
}
|
|
2030
2044
|
}
|
|
2031
2045
|
if (cmds.length > 1) {
|
|
@@ -2042,9 +2056,10 @@ async function _requireSource(currSpace, cmdMatchStr) {
|
|
|
2042
2056
|
let path = getFullPath(uniqueName)
|
|
2043
2057
|
let text = String(await fp.readFile(path))
|
|
2044
2058
|
let pair = parseUniqueName(uniqueName)
|
|
2045
|
-
|
|
2059
|
+
let typeKey = getJsirTypeKey(pair[1]);
|
|
2060
|
+
if (typeKey === setting.initKey) {
|
|
2046
2061
|
result = await evalText(text, uniqueName)
|
|
2047
|
-
} else if (
|
|
2062
|
+
} else if (typeKey === setting.exeKey) {
|
|
2048
2063
|
result = async (argsStr) => {
|
|
2049
2064
|
return await runCmd(trim(argsStr), uniqueName, text)
|
|
2050
2065
|
}
|
package/deps/evalCode.js
CHANGED
|
@@ -37,6 +37,10 @@ module.exports = async ($text = '', $cmdName = '', $args = [],
|
|
|
37
37
|
$homeDir, $lib, $cmdMap
|
|
38
38
|
}
|
|
39
39
|
let console = $lib.createConsole($cmdName);
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
try {
|
|
41
|
+
return await eval(`(async ()=>{${$text};
|
|
42
|
+
})()`)
|
|
43
|
+
} catch (e) {
|
|
44
|
+
console.error(e)
|
|
45
|
+
}
|
|
42
46
|
}
|
package/deps/room.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const os = require('os');
|
|
2
2
|
const {fileJson, fileLock, vl, createConsole, getKeyTips, getValTips,
|
|
3
|
-
getRoomsDir, e, regEach
|
|
4
|
-
|
|
3
|
+
getRoomsDir, e, regEach, isRunningInBackground,
|
|
4
|
+
batchAsync, debugStr
|
|
5
|
+
} = require('./util');
|
|
6
|
+
const {setRoute, createSign} = require('../deps/server')
|
|
5
7
|
const roomDataFile = "jsirRoom.json"
|
|
6
8
|
const roomsDirLockKey = "RW_" + getRoomsDir();
|
|
7
9
|
const syncRoomsLockKey = "SyncRooms_" + getRoomsDir();
|
|
@@ -14,6 +16,12 @@ const http = require('http');
|
|
|
14
16
|
let tailscalePath = os.platform() === 'darwin' ?
|
|
15
17
|
'/Applications/Tailscale.app/Contents/MacOS/Tailscale':'tailscale';
|
|
16
18
|
|
|
19
|
+
function debug(...args) {
|
|
20
|
+
if (global.$DEBUG) {
|
|
21
|
+
console.$log(debugStr('[debug]'), ...args);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
function isPidAlive(pid) {
|
|
18
26
|
try {
|
|
19
27
|
process.kill(Number(pid), 0); // 信号 0 不会实际发送,但会检查进程是否存在
|
|
@@ -22,7 +30,7 @@ function isPidAlive(pid) {
|
|
|
22
30
|
if (err.code === 'ESRCH') {
|
|
23
31
|
return false; // 进程不存在
|
|
24
32
|
}
|
|
25
|
-
|
|
33
|
+
debug(`check isPidAlive ${pid} failed`, err)
|
|
26
34
|
return false;
|
|
27
35
|
}
|
|
28
36
|
}
|
|
@@ -33,7 +41,7 @@ function onRoom() {
|
|
|
33
41
|
setRoute("post", "/", (req, res) => setting.selfRoom)
|
|
34
42
|
setRoute("get", "/", (req, res) => setting.selfRoom)
|
|
35
43
|
} catch (e) {
|
|
36
|
-
|
|
44
|
+
debug("initRoute failed", e)
|
|
37
45
|
}
|
|
38
46
|
_onRoom();
|
|
39
47
|
}
|
|
@@ -44,7 +52,7 @@ function _onRoom() {
|
|
|
44
52
|
try {
|
|
45
53
|
await initRoom();
|
|
46
54
|
} catch (e) {
|
|
47
|
-
|
|
55
|
+
debug('initRoom', e)
|
|
48
56
|
}
|
|
49
57
|
if (setting.roomTid[0]) {
|
|
50
58
|
_onRoom();
|
|
@@ -58,7 +66,7 @@ function offRoom() {
|
|
|
58
66
|
setting.roomTid[0] = null
|
|
59
67
|
if (setting.server) {
|
|
60
68
|
setting.server.close(() => {
|
|
61
|
-
|
|
69
|
+
debug('Existing server shut down.');
|
|
62
70
|
});
|
|
63
71
|
}
|
|
64
72
|
}
|
|
@@ -71,7 +79,6 @@ function getSelfIP(nodes) {
|
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
async function getTailscaleNodes() {
|
|
74
|
-
console.$log("getNodes")
|
|
75
82
|
let resp = await e(`${tailscalePath} status`);
|
|
76
83
|
let nodes = []
|
|
77
84
|
regEach(resp, /^(\d+\.\d+\.\d+\.\d+)\s+/mg, arr => {
|
|
@@ -88,34 +95,42 @@ async function enrichRoomInfo() {
|
|
|
88
95
|
let name = os.hostname();
|
|
89
96
|
if (!vl(room.name) || room.name !== name) {
|
|
90
97
|
room.name = name;
|
|
91
|
-
|
|
98
|
+
debug("set roomName", name)
|
|
92
99
|
}
|
|
93
100
|
room.selfNode = ip;
|
|
94
101
|
room.nodes = nodes;
|
|
95
102
|
room.lastUpdateTime = Date.now()
|
|
96
|
-
|
|
103
|
+
debug("init room", room.name)
|
|
104
|
+
|
|
105
|
+
// 提前设置一下
|
|
106
|
+
setting.selfRoom = Object.assign(setting.selfRoom || {}, room);
|
|
97
107
|
})
|
|
98
108
|
}
|
|
99
109
|
|
|
100
110
|
async function syncRooms() {
|
|
101
|
-
console.$log('syncRooms')
|
|
102
111
|
let roomsDir = getRoomsDir();
|
|
103
112
|
let room = await fileJson(roomDataFile)
|
|
104
113
|
|
|
105
114
|
let syncRooms = []
|
|
115
|
+
let fns = []
|
|
106
116
|
for (let node of room.nodes) {
|
|
107
117
|
if (node === room.selfNode) {
|
|
108
118
|
continue
|
|
109
119
|
}
|
|
110
|
-
|
|
111
|
-
let respBody =
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
120
|
+
fns.push(async () => {
|
|
121
|
+
let respBody = ''
|
|
122
|
+
try {
|
|
123
|
+
respBody = await reqNode(node, "get", "/");
|
|
124
|
+
syncRooms.push(JSON.parse(respBody))
|
|
125
|
+
debug(`sync ${node} success`);
|
|
126
|
+
} catch (e) {
|
|
127
|
+
debug(`sync ${node} failed:`, respBody, e);
|
|
128
|
+
}
|
|
129
|
+
})
|
|
116
130
|
}
|
|
131
|
+
await batchAsync(fns, 9, 3000);
|
|
117
132
|
await fileLock(roomsDirLockKey, async () => {
|
|
118
|
-
for (let syncRoom of syncRooms) {
|
|
133
|
+
for (let syncRoom of [...syncRooms]) {
|
|
119
134
|
if (syncRoom.selfNode) {
|
|
120
135
|
await fp.writeFile(roomsDir + "/" + syncRoom.selfNode, JSON.stringify(syncRoom, null, 2))
|
|
121
136
|
}
|
|
@@ -130,10 +145,11 @@ async function syncRooms() {
|
|
|
130
145
|
try {
|
|
131
146
|
await fp.unlink(roomsDir + '/' + file)
|
|
132
147
|
} catch (e) {
|
|
133
|
-
|
|
148
|
+
debug(e);
|
|
134
149
|
}
|
|
135
150
|
}
|
|
136
151
|
}
|
|
152
|
+
debug('syncRooms done')
|
|
137
153
|
}
|
|
138
154
|
|
|
139
155
|
async function syncSetting() {
|
|
@@ -143,7 +159,6 @@ async function syncSetting() {
|
|
|
143
159
|
|
|
144
160
|
async function _syncSetting(room) {
|
|
145
161
|
setting.selfRoom = room;
|
|
146
|
-
setting.selfRoom.local = true;
|
|
147
162
|
let roomDir = getRoomsDir();
|
|
148
163
|
let rooms = []
|
|
149
164
|
let files = await fp.readdir(roomDir);
|
|
@@ -184,7 +199,7 @@ async function initRoom() {
|
|
|
184
199
|
|
|
185
200
|
if (roomUpdateTouchTime) {
|
|
186
201
|
await fileLock(enrichRoomInfoLockKey, enrichRoomInfo, false)
|
|
187
|
-
|
|
202
|
+
fileLock(syncRoomsLockKey, syncRooms, false);
|
|
188
203
|
}
|
|
189
204
|
|
|
190
205
|
await syncSetting();
|
|
@@ -216,11 +231,6 @@ async function initRoomJsir(room) {
|
|
|
216
231
|
lastUpdateTime: Date.now(),
|
|
217
232
|
port: setting.server ? setting.server.address().port:null
|
|
218
233
|
}
|
|
219
|
-
console.$log("init jsir", process.pid)
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function isRunningInBackground() {
|
|
223
|
-
return !(process.stdout.isTTY && process.stdin.isTTY);
|
|
224
234
|
}
|
|
225
235
|
|
|
226
236
|
/**
|
|
@@ -295,12 +305,18 @@ function checkPortOpen(ip, port) {
|
|
|
295
305
|
});
|
|
296
306
|
}
|
|
297
307
|
|
|
308
|
+
function isDisableConnect(node, port) {
|
|
309
|
+
let disableTime = setting.disableConnect[node + ":" + port] || 0;
|
|
310
|
+
return disableTime > Date.now()
|
|
311
|
+
}
|
|
312
|
+
|
|
298
313
|
async function reqNode(node, method, url) {
|
|
299
314
|
let port = 52108;
|
|
300
315
|
let room = setting.rooms.filter(i => i.selfNode === node)[0]
|
|
301
316
|
if (room) {
|
|
302
317
|
let activeJsir = Object.values(room.jsirs)
|
|
303
|
-
.filter(i =>
|
|
318
|
+
.filter(i => !isDisableConnect(node, i.port))
|
|
319
|
+
.sort((a,b) => a.busy - b.busy);
|
|
304
320
|
if (activeJsir.length > 0) {
|
|
305
321
|
port = activeJsir[0].port;
|
|
306
322
|
}
|
|
@@ -310,8 +326,11 @@ async function reqNode(node, method, url) {
|
|
|
310
326
|
port: port, // HTTP 默认端口
|
|
311
327
|
path: url,
|
|
312
328
|
method: method.toUpperCase(),
|
|
329
|
+
headers: {
|
|
330
|
+
'sign': createSign()
|
|
331
|
+
}
|
|
313
332
|
};
|
|
314
|
-
|
|
333
|
+
debug('reqRoom', JSON.stringify(opt))
|
|
315
334
|
return await new Promise((resolve, reject) => {
|
|
316
335
|
const req = http.request(opt, (res) => {
|
|
317
336
|
let data = '';
|
|
@@ -327,6 +346,9 @@ async function reqNode(node, method, url) {
|
|
|
327
346
|
|
|
328
347
|
// 错误处理
|
|
329
348
|
req.on('error', (e) => {
|
|
349
|
+
if (room) {
|
|
350
|
+
setting.disableConnect[node + ":" + port] = Date.now() + 9000
|
|
351
|
+
}
|
|
330
352
|
reject(e)
|
|
331
353
|
});
|
|
332
354
|
|
package/deps/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const http = require('http');
|
|
2
|
-
const {createConsole, vl} = require('./util');
|
|
2
|
+
const {createConsole, vl, aesDecipher, md5, aesCipher, debugStr} = require('./util');
|
|
3
3
|
const console = createConsole();
|
|
4
4
|
const setting = require('../deps/setting')
|
|
5
5
|
// 尝试监听的端口
|
|
@@ -8,6 +8,30 @@ const preferredPort = 52108;
|
|
|
8
8
|
const routes = {};
|
|
9
9
|
let invokeStart = false;
|
|
10
10
|
|
|
11
|
+
function debug(...args) {
|
|
12
|
+
if (global.$DEBUG) {
|
|
13
|
+
console.$log(debugStr('[debug]'), ...args);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function verifySign(sign) {
|
|
18
|
+
try {
|
|
19
|
+
let key = md5([...setting.selfRoom.nodes].sort().join(":")).substring(0, 16);
|
|
20
|
+
return parseInt(aesDecipher(sign, key), 10); // 假设sign是base64编码的毫秒数
|
|
21
|
+
} catch (e) {
|
|
22
|
+
return null; // 解码失败返回null
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function createSign() {
|
|
27
|
+
try {
|
|
28
|
+
let key = md5([...setting.selfRoom.nodes].sort().join(":")).substring(0, 16);
|
|
29
|
+
return aesCipher(String(Date.now()), key)
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return null; // 解码失败返回null
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
11
35
|
// 创建一个 HTTP 服务
|
|
12
36
|
async function createServer(port) {
|
|
13
37
|
const server = http.createServer(async (req, res) => {
|
|
@@ -17,6 +41,26 @@ async function createServer(port) {
|
|
|
17
41
|
// 查找对应的路由处理函数
|
|
18
42
|
const routeKey = `${method} ${url}`;
|
|
19
43
|
if (routes[routeKey]) {
|
|
44
|
+
// 取header里的sign字段
|
|
45
|
+
const sign = req.headers['sign'];
|
|
46
|
+
if (sign) {
|
|
47
|
+
const decodedTime = verifySign(sign);
|
|
48
|
+
const currentTime = Date.now();
|
|
49
|
+
|
|
50
|
+
if (decodedTime === null || Math.abs(currentTime - decodedTime) > 3000) {
|
|
51
|
+
// 解码失败或者时间差大于9秒,返回403
|
|
52
|
+
res.writeHead(403, { 'Content-Type': 'text/plain' });
|
|
53
|
+
res.end('Forbidden: Invalid Sign\n');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
// 如果没有sign字段,返回403
|
|
58
|
+
res.writeHead(403, { 'Content-Type': 'text/plain' });
|
|
59
|
+
res.end('Forbidden: Missing Sign\n');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 如果签名通过,继续处理请求
|
|
20
64
|
await routes[routeKey](req, res);
|
|
21
65
|
} else {
|
|
22
66
|
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
@@ -27,11 +71,11 @@ async function createServer(port) {
|
|
|
27
71
|
return await new Promise((resolve, reject) => {
|
|
28
72
|
server.listen(port, () => {
|
|
29
73
|
const address = server.address();
|
|
30
|
-
|
|
74
|
+
debug(`Server listening on port ${address.port}`);
|
|
31
75
|
resolve(server)
|
|
32
76
|
});
|
|
33
77
|
server.on('error', (err) => {
|
|
34
|
-
|
|
78
|
+
debug(`Error occurred: ${err.message}`);
|
|
35
79
|
reject(err)
|
|
36
80
|
});
|
|
37
81
|
})
|
|
@@ -44,7 +88,7 @@ async function startServer() {
|
|
|
44
88
|
try {
|
|
45
89
|
setting.server = await createServer(preferredPort);
|
|
46
90
|
} catch (e) {
|
|
47
|
-
|
|
91
|
+
debug("startServer failed, try other port")
|
|
48
92
|
setting.server = await createServer(0);
|
|
49
93
|
}
|
|
50
94
|
}
|
|
@@ -62,14 +106,14 @@ function setRoute(method, url, fn, handler = jsonHandle) {
|
|
|
62
106
|
} else {
|
|
63
107
|
routes[routeKey] = fn;
|
|
64
108
|
}
|
|
65
|
-
|
|
109
|
+
debug(`AddRoute: ${method.toUpperCase()} ${url} ${handler ? handler.constructor.name:''}`);
|
|
66
110
|
return setting.server;
|
|
67
111
|
}
|
|
68
112
|
|
|
69
113
|
function delRoute(method, url) {
|
|
70
114
|
const routeKey = `${method.toLowerCase()} ${url}`;
|
|
71
115
|
delete routes[routeKey];
|
|
72
|
-
|
|
116
|
+
debug(`DelRoute: ${method.toUpperCase()} ${url}`);
|
|
73
117
|
}
|
|
74
118
|
|
|
75
119
|
function jsonHandle(req, res, fn) {
|
|
@@ -107,5 +151,6 @@ function jsonHandle(req, res, fn) {
|
|
|
107
151
|
module.exports = {
|
|
108
152
|
setRoute,
|
|
109
153
|
delRoute,
|
|
110
|
-
jsonHandle
|
|
154
|
+
jsonHandle,
|
|
155
|
+
createSign
|
|
111
156
|
};
|
package/deps/setting.js
CHANGED
package/deps/util.js
CHANGED
|
@@ -14,6 +14,7 @@ const initModulePaths = Object.assign([], module.paths)
|
|
|
14
14
|
const path = require('path')
|
|
15
15
|
const _types = setting.fileType
|
|
16
16
|
const _typeKeys = Object.keys(_types)
|
|
17
|
+
const util = require('util')
|
|
17
18
|
|
|
18
19
|
global.$newInput = false
|
|
19
20
|
global.$newError = false
|
|
@@ -26,6 +27,37 @@ let configDir;
|
|
|
26
27
|
let roomsDir;
|
|
27
28
|
let dataDir;
|
|
28
29
|
|
|
30
|
+
|
|
31
|
+
function isRunningInBackground() {
|
|
32
|
+
return !(process.stdout.isTTY && process.stdin.isTTY);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 模拟 console.log 的输出字符串,返回打印的完整字符串
|
|
37
|
+
* @param {...any} args - 传入的参数
|
|
38
|
+
* @returns {string} - 返回最终打印的完整字符串
|
|
39
|
+
*/
|
|
40
|
+
function consoleStrs(...args) {
|
|
41
|
+
// 如果没有参数,返回空字符串
|
|
42
|
+
if (args.length === 0) {
|
|
43
|
+
return '';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 格式化第一个参数
|
|
47
|
+
if (typeof args[0] === 'string') {
|
|
48
|
+
return util.format(...args); // 处理格式化字符串 (%s, %d 等)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 如果第一个参数不是字符串,直接用空格拼接其他参数的字符串化结果
|
|
52
|
+
return args
|
|
53
|
+
.map((arg) =>
|
|
54
|
+
typeof arg !== 'string'
|
|
55
|
+
? util.inspect(arg, { depth: 2, colors: true }) // 对象序列化
|
|
56
|
+
: String(arg) // 其他类型转为字符串
|
|
57
|
+
)
|
|
58
|
+
.join(' ');
|
|
59
|
+
}
|
|
60
|
+
|
|
29
61
|
class SyncQueue {
|
|
30
62
|
constructor() {
|
|
31
63
|
this.queue = [];
|
|
@@ -135,15 +167,15 @@ function dealLevelArgs(levelStrFn, args) {
|
|
|
135
167
|
if (args.length <= 0) {
|
|
136
168
|
return args;
|
|
137
169
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
170
|
+
let text = consoleStrs(...args)
|
|
171
|
+
if (typeof args[0] === "string" && args[0].trim() && text.startsWith(args[0])) {
|
|
172
|
+
if(text.length === args[0].length) {
|
|
173
|
+
text = levelStrFn(args[0])
|
|
174
|
+
} else {
|
|
175
|
+
text = levelStrFn(args[0]) + ' ' + consoleStrs(...args.slice(1))
|
|
176
|
+
}
|
|
144
177
|
}
|
|
145
|
-
|
|
146
|
-
return args
|
|
178
|
+
return text;
|
|
147
179
|
}
|
|
148
180
|
|
|
149
181
|
const _console =Object.assign({}, global.console);
|
|
@@ -162,23 +194,23 @@ const _consoleFns= {
|
|
|
162
194
|
},
|
|
163
195
|
info: {
|
|
164
196
|
fn: _console.info,
|
|
165
|
-
args: args => [infoStr('[info]'),
|
|
197
|
+
args: args => [infoStr('[info]'), dealLevelArgs(infoStr, args)]
|
|
166
198
|
},
|
|
167
199
|
msg: {
|
|
168
200
|
fn: _console.log,
|
|
169
|
-
args: args => [msgStr('[msg]'),
|
|
201
|
+
args: args => [msgStr('[msg]'), dealLevelArgs(msgStr, args)]
|
|
170
202
|
},
|
|
171
203
|
warn: {
|
|
172
204
|
fn: _console.warn,
|
|
173
|
-
args: args => [warnStr('[warn]'),
|
|
205
|
+
args: args => [warnStr('[warn]'), dealLevelArgs(warnStr, args)],
|
|
174
206
|
},
|
|
175
207
|
error: {
|
|
176
208
|
fn: _console.error,
|
|
177
|
-
args: args => [errorStr('[error]'),
|
|
209
|
+
args: args => [errorStr('[error]'), dealLevelArgs(errorStr, args)]
|
|
178
210
|
},
|
|
179
211
|
debug: {
|
|
180
212
|
fn: _console.debug,
|
|
181
|
-
args: args => [debugStr('[debug]'),
|
|
213
|
+
args: args => [debugStr('[debug]'), dealLevelArgs(debugStr, args)]
|
|
182
214
|
}
|
|
183
215
|
}
|
|
184
216
|
|
|
@@ -224,7 +256,7 @@ function createConsole(uniqueName) {
|
|
|
224
256
|
if ('debug' === key && !global.$DEBUG) {
|
|
225
257
|
return;
|
|
226
258
|
}
|
|
227
|
-
if (uniqueName && quite) {
|
|
259
|
+
if (isRunningInBackground() || (uniqueName && quite)) {
|
|
228
260
|
if ((key === 'table' || key === 'nable') && typeof args[0] === "object") {
|
|
229
261
|
args = ['', ...args]
|
|
230
262
|
}
|
|
@@ -578,7 +610,9 @@ function randomInt(min,max){
|
|
|
578
610
|
}
|
|
579
611
|
|
|
580
612
|
async function timeLimit(proms, mills) {
|
|
581
|
-
let
|
|
613
|
+
let tIds = []
|
|
614
|
+
let result = await Promise.race([Promise.all(proms), sleep(mills, tIds)])
|
|
615
|
+
clearTimeout(tIds[0])
|
|
582
616
|
if (!result) {
|
|
583
617
|
throw new Error(`timeLimit: exceed ${mills} ms`)
|
|
584
618
|
}
|
|
@@ -660,16 +694,15 @@ function createLimitLogger(fileName, {
|
|
|
660
694
|
if (args.length <= 0) {
|
|
661
695
|
return
|
|
662
696
|
}
|
|
663
|
-
// 处理参数
|
|
664
|
-
args = args.map(i => isError(i) ? errorStack(i):i);
|
|
665
697
|
|
|
666
698
|
// 处理同步函数
|
|
667
699
|
syncLogs.forEach(i => i(...args));
|
|
668
700
|
|
|
669
|
-
let text = args
|
|
701
|
+
let text = consoleStrs(...args)
|
|
670
702
|
if (error) {
|
|
671
703
|
global.$newError = true;
|
|
672
704
|
}
|
|
705
|
+
text = `${pad(3, String(process.pid%1000), ' ')}> ${text}`
|
|
673
706
|
if (time) {
|
|
674
707
|
text = `${timeStr('YYYY-MM-DD HH:mm:ss.SSS')} ${text}`
|
|
675
708
|
}
|
|
@@ -700,10 +733,10 @@ function getInitName(fileName) {
|
|
|
700
733
|
fileName = trim(fileName)
|
|
701
734
|
let homeDir = setting.workspaceMap[setting.defaultSpace]
|
|
702
735
|
if (!fileName.startsWith("/")) {
|
|
703
|
-
fileName
|
|
704
|
-
|
|
705
|
-
fileName = fileName + '.js'
|
|
736
|
+
if (getJsirTypeKey(fileName) !== setting.initKey) {
|
|
737
|
+
fileName = setting.initKey + ' ' + fileName
|
|
706
738
|
}
|
|
739
|
+
fileName = toJsirFileName(fileName)
|
|
707
740
|
fileName = homeDir + '/' + fileName
|
|
708
741
|
}
|
|
709
742
|
return fileName;
|
|
@@ -768,7 +801,7 @@ async function fileJson(key, fn = null, fmt = true, safeMs = 49000) {
|
|
|
768
801
|
let fileName = trim(key)
|
|
769
802
|
let path = dataDir + "/" + fileName;
|
|
770
803
|
let homeDir = setting.workspaceMap[setting.defaultSpace]
|
|
771
|
-
let isInit = fileName
|
|
804
|
+
let isInit = getJsirTypeKey(fileName) === setting.initKey;
|
|
772
805
|
if (isInit) {
|
|
773
806
|
path = homeDir + '/' + toJsirFileName(fileName);
|
|
774
807
|
}
|
|
@@ -868,7 +901,7 @@ function aesCipher(str, key){
|
|
|
868
901
|
const cipher = crypto.createCipheriv('aes-128-ecb', pad(key, 16, '0'), null);
|
|
869
902
|
return cipher.update(str, 'utf8', 'hex') + cipher.final('hex');
|
|
870
903
|
} catch(err) {
|
|
871
|
-
$
|
|
904
|
+
$log(err)
|
|
872
905
|
throw 'aesCipher failed: ' + String(err)
|
|
873
906
|
}
|
|
874
907
|
}
|
|
@@ -885,7 +918,7 @@ function aesDecipher(str, key){
|
|
|
885
918
|
const decipher = crypto.createDecipheriv('aes-128-ecb', pad(key, 16, '0'), null);
|
|
886
919
|
return decipher.update(str, 'hex', 'utf8') + decipher.final('utf8');
|
|
887
920
|
} catch(err) {
|
|
888
|
-
$
|
|
921
|
+
$log(err)
|
|
889
922
|
throw 'aesDecipher failed: ' + String(err)
|
|
890
923
|
}
|
|
891
924
|
}
|
|
@@ -1215,6 +1248,9 @@ function setTips(key, value, onRm) {
|
|
|
1215
1248
|
function delTips(...keys) {
|
|
1216
1249
|
for (let key of Object.keys(setting.tips)) {
|
|
1217
1250
|
if (keys.length === 0) {
|
|
1251
|
+
if (key === 'DEBUG') {
|
|
1252
|
+
continue
|
|
1253
|
+
}
|
|
1218
1254
|
delete setting.tips[key]
|
|
1219
1255
|
tipsOnRmCallback(key)
|
|
1220
1256
|
} else if (keys.indexOf(key) !== -1) {
|
|
@@ -1224,6 +1260,9 @@ function delTips(...keys) {
|
|
|
1224
1260
|
}
|
|
1225
1261
|
if (keys.length === 0) {
|
|
1226
1262
|
for (let key of Object.keys(_tipsOnRm)) {
|
|
1263
|
+
if (key === 'DEBUG') {
|
|
1264
|
+
continue
|
|
1265
|
+
}
|
|
1227
1266
|
tipsOnRmCallback(key)
|
|
1228
1267
|
}
|
|
1229
1268
|
}
|
|
@@ -1519,8 +1558,10 @@ async function setCbText(str) {
|
|
|
1519
1558
|
fs.unlinkSync(copyFile)
|
|
1520
1559
|
}
|
|
1521
1560
|
|
|
1522
|
-
async function sleep(milliseconds) {
|
|
1523
|
-
return new Promise(resolve =>
|
|
1561
|
+
async function sleep(milliseconds, tIds = []) {
|
|
1562
|
+
return new Promise(resolve => {
|
|
1563
|
+
tIds.push(setTimeout(resolve, milliseconds))
|
|
1564
|
+
});
|
|
1524
1565
|
}
|
|
1525
1566
|
|
|
1526
1567
|
function splitArray(items, size) {
|
|
@@ -1813,7 +1854,7 @@ function md5(message) {
|
|
|
1813
1854
|
return crypto.createHash('md5').update(message).digest('hex');
|
|
1814
1855
|
}
|
|
1815
1856
|
|
|
1816
|
-
async function batchAsync(fns = [], asyncNum = 1) {
|
|
1857
|
+
async function batchAsync(fns = [], asyncNum = 1, limitMs = 9000) {
|
|
1817
1858
|
if (fns.length <= 0 || asyncNum < 1) {
|
|
1818
1859
|
return []
|
|
1819
1860
|
}
|
|
@@ -1823,9 +1864,9 @@ async function batchAsync(fns = [], asyncNum = 1) {
|
|
|
1823
1864
|
for(let i = 0; i< fns.length; i++) {
|
|
1824
1865
|
let pro = new Promise(async (resolve, reject) => {
|
|
1825
1866
|
try {
|
|
1826
|
-
let resp = await fns[i]();
|
|
1867
|
+
let resp = await timeLimit([fns[i]()], limitMs);
|
|
1827
1868
|
doneMap[i] = pro;
|
|
1828
|
-
resolve(resp)
|
|
1869
|
+
resolve(resp[0])
|
|
1829
1870
|
} catch (e) {
|
|
1830
1871
|
doneMap[i] = pro;
|
|
1831
1872
|
resolve(isError(e) ? e:new Error(e));
|
|
@@ -1931,8 +1972,8 @@ function getTextComments(text) {
|
|
|
1931
1972
|
|
|
1932
1973
|
function wrapperJsirText(text) {
|
|
1933
1974
|
return text
|
|
1934
|
-
.replace(/^require\s*\(\s*(["'`][ei]
|
|
1935
|
-
.replace(/([\s=;])require\s*\(\s*(["'`][ei]
|
|
1975
|
+
.replace(/^require\s*\(\s*(["'`][ei][^a-zA-Z]+)/mg, 'await $require($2')
|
|
1976
|
+
.replace(/([\s=;])require\s*\(\s*(["'`][ei][^a-zA-Z]+)/g, '$1await $require($2')
|
|
1936
1977
|
.replace(/([\s=;])import\s*\(/g, '$1$import(')
|
|
1937
1978
|
.replace(/^import\s*\(/mg, '$import(')
|
|
1938
1979
|
.replace(/^module\.exports\s*=\s*/m, 'return ')
|
|
@@ -1980,6 +2021,10 @@ function getValTips() {
|
|
|
1980
2021
|
return items
|
|
1981
2022
|
}
|
|
1982
2023
|
|
|
2024
|
+
function getJsirTypeKey(fileName) {
|
|
2025
|
+
return fileName.split(/[^a-zA-Z]+/)[0] || ''
|
|
2026
|
+
}
|
|
2027
|
+
|
|
1983
2028
|
module.exports = {
|
|
1984
2029
|
wrapperJsirText,
|
|
1985
2030
|
run,
|
|
@@ -2084,5 +2129,7 @@ module.exports = {
|
|
|
2084
2129
|
getKeyTips,
|
|
2085
2130
|
getValTips,
|
|
2086
2131
|
getRoomsDir,
|
|
2087
|
-
getDataDir
|
|
2132
|
+
getDataDir,
|
|
2133
|
+
getJsirTypeKey,
|
|
2134
|
+
isRunningInBackground
|
|
2088
2135
|
}
|