jsir 2.6.14 → 3.0.1

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
@@ -13,7 +13,8 @@ const {
13
13
  getFullPath, parseUniqueName, toUniqueName, isJsirFileName, toJsirFileName,
14
14
  getAlias, wrapperJsirText, eia, getKeyTips, getValTips, getJsirTypeKey,
15
15
  createDetachedProcess, interceptStdStreams,
16
- draftModify, isRunningInBackground, fileJson, fileLock, processLock, cleanFileLocks, getMd5Key, terminalTitle
16
+ draftModify, isRunningInBackground, fileJson, fileLock, processLock, cleanFileLocks, getMd5Key, terminalTitle,
17
+ getFileOpenExe, formatSec, formatMb
17
18
  } = $lib;
18
19
  const _args = process.argv.slice(2).map(trim);
19
20
  const evalCode = require('../deps/evalCode')
@@ -164,20 +165,6 @@ const $data = {
164
165
  }
165
166
  const $homeDir = getLibDataDir()
166
167
 
167
- function getFileOpenExe(fileName) {
168
- fileName = trim(fileName);
169
- let strs = fileName.split('.')
170
- let suffix = ''
171
- if (strs.length > 1) {
172
- suffix = strs[strs.length - 1]
173
- }
174
- let defaultExe = getConfig("defaultExe", "open");
175
- if (!suffix) {
176
- return defaultExe
177
- }
178
- return getConfig(`${suffix}_exe`, defaultExe);
179
- }
180
-
181
168
  function checkWorkspaces() {
182
169
  let localWorkspace = _libDataDir + '/local';
183
170
  setting.workspaceMap = {
@@ -280,7 +267,7 @@ async function watchFile(uniqueName) {
280
267
  closeFileWatcher(workFilePath);
281
268
  });
282
269
  }
283
- await e(`"${getFileOpenExe(parseUniqueName(uniqueName)[1])}" "${workFilePath}"`)
270
+ await eia(getFileOpenExe(), [`"${workFilePath}"`], true)
284
271
  }
285
272
 
