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 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, getRoomsDir
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
- if (args[0].startsWith(setting.exeKey)) {
440
+ let typeKey = getJsirTypeKey(args[0]);
441
+ if (typeKey === setting.exeKey) {
441
442
  resp = example.exeFile;
442
- } else if (args[0].startsWith(setting.initKey)) {
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.split(/\s+/)[0]);
502
- let orderB = typeKeys.indexOf(b.split(/\s+/)[0]);
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.substring(0, 1)] || setting.defaultType, suffix].map(trim).join(".")
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.substring(0, 1)
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
- for (let i = 0; i < setting.rooms.length; i++) {
1412
- let room = setting.rooms[i]
1413
- results.push({
1414
- mid: i,
1415
- name: (room.local ? "*":" ") + room.name,
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
- console.warn("no items")
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].startsWith(setting.exeKey))
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 && !parseUniqueName(uniqueName)[1].startsWith(setting.exeKey)) {
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].startsWith(setting.initKey))
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
- if (pair[1].startsWith(setting.initKey)) {
2059
+ let typeKey = getJsirTypeKey(pair[1]);
2060
+ if (typeKey === setting.initKey) {
2046
2061
  result = await evalText(text, uniqueName)
2047
- } else if (pair[1].startsWith(setting.exeKey)) {
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
- return await eval(`(async ()=>{${$text};
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} = require('./util');
4
- const {setRoute} = require('../deps/server')
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
- console.$error(`check isPidAlive ${pid} failed`, err)
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
- console.$error("initRoute failed", e)
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
- console.$error('initRoom', e)
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
- console.$log('Existing server shut down.');
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
- console.$log("set roomName", name)
98
+ debug("set roomName", name)
92
99
  }
93
100
  room.selfNode = ip;
94
101
  room.nodes = nodes;
95
102
  room.lastUpdateTime = Date.now()
96
- console.$log("init room", room.name)
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
- try {
111
- let respBody = await reqNode(node, "get", "/");
112
- syncRooms.push(JSON.parse(respBody))
113
- } catch (e) {
114
- console.$log(`sync ${node} failed`, e);
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
- console.$error(e);
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
- await fileLock(syncRoomsLockKey, syncRooms, false);
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 => i.active).sort((a,b) => a.busy - b.busy);
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
- console.$log('reqRoom', JSON.stringify(opt))
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
- console.$log(`Server listening on port ${address.port}`);
74
+ debug(`Server listening on port ${address.port}`);
31
75
  resolve(server)
32
76
  });
33
77
  server.on('error', (err) => {
34
- console.$log(`Error occurred: ${err.message}`);
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
- console.$log("startServer failed, try other port")
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
- console.$log(`AddRoute: ${method.toUpperCase()} ${url} ${handler ? handler.constructor.name:''}`);
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
- console.$log(`DelRoute: ${method.toUpperCase()} ${url}`);
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
@@ -26,5 +26,6 @@ module.exports = {
26
26
  roomTid: [],
27
27
  selfRoom: {},
28
28
  rooms: [],
29
- server: null
29
+ server: null,
30
+ disableConnect: {}
30
31
  }
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
- if (typeof args[0] !== 'string') {
139
- return args;
140
- }
141
- let ss = args[0].split("\n");
142
- if (ss[0]) {
143
- ss[0] = levelStrFn(ss[0])
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
- args[0] = ss.join("\n");
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]'), ...dealLevelArgs(infoStr, args)]
197
+ args: args => [infoStr('[info]'), dealLevelArgs(infoStr, args)]
166
198
  },
167
199
  msg: {
168
200
  fn: _console.log,
169
- args: args => [msgStr('[msg]'), ...dealLevelArgs(msgStr, args)]
201
+ args: args => [msgStr('[msg]'), dealLevelArgs(msgStr, args)]
170
202
  },
171
203
  warn: {
172
204
  fn: _console.warn,
173
- args: args => [warnStr('[warn]'), ...dealLevelArgs(warnStr, args)],
205
+ args: args => [warnStr('[warn]'), dealLevelArgs(warnStr, args)],
174
206
  },
175
207
  error: {
176
208
  fn: _console.error,
177
- args: args => [errorStr('[error]'), ...dealLevelArgs(errorStr, args)]
209
+ args: args => [errorStr('[error]'), dealLevelArgs(errorStr, args)]
178
210
  },
179
211
  debug: {
180
212
  fn: _console.debug,
181
- args: args => [debugStr('[debug]'), ...dealLevelArgs(debugStr, args)]
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 result = await Promise.race([Promise.all(proms), sleep(mills)])
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.join(" ")
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 = setting.initKey + ' ' + fileName.replace(new RegExp(`^${setting.initKey}\\s+`), '')
704
- if (!/\..+/.test(fileName)) {
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.startsWith(setting.initKey);
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
- $error(err)
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
- $error(err)
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 => setTimeout(resolve, milliseconds));
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]\s+)/mg, 'await $require($2')
1935
- .replace(/([\s=;])require\s*\(\s*(["'`][ei]\s+)/g, '$1await $require($2')
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsir",
3
- "version": "2.3.8",
3
+ "version": "2.4.0",
4
4
  "description": "JavaScript Script Management Tool",
5
5
  "main": "index.js",
6
6
  "scripts": {