286
273
  function getExeStr(oldText, newText) {
@@ -332,8 +319,8 @@ function getExeStr(oldText, newText) {
332
319
  }
333
320
 
334
321
  async function nextLine(callback, promptStr, hidden) {
335
- return new Promise(resolve => {
336
- _nextLine(callback, promptStr, hidden, resolve)
322
+ return new Promise((resolve, reject) => {
323
+ _nextLine(callback, promptStr, hidden, resolve, reject)
337
324
  })
338
325
  }
339
326
 
@@ -343,14 +330,18 @@ function defaultPromptStr(showKey = false) {
343
330
  return tips;
344
331
  }
345
332
 
346
- function initRl(callback, promptStr, hidden) {
333
+ function initRl(callback, promptStr, hidden, reject) {
347
334
  let origin_writeToOutput;
348
335
  if (!_rl) {
349
336
  _rl = readline.createInterface({
350
337
  input: process.stdin,
351
- output: process.stdout
338
+ output: process.stdout,
339
+ historySize: 1000
352
340
  })
353
341
  _rl.on("SIGINT", async () => {
342
+ if (callback !== wrapperInput) {
343
+ reject('Terminal Interrupt');
344
+ }
354
345
  if (_noAppendNextLine) {
355
346
  setting.promptId = Date.now();
356
347
  await delTips();
@@ -358,7 +349,11 @@ function initRl(callback, promptStr, hidden) {
358
349
  _rl._writeToOutput = origin_writeToOutput;
359
350
  _haveWrapperInput = true;
360
351
  _rl.clearLine(0)
361
- nextLine();
352
+ if (callback === wrapperInput) {
353
+ nextLine();
354
+ } else {
355
+ closeRl()
356
+ }
362
357
  }
363
358
  });
364
359
  _rl.history = _rlHistory
@@ -408,19 +403,19 @@ function closeRl() {
408
403
  _rl = null;
409
404
  }
410
405
 
411
- function _nextLine(callback, promptStr, hidden, resolve, end, isText) {
406
+ function _nextLine(callback, promptStr, hidden, resolve, reject, end, isText) {
412
407
  callback = callback || wrapperInput;
413
408
  if (!setting.enableNextLine) {
414
- console.$log(warnStr("[warn]"), "NextLine Disabled");
409
+ console.$warn("NextLine Disabled");
415
410
  resolve(null);
416
411
  return;
417
412
  }
418
413
  if (!_haveWrapperInput) {
419
- console.$error(errorStr("[error]"), "NextLine Blocked");
414
+ console.$error("NextLine Blocked");
420
415
  resolve(null);
421
416
  return;
422
417
  }
423
- initRl(callback, promptStr, hidden);
418
+ initRl(callback, promptStr, hidden, reject);
424
419
  if (callback !== wrapperInput) {
425
420
  _haveWrapperInput = false
426
421
  }
@@ -439,7 +434,7 @@ function _nextLine(callback, promptStr, hidden, resolve, end, isText) {
439
434
  } else {
440
435
  inputs.push(line)
441
436
  }
442
- if (trim(textLine) && (hidden || callback !== wrapperInput)) {
437
+ if (trim(textLine) && (hidden || isText)) {
443
438
  _rl.history = _rl.history.slice(1)
444
439
  }
445
440
  if (!isText || line === end) {
@@ -473,13 +468,13 @@ function _nextLine(callback, promptStr, hidden, resolve, end, isText) {
473
468
  _rl.prompt()
474
469
  if (callback === wrapperInput) {
475
470
  setting.promptId = Date.now();
471
+ setting.lastOutput = null;
476
472
  }
477
- setting.lastOutput = null;
478
473
  }
479
474
 
480
475
  async function nextText(callback, end, hidden) {
481
- return new Promise(resolve => {
482
- _nextLine(callback, '', hidden, resolve, end, true)
476
+ return new Promise((resolve, reject) => {
477
+ _nextLine(callback, '', hidden, resolve, reject, end, true)
483
478
  })
484
479
  }
485
480
 
@@ -755,7 +750,7 @@ async function execLibFn(fn, fnArgs) {
755
750
 
756
751
  async function joinServer(uniqueName, isApi, exportLib) {
757
752
  if (!setting.serviceReg.test(uniqueName)) {
758
- throw 'invalid service name';
753
+ return;
759
754
  }
760
755
  let asyncFnSize = 0
761
756
  for (let key of Object.keys(exportLib)) {
@@ -785,7 +780,7 @@ async function joinServer(uniqueName, isApi, exportLib) {
785
780
 
786
781
  async function offServer(uniqueName) {
787
782
  if (!setting.serviceReg.test(uniqueName)) {
788
- throw 'invalid service name';
783
+ return;
789
784
  }
790
785
  let pair = parseUniqueName(uniqueName)
791
786
  let service = `${pair[0]}/${trimJsirFileName(pair[1])}`;
@@ -1044,29 +1039,6 @@ function help(filterFn) {
1044
1039
  }))
1045
1040
  }
1046
1041
 
1047
- function delTipsByIndex(idxs) {
1048
- let keys = Object.keys(setting.tips)
1049
- let indexKeyMap = {}
1050
- for(let i = 1;i<=keys.length;i++) {
1051
- indexKeyMap[i] = keys[i - 1]
1052
- }
1053
- let params = []
1054
- for (const index of idxs) {
1055
- if (setting.tips.hasOwnProperty(index)) {
1056
- params.push(index)
1057
- } else if (indexKeyMap[Number(index)]) {
1058
- params.push(indexKeyMap[Number(index)])
1059
- } else if (indexKeyMap[keys.length + 1 + Number(index)]) {
1060
- params.push(indexKeyMap[keys.length + 1 + Number(index)])
1061
- }
1062
- }
1063
- if (idxs.length > 0 && params.length <= 0) {
1064
- console.warn("no items")
1065
- return;
1066
- }
1067
- return delTips(...params)
1068
- }
1069
-
1070
1042
  function getPackageVersion(space, name) {
1071
1043
  let moduleDir = setting.workspaceMap[space] + '/node_modules'
1072
1044
  let dir = moduleDir + "/" + name;
@@ -1158,26 +1130,28 @@ async function showRooms() {
1158
1130
  for (let i = 0; i < setting.rooms.length; i++) {
1159
1131
  let room = setting.rooms[i]
1160
1132
  let isLocal = setting.selfRoom.selfNode === room.selfNode;
1133
+ let roomName = room.active ? infoStr(room.name):room.name;
1134
+ let delayStr = vl(room.delay) ? (room.delay + "ms"):"";
1161
1135
  results.push({
1162
- name: (isLocal ? "*" : " ") + room.name,
1136
+ name: (isLocal ? infoStr("*") : " ") + roomName,
1163
1137
  node: room.selfNode,
1164
- active: room.active,
1138
+ delay: delayStr
1165
1139
  })
1166
1140
  for (let key of Object.keys(room.jsirs)) {
1167
1141
  let jsir = room.jsirs[key]
1168
- let pidStr = (process.pid === jsir.pid ? "*" : " ") + jsir.pid;
1142
+ let pidStr = (process.pid === jsir.pid ? infoStr("*") : " ") + (jsir.newError ? errorStr(jsir.pid):(jsir.active ? infoStr(jsir.pid):jsir.pid));
1169
1143
  results.push({
1170
- name: (isLocal ? "*" : " ") + room.name,
1144
+ name: (isLocal ? infoStr("*") : " ") + roomName,
1171
1145
  node: room.selfNode,
1172
- active: room.active,
1173
- pid: jsir.newError ? errorStr(pidStr):pidStr,
1174
- up: jsir.upTime || '',
1146
+ delay: delayStr,
1147
+ pid: pidStr,
1148
+ up: formatSec(jsir.upTime) || '',
1175
1149
  version: jsir.version || '',
1176
1150
  space: jsir.space,
1177
- running: jsir.active,
1178
1151
  port: jsir.port,
1179
1152
  back: jsir.back,
1180
1153
  busy: jsir.busy,
1154
+ mem: formatMb(jsir.mem) || '',
1181
1155
  tips: Object.keys(jsir.tips).map(i => infoStr(i) + ': ' + jsir.tips[i]).join('\n'),
1182
1156
  services: Object.keys(jsir.services || []).map(msgStr).join('\n')
1183
1157
  });
@@ -1211,7 +1185,24 @@ const keywordDef = {
1211
1185
  clear: {
1212
1186
  comment: 'Clear task',
1213
1187
  exeFn: async (args) => {
1214
- await delTipsByIndex(args.filter(i => i))
1188
+ if (args.length > 0 && _cmdMap[args[0]]) {
1189
+ let cmdName = _cmdMap[args[0]];
1190
+ if (args.length === 1) {
1191
+ $data.del(cmdName)
1192
+ } else {
1193
+ let metadata = $data.get(cmdName);
1194
+ if (!vl(metadata) || typeof metadata !== 'object') {
1195
+ return;
1196
+ }
1197
+ for (let key of args.slice(1)) {
1198
+ if (metadata.hasOwnProperty(key)) {
1199
+ delete metadata[key]
1200
+ }
1201
+ }
1202
+ }
1203
+ } else {
1204
+ await delTips(...args)
1205
+ }
1215
1206
  },
1216
1207
  args: {
1217
1208
  tipIndex: 'left prompt index, can be separated by spaces for multiple'
@@ -1303,7 +1294,7 @@ const keywordDef = {
1303
1294
  console.warn("no items")
1304
1295
  } else {
1305
1296
  let path = getFullPath(uniqueName)
1306
- await eia(getEditor(), [path])
1297
+ await eia(getEditor(), [`"${path}"`], true)
1307
1298
  }
1308
1299
  },
1309
1300
  args: {
@@ -1332,12 +1323,22 @@ const keywordDef = {
1332
1323
  console.msg("config service offline")
1333
1324
  } else if (_cmdMap[args[0]]){
1334
1325
  let uniqueName = _cmdMap[args[0]];
1335
- await eia(getEditor(), [`${getConfigDir()}/${md5(uniqueName + (global.$TEST ? '.test':''))}.json`])
1326
+ let configPath = `${getConfigDir()}/${md5(uniqueName + (global.$TEST ? '.test':''))}.json`;
1327
+ if (isRunningInBackground()) {
1328
+ console.log(String(await fp.readFile(configPath)).trim())
1329
+ } else {
1330
+ await eia(getEditor(), [`"${configPath}"`], true)
1331
+ }
1336
1332
  } else {
1337
1333
  console.warn('invalid args')
1338
1334
  }
1339
1335
  } else {
1340
- await eia(getEditor(), [`${getLibDataDir()}/config.json`])
1336
+ let configPath = `${getLibDataDir()}/config.json`;
1337
+ if (isRunningInBackground()) {
1338
+ console.log(String(await fp.readFile(configPath)).trim())
1339
+ } else {
1340
+ await eia(getEditor(), [`"${configPath}"`], true)
1341
+ }
1341
1342
  }
1342
1343
  },
1343
1344
  short: 's'
@@ -1349,18 +1350,24 @@ const keywordDef = {
1349
1350
  if (!uniqueName) {
1350
1351
  console.warn("no items")
1351
1352
  } else {
1352
- let path = getFullPath(uniqueName)
1353
- if (!fs.existsSync(path)) {
1354
- let cmds = filterCmd(uniqueName);
1355
- if (cmds.length === 1) {
1356
- uniqueName = cmds[0];
1357
- path = getFullPath(cmds[0])
1358
- } else {
1359
- console.warn("no items")
1360
- return;
1353
+ let names = [uniqueName]
1354
+ if (uniqueName === 'ALL') {
1355
+ names = Object.values(_cmdMap)
1356
+ }
1357
+ for (let uniqueName of names) {
1358
+ let path = getFullPath(uniqueName)
1359
+ if (!fs.existsSync(path)) {
1360
+ let cmds = filterCmd(uniqueName);
1361
+ if (cmds.length === 1) {
1362
+ uniqueName = cmds[0];
1363
+ path = getFullPath(cmds[0])
1364
+ } else {
1365
+ console.warn("no items")
1366
+ return;
1367
+ }
1361
1368
  }
1369
+ await eia(getFileOpenExe(), [`"${path}"`], true)
1362
1370
  }
1363
- await e(`"${getFileOpenExe(parseUniqueName(uniqueName)[1])}" "${path}"`)
1364
1371
  }
1365
1372
  },
1366
1373
  args: {
@@ -1377,7 +1384,7 @@ const keywordDef = {
1377
1384
  let bSpace = args[1]
1378
1385
 
1379
1386
  if (aUniqueName && bUniqueName) {
1380
- let result = await e(`${getConfig("compareExe", "diff")} "${getFullPath(aUniqueName)}" "${getFullPath(bUniqueName)}"`)
1387
+ let result = await eia(getConfig("compareExe", "diff"), [`"${getFullPath(aUniqueName)}"`, `"${getFullPath(bUniqueName)}"`], true)
1381
1388
  if (result) {
1382
1389
  console.log(result)
1383
1390
  }
@@ -1709,6 +1716,10 @@ const keywordDef = {
1709
1716
  if (setting.selfRoom.selfNode === room.selfNode && String(process.pid) === pid) {
1710
1717
  continue;
1711
1718
  }
1719
+ if (setting.selfRoom.selfNode !== room.selfNode && args.includes(room.selfNode) && !args.includes(pid)
1720
+ && room.jsirs[pid].port === setting.defaultPort) {
1721
+ continue;
1722
+ }
1712
1723
  have = true;
1713
1724
  tasks.push(async (input) => {
1714
1725
  let jsir = room.jsirs[pid];
@@ -1907,26 +1918,36 @@ function getComments(i, cmdName, text, cols = [], col) {
1907
1918
  let docLines = [getMd5Key(parseUniqueName(cmdName)[1]) + " - " + i]
1908
1919
  text = trim(text)
1909
1920
  docLines.push(...getTextComments(text))
1910
- let argDef = getArgDef(text, cmdName)
1911
- let comments = getArgComments(argDef, true)
1912
- if (comments) {
1913
- docLines.push(...comments)
1914
- }
1915
- if (docLines.length > 0) {
1916
- col.doc = '- ' + docLines[0]
1917
- if (docLines.length > 1) {
1918
- cols.push({
1919
- doc: ' ' + infoStr(docLines[1])
1920
- })
1921
- if (docLines.length > 2) {
1922
- for (let line of docLines.slice(2)) {
1923
- cols.push({
1924
- doc: ' ' + line
1925
- })
1926
- }
1921
+ col.doc = '- ' + docLines[0]
1922
+ if (docLines.length > 1) {
1923
+ cols.push({
1924
+ doc: ' ' + infoStr(docLines[1])
1925
+ })
1926
+ if (docLines.length > 2) {
1927
+ for (let line of docLines.slice(2)) {
1928
+ cols.push({
1929
+ doc: ' ' + line
1930
+ })
1927
1931
  }
1928
1932
  }
1929
1933
  }
1934
+
1935
+ // 处理参数
1936
+ let argDef = getArgDef(text, cmdName)
1937
+ let comments = getArgComments(argDef, true)
1938
+ for (let line of comments) {
1939
+ cols.push({
1940
+ doc: ' ' + line
1941
+ })
1942
+ }
1943
+
1944
+ // 处理元数据
1945
+ let metadata = $data.get(cmdName);
1946
+ if (vl(metadata) && typeof metadata === 'object' && Object.keys(metadata).length > 0) {
1947
+ cols.push({
1948
+ doc: ' ' + Object.keys(metadata).map(msgStr).join(' / ')
1949
+ })
1950
+ }
1930
1951
  }
1931
1952
 
1932
1953
  function trimJsirFileName(name) {
@@ -2428,17 +2449,27 @@ function _addErrorTag(lines) {
2428
2449
  } else {
2429
2450
  result.push(line);
2430
2451
  }
2431
- let isAsyncFn = line.startsWith('async function');
2432
- let isSyncFn = line.startsWith('function');
2452
+ let isAsyncFn = line.startsWith('async function ');
2453
+ let isSyncFn = line.startsWith('function ');
2433
2454
  if (isAsyncFn || isSyncFn) {
2434
- fnName = reget(line, /function\s+([\s\S]+)\s*\(/)
2455
+ fnName = reget(line, /function\s+([a-zA-Z_$][a-zA-Z0-9_$.]*)\s*\(/)
2435
2456
  fnIsAsync = isAsyncFn;
2436
2457
  }
2437
2458
  if (functionEnd && fnName && (/\)\s*\{$/.test(trim(line)) || (line.startsWith("{") && trim(line) === '{'))) {
2438
2459
  result[i] += 'try{';
2439
2460
  if (wrapperFn.length > 0) {
2440
2461
  let defaultArgsList = '("'+ fnName +'")';
2441
- let runner = `([${wrapperFn.map(i => 'new ' + i + (i.endsWith(")") ? '':defaultArgsList)).join(",")}],`
2462
+ let runner = `([${wrapperFn.map(i => {
2463
+ if (i.endsWith(")")) {
2464
+ i = i
2465
+ .replace(/^([^(]+)\(\s*null\s*/, '$1("'+ fnName + '"')
2466
+ .replace(/^([^(]+)\(\s*undefined\s*/, '$1("'+ fnName + '"')
2467
+ .replace(/^([^(]+)\(\s*\)/, '$1' + defaultArgsList)
2468
+ } else {
2469
+ i += defaultArgsList;
2470
+ }
2471
+ return 'new ' + i;
2472
+ }).join(",")}],`
2442
2473
  if (fnIsAsync) {
2443
2474
  result[i] += `return await $aopAsync${runner}async ()=>{`;
2444
2475
  } else {
package/deps/evalCode.js CHANGED
@@ -17,10 +17,12 @@ module.exports = async ($text = '', $cmdName = '', $args = [],
17
17
  // 兼容
18
18
  $text = $lib.wrapperJsirText($text)
19
19
 
20
- const $setTips = $lib.setTips;
21
- const $delTips = $lib.delTips;
22
20
  const $tips = $lib.tipFns;
23
21
  const $errorTag = $lib.errorTag;
22
+
23
+ // 不在context中
24
+ const $setTips = $lib.setTips;
25
+ const $delTips = $lib.delTips;
24
26
  const $aop = $lib.aop;
25
27
  const $aopAsync = $lib.aopAsync;
26
28
 
package/deps/room.js CHANGED
@@ -1,8 +1,9 @@
1
1
  const os = require('os');
2
- const {fileJson, fileLock, vl, createConsole, getKeyTips, getValTips,
2
+ const {fileJson, fileLock, vl, getKeyTips, getValTips,
3
3
  getRoomsDir, e, isRunningInBackground,
4
- batchAsync, debugStr, trim, getOr, errorTag, warnStr, getConfig, getConfigDir,
5
- fileExist, formatUptime, processLock, isPidAlive, cleanFileLocks
4
+ batchAsync, trim, getOr, errorTag, warnStr, getConfig, getConfigDir,
5
+ fileExist, processLock, isPidAlive, cleanFileLocks,
6
+ roomConsole: console, reget
6
7
  } = require('./util');
7
8
  const {setRoute, createSign} = require('../deps/server')
8
9
  const roomDataFile = "jsirRoom.json"
@@ -10,20 +11,12 @@ const jsirNodesFile = "jsirNodes.json"
10
11
  const roomTasksFile = "roomTasks.json"
11
12
  const roomsDirLockKey = "RW_" + getRoomsDir();
12
13
  const updateRoomInfoLockKey = "UPDATE_" + roomDataFile
13
- const console = createConsole();
14
14
  const setting = require('../deps/setting')
15
15
  const fp = require('fs').promises
16
16
  const http = require('http');
17
17
  const tailscalePath = os.platform() === 'darwin' ?
18
18
  '/Applications/Tailscale.app/Contents/MacOS/Tailscale':'tailscale';
19
19
  const packageJson = require("../package.json");
20
- const defTasks = getConfig("tasks");
21
-
22
- function debug(...args) {
23
- if (global.$DEBUG) {
24
- console.$log(debugStr('[debug]'), ...args);
25
- }
26
- }
27
20
 
28
21
  async function localConfigs() {
29
22
  let configDir = getConfigDir();
@@ -61,7 +54,7 @@ function onRoom() {
61
54
  }
62
55
  })
63
56
  } catch (e) {
64
- debug("initRoute failed", e)
57
+ console.$debug("initRoute failed", e)
65
58
  }
66
59
  _onRoom();
67
60
  }
@@ -72,7 +65,7 @@ function _onRoom() {
72
65
  try {
73
66
  await initRoom();
74
67
  } catch (e) {
75
- debug('initRoom', e)
68
+ console.$debug('initRoom', e)
76
69
  }
77
70
  if (setting.roomTid[0]) {
78
71
  _onRoom();
@@ -86,7 +79,7 @@ function offRoom() {
86
79
  setting.roomTid[0] = null
87
80
  if (setting.server) {
88
81
  setting.server.close(() => {
89
- debug('Existing server shut down.');
82
+ console.$debug('Existing server shut down.');
90
83
  });
91
84
  }
92
85
  }
@@ -117,7 +110,7 @@ async function initNodes() {
117
110
  try {
118
111
  resp = await e(`${tailscalePath} status`);
119
112
  } catch (e) {
120
- debug("initNodes", e)
113
+ console.$debug("initNodes", e)
121
114
  }
122
115
  for (let line of resp.split("\n").map(trim)) {
123
116
  let offline = line.indexOf('offline') !== -1
@@ -145,7 +138,7 @@ async function updateRoomInfo(room) {
145
138
  room.name = setting.nodeMap[ip]?.name || os.hostname();
146
139
  room.selfNode = ip;
147
140
  room.lastUpdateTime = setting.roomTime
148
- debug("init room", room.name)
141
+ console.$debug("init room", room.name)
149
142
 
150
143
  await cleanRoom(room)
151
144
  return room;
@@ -167,10 +160,11 @@ async function syncRooms() {
167
160
  fns.push(async () => {
168
161
  let respBody = ''
169
162
  try {
163
+ let begin = Date.now();
170
164
  try {
171
165
  respBody = await reqNode(node, "get", "/");
172
166
  } catch (e) {
173
- debug(`sync ${node} failed:`, e);
167
+ console.$debug(`sync ${node} failed:`, e);
174
168
  if (!isDisableConnect(node, setting.defaultPort)) {
175
169
  respBody = await reqNode(node, "get", "/", setting.defaultPort);
176
170
  }
@@ -184,11 +178,12 @@ async function syncRooms() {
184
178
  Object.entries(currRoom.jsirs || {}).filter(([pid, jsir]) => jsir.port === setting.defaultPort)
185
179
  );
186
180
  }
181
+ currRoom.delay = Date.now() - begin;
187
182
  syncRooms.push(currRoom)
188
- debug(`sync ${node} success`);
183
+ console.$debug(`sync ${node} success`);
189
184
  }
190
185
  } catch (e) {
191
- debug(`sync ${node} failed:`, respBody, e);
186
+ console.$debug(`sync ${node} failed:`, respBody, e);
192
187
  }
193
188
  })
194
189
  }
@@ -208,11 +203,11 @@ async function syncRooms() {
208
203
  try {
209
204
  await fp.unlink(roomsDir + '/' + file)
210
205
  } catch (e) {
211
- debug(e);
206
+ console.$debug(e);
212
207
  }
213
208
  }
214
209
  }
215
- debug('syncRooms done')
210
+ console.$debug('syncRooms done')
216
211
  }
217
212
 
218
213
  async function syncSetting() {
@@ -278,32 +273,45 @@ async function _syncSetting(room) {
278
273
  }
279
274
  }
280
275
 
281
- async function processTasks() {
276
+ async function processTasks(defTasks) {
282
277
  await fileJson(roomTasksFile, async tasks => {
283
- tasks = Object.fromEntries(
284
- Object.entries(tasks).filter(([key, pid]) => isPidAlive(pid))
285
- );
286
- if (Object.values(tasks).includes(process.pid)) {
287
- return tasks;
278
+ for (let key of Object.keys(tasks)) {
279
+ let pids = tasks[key] || []
280
+ // 清理已经结束的进程
281
+ for (let i = 0; i < pids.length; i++) {
282
+ let pid = pids[i];
283
+ if (!isPidAlive(pid)) {
284
+ pids.splice(i, 1);
285
+ }
286
+ }
287
+ if (pids.length === 0) {
288
+ delete tasks[key]
289
+ }
288
290
  }
291
+
289
292
  let unHandleKey = null;
290
293
  for (let key of Object.keys(defTasks)) {
291
- if (!tasks[key]) {
292
- if (key.indexOf("*") !== -1 && setting.defaultPort !== setting.selfJsir.port) {
293
- continue;
294
- }
295
- if (key.indexOf("*") === -1 && setting.defaultPort === setting.selfJsir.port) {
296
- continue;
297
- }
298
- unHandleKey = key
299
- break;
294
+ let isMainPid = setting.defaultPort === setting.selfJsir.port;
295
+ let isMainTask = key.includes("*");
296
+ if (isMainPid !== isMainTask) {
297
+ continue;
300
298
  }
299
+
300
+ let num = Number(reget(trim(key), /(\d+)$/) || 1);
301
+ let taskKey = trim(trim(key).replace(/\d+$/, ''));
302
+ let pids = tasks[taskKey] || [];
303
+ if (pids.length >= num || pids.includes(process.pid)) {
304
+ continue;
305
+ }
306
+
307
+ unHandleKey = key;
301
308
  }
302
309
  if (unHandleKey) {
303
310
  console.$log(process.pid, `run task ${unHandleKey}[${defTasks[unHandleKey]}]`)
304
311
  await setting.wrapperInput(defTasks[unHandleKey]);
305
312
  if (!setting.newError) {
306
- tasks[unHandleKey] = process.pid;
313
+ let taskKey = trim(trim(unHandleKey).replace(/\d+$/, ''));
314
+ tasks[taskKey] = [...(tasks[taskKey] || []), process.pid];
307
315
  console.$log(process.pid, `handle task ${unHandleKey}[${defTasks[unHandleKey]}]`)
308
316
  }
309
317
  }
@@ -333,10 +341,11 @@ async function initRoom() {
333
341
  pros.push(syncConfigs())
334
342
  }
335
343
  await Promise.all(pros);
336
- }, false).catch(debug)
344
+ }, false).catch(console.$debug)
337
345
  }
346
+ const defTasks = getConfig("tasks");
338
347
  if (defTasks && Object.keys(defTasks).length > 0) {
339
- processLock(roomTasksFile, processTasks, false).catch(debug)
348
+ processLock(roomTasksFile, () => processTasks(defTasks), false).catch(console.$debug)
340
349
  }
341
350
  await syncSetting();
342
351
  }
@@ -346,7 +355,7 @@ async function syncConfigs() {
346
355
  try {
347
356
  configs = await reqFn(setting.configMainFnKey);
348
357
  } catch (e) {
349
- debug("syncConfigs failed", e)
358
+ console.$debug("syncConfigs failed", e)
350
359
  return;
351
360
  }
352
361
  let configDir = getConfigDir();
@@ -359,16 +368,16 @@ async function syncConfigs() {
359
368
  let currText = String(await fp.readFile(path));
360
369
  if (currText !== text) {
361
370
  await fp.writeFile(path, text)
362
- debug(`sync ${key} success`);
371
+ console.$debug(`sync ${key} success`);
363
372
  }
364
373
  } else {
365
374
  await fp.writeFile(path, text)
366
- debug(`sync ${key} success`);
375
+ console.$debug(`sync ${key} success`);
367
376
  }
368
377
  });
369
378
  }
370
379
  await batchAsync(fns, 33)
371
- debug('syncConfigs done')
380
+ console.$debug('syncConfigs done')
372
381
  }
373
382
 
374
383
  async function cleanRoom(room) {
@@ -378,10 +387,10 @@ async function cleanRoom(room) {
378
387
  let active = Date.now() - (jsir.lastUpdateTime || 0) <= setting.roomHeartbeatExpire;
379
388
  if (jsir.back && !active && isPidAlive(pid)) {
380
389
  try {
381
- debug(`kill inactive jsir ${pid}`)
390
+ console.$debug(`kill inactive jsir ${pid}`)
382
391
  process.kill(parseInt(pid), 'SIGKILL'); // 强制终止进程
383
392
  } catch (e) {
384
- debug(`cleanRoom ${pid} failed`, e)
393
+ console.$debug(`cleanRoom ${pid} failed`, e)
385
394
  }
386
395
  }
387
396
  }
@@ -438,7 +447,8 @@ async function initRoomJsir(room) {
438
447
  services: services,
439
448
  newError: setting.newError,
440
449
  version: packageJson.version,
441
- upTime: formatUptime()
450
+ upTime: process.uptime(),
451
+ mem: Math.floor(process.memoryUsage().rss / 1024 / 1024)
442
452
  }
443
453
  room.jsirs[process.pid] = setting.selfJsir
444
454
  }
@@ -547,7 +557,7 @@ async function reqNode(node, method, url, port, body) {
547
557
  req.end();
548
558
  });
549
559
  } finally {
550
- debug(`Request cost ${Date.now() - time}ms`, JSON.stringify(opt))
560
+ console.$debug(`Request cost ${Date.now() - time}ms`, JSON.stringify(opt))
551
561
  }
552
562
  }
553
563