jsir 2.6.7 → 2.6.9

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
@@ -106,6 +106,9 @@ const $data = {
106
106
  return _dealOnLazyGet(key, onLazyTempCode)
107
107
  },
108
108
  gos: (key, defaultVal, onLazyTempCode) => {
109
+ `
110
+ get or set
111
+ `
109
112
  if (!vl(_data[key])) {
110
113
  if (defaultVal !== undefined) {
111
114
  return _dataSet(key, defaultVal, onLazyTempCode)
@@ -116,8 +119,20 @@ const $data = {
116
119
  return _dealOnLazyGet(key, onLazyTempCode)
117
120
  },
118
121
  gfs: (key, fn, onLazyTempCode) => {
122
+ `
123
+ get or set by function
124
+ `
119
125
  if (!vl(_data[key])) {
120
- return _dataSet(key, fn(), onLazyTempCode)
126
+ return _dataSet(key, fn(), onLazyTempCode)
127
+ }
128
+ return _dealOnLazyGet(key, onLazyTempCode)
129
+ },
130
+ gafs: async (key, fn, onLazyTempCode) => {
131
+ `
132
+ get or set by async function
133
+ `
134
+ if (!vl(_data[key])) {
135
+ return _dataSet(key, await fn(), onLazyTempCode)
121
136
  }
122
137
  return _dealOnLazyGet(key, onLazyTempCode)
123
138
  },
@@ -591,12 +606,20 @@ function listCmd(tmpMap) {
591
606
  }
592
607
  }
593
608
 
594
- async function wrapperInput(str) {
609
+ async function wrapperInput(str, packOutput = false) {
610
+ if (packOutput) {
611
+ setting.enterOutputs = []
612
+ }
595
613
  try {
596
614
  await _wrapperInput(str);
597
615
  } catch (e) {
598
616
  console.error(e)
599
617
  }
618
+ if (packOutput) {
619
+ let outputs = setting.enterOutputs || [];
620
+ setting.enterOutputs = null;
621
+ return outputs.join('');
622
+ }
600
623
  }
601
624
 
602
625
  function wrapperAlias(str) {
package/deps/room.js CHANGED
@@ -2,7 +2,7 @@ const os = require('os');
2
2
  const {fileJson, fileLock, vl, createConsole, getKeyTips, getValTips,
3
3
  getRoomsDir, e, isRunningInBackground,
4
4
  batchAsync, debugStr, trim, getOr, errorTag, warnStr, getConfig, getConfigDir,
5
- fileExist, formatUptime, processLock
5
+ fileExist, formatUptime, processLock, isPidAlive, cleanFileLocks
6
6
  } = require('./util');
7
7
  const {setRoute, createSign} = require('../deps/server')
8
8
  const roomDataFile = "jsirRoom.json"
@@ -25,19 +25,6 @@ function debug(...args) {
25
25
  }
26
26
  }
27
27
 
28
- function isPidAlive(pid) {
29
- try {
30
- process.kill(Number(pid), 0); // 信号 0 不会实际发送,但会检查进程是否存在
31
- return true; // PID 存在
32
- } catch (err) {
33
- if (err.code === 'ESRCH') {
34
- return false; // 进程不存在
35
- }
36
- debug(`check isPidAlive ${pid} failed`, err)
37
- return false;
38
- }
39
- }
40
-
41
28
  async function localConfigs() {
42
29
  let configDir = getConfigDir();
43
30
  let configFiles = await fp.readdir(configDir)
@@ -69,11 +56,7 @@ function onRoom() {
69
56
  res.output = warnStr("Disable Remote")
70
57
  return;
71
58
  }
72
- setting.enterOutputs = []
73
- await setting.wrapperInput(req.input)
74
- let outputs = setting.enterOutputs || [];
75
- setting.enterOutputs = null;
76
- res.output = outputs.join('');
59
+ res.output = await setting.wrapperInput(req.input, true)
77
60
  global.$newInput = true;
78
61
  }
79
62
  })
@@ -337,6 +320,7 @@ async function initRoom() {
337
320
  if (roomUpdateTouchTime) {
338
321
  fileLock(updateRoomInfoLockKey, async () => {
339
322
  let pros = []
323
+ pros.push(cleanFileLocks())
340
324
  pros.push(syncRooms())
341
325
  if (setting.serviceFns[setting.configMainFnKey] && !getConfig("configMain")) {
342
326
  pros.push(syncConfigs())
@@ -390,7 +374,7 @@ async function cleanRoom(room) {
390
374
  debug(`kill inactive jsir ${pid}`)
391
375
  process.kill(parseInt(pid), 'SIGKILL'); // 强制终止进程
392
376
  } catch (e) {
393
- debug(`clearRoom ${pid} failed`, e)
377
+ debug(`cleanRoom ${pid} failed`, e)
394
378
  }
395
379
  }
396
380
  }
package/deps/util.js CHANGED
@@ -879,7 +879,7 @@ async function fileExist(path) {
879
879
  }
880
880
  }
881
881
 
882
- async function fileJson(key, fn = null, fmt = true, safeMs = 49000) {
882
+ async function fileJson(key, fn = null, fmt = true) {
883
883
  `
884
884
  多进程安全文件读写
885
885
  `
@@ -910,7 +910,7 @@ async function fileJson(key, fn = null, fmt = true, safeMs = 49000) {
910
910
  result = val
911
911
  }
912
912
  await fp.writeFile(path, prefixStr + JSON.stringify(result, null, fmt ? 2:null))
913
- }, true, safeMs);
913
+ }, true);
914
914
  return result;
915
915
  }
916
916
 
@@ -1203,28 +1203,41 @@ function getLockKeyDir(key) {
1203
1203
  return lockDir + "/" + key;
1204
1204
  }
1205
1205
 
1206
- /**
1207
- * 从目录中读取过期时间戳
1208
- * @param {string} lockDir - 锁目录路径
1209
- * @returns {Promise<number | null>} 如果目录下存在过期时间戳文件,则返回其数值;否则返回 null
1210
- */
1211
- async function readExpireTimestamp(lockDir) {
1206
+ async function readLockPid(lockDir) {
1212
1207
  try {
1213
1208
  const files = await fp.readdir(lockDir);
1214
- // 假设我们只会创建一个文件,其文件名包含过期时间,如 `expire-1672531200000`
1215
- const expireFile = files.find(name => name.startsWith('expire-'));
1216
- if (!expireFile) {
1209
+ const pidFile = files.find(name => name.startsWith('pid-'));
1210
+ if (!pidFile) {
1217
1211
  return null;
1218
1212
  }
1219
- const timestamp = parseInt(expireFile.replace('expire-', ''), 10);
1220
- return isNaN(timestamp) ? null : timestamp;
1213
+ return pidFile.split("-")[1];
1221
1214
  } catch (err) {
1222
1215
  // 读取目录出错(可能不存在?)直接返回 null
1223
1216
  return null;
1224
1217
  }
1225
1218
  }
1226
1219
 
1227
- async function _fileLock(key, fn, expireMs = 49000) {
1220
+ async function cleanFileLocks() {
1221
+ let lockDir = getLockDir();
1222
+ const files = await fp.readdir(lockDir);
1223
+ for (let file of files) {
1224
+ let lockKeyDir = lockDir + '/' + file;
1225
+ let pid = await readLockPid(lockKeyDir);
1226
+ if (!pid) {
1227
+ continue;
1228
+ }
1229
+ if (!isPidAlive(pid)) {
1230
+ // 持有锁的进程已经没了,则删除锁文件
1231
+ try {
1232
+ await fp.rm(lockKeyDir, { recursive: true, force: true });
1233
+ } catch (err) {
1234
+ console.$error(`cleanLock ${lockKeyDir} failed`, err);
1235
+ }
1236
+ }
1237
+ }
1238
+ }
1239
+
1240
+ async function _fileLock(key, fn) {
1228
1241
  `
1229
1242
  文件锁,返回true/false,
1230
1243
  如果没锁住则不执行fn
@@ -1232,31 +1245,12 @@ async function _fileLock(key, fn, expireMs = 49000) {
1232
1245
  if (!key || typeof fn !== 'function') {
1233
1246
  throw new Error('invalid arguments');
1234
1247
  }
1235
- if (expireMs < 1000) {
1236
- throw new Error("expireMs can not less than 1000")
1237
- }
1238
1248
 
1239
1249
  let lockKeyDir = getLockKeyDir(key)
1240
- const now = Date.now();
1241
- const expireAt = now + expireMs;
1242
-
1243
1250
  // 1. 尝试判断锁目录是否已存在
1244
1251
  let lockExists = await fileExist(lockKeyDir);
1245
-
1246
1252
  if (lockExists) {
1247
- // 目录存在时,读取文件名中的过期时间戳
1248
- const storedExpireAt = await readExpireTimestamp(lockKeyDir) || 0;
1249
- if (storedExpireAt > now) {
1250
- // 说明锁尚未过期
1251
- return false;
1252
- }
1253
- // 如果过期了,则清理原目录,以便重新加锁
1254
- try {
1255
- await fp.rm(lockKeyDir, { recursive: true, force: true });
1256
- } catch (err) {
1257
- // 删除失败,可能是权限问题;这里直接返回 false 或者抛错
1258
- return false;
1259
- }
1253
+ return false;
1260
1254
  }
1261
1255
 
1262
1256
  // 2. 创建锁目录
@@ -1267,12 +1261,10 @@ async function _fileLock(key, fn, expireMs = 49000) {
1267
1261
  return false;
1268
1262
  }
1269
1263
 
1270
- // 3. 在锁目录下创建一个文件,文件名带“过期时间戳”
1271
- // expireAt === 0 表示永不过期
1272
- const expireFilename = `expire-${expireAt}`;
1273
- const expireFilePath = path.join(lockKeyDir, expireFilename);
1264
+ const lockPidFile = `pid-${process.pid}`;
1265
+ const lockPidFilePath = path.join(lockKeyDir, lockPidFile);
1274
1266
  try {
1275
- await fp.writeFile(expireFilePath, '');
1267
+ await fp.writeFile(lockPidFilePath, '');
1276
1268
  } catch (err) {
1277
1269
  // 无法写文件就释放锁并抛错
1278
1270
  try {
@@ -1283,19 +1275,16 @@ async function _fileLock(key, fn, expireMs = 49000) {
1283
1275
 
1284
1276
  // 4. 成功加锁后执行 fn
1285
1277
  try {
1286
- await timeLimit([fn()], expireMs)
1278
+ await fn();
1287
1279
  return true;
1288
1280
  } finally {
1289
- if (Date.now() <= expireAt - 9) {
1290
- // 5. 执行完毕后,手动释放锁目录(也可选择保留到过期自动失效,但一般都建议主动释放)
1291
- try {
1292
- await fp.rm(lockKeyDir, { recursive: true, force: true });
1293
- } catch (_) {}
1294
- }
1281
+ try {
1282
+ await fp.rm(lockKeyDir, { recursive: true, force: true });
1283
+ } catch (_) {}
1295
1284
  }
1296
1285
  }
1297
1286
 
1298
- async function fileLock(key, fn, wait = true, expireMs = 49000) {
1287
+ async function fileLock(key, fn, wait = true) {
1299
1288
  `
1300
1289
  文件锁, 默认一直等待expireMs,直到加锁成功执行fn
1301
1290
  wait = false, 加锁失败则不执行fn
@@ -1303,13 +1292,13 @@ async function fileLock(key, fn, wait = true, expireMs = 49000) {
1303
1292
  `
1304
1293
  if (wait) {
1305
1294
  while (true) {
1306
- if (await _fileLock(key, fn, expireMs)) {
1295
+ if (await _fileLock(key, fn)) {
1307
1296
  break;
1308
1297
  }
1309
1298
  await sleep(9);
1310
1299
  }
1311
1300
  } else {
1312
- await _fileLock(key, fn, expireMs);
1301
+ await _fileLock(key, fn);
1313
1302
  }
1314
1303
  }
1315
1304
 
@@ -1533,6 +1522,19 @@ function getLisPidDir() {
1533
1522
  return dir
1534
1523
  }
1535
1524
 
1525
+ function isPidAlive(pid) {
1526
+ try {
1527
+ process.kill(Number(pid), 0); // 信号 0 不会实际发送,但会检查进程是否存在
1528
+ return true; // PID 存在
1529
+ } catch (err) {
1530
+ if (err.code === 'ESRCH') {
1531
+ return false; // 进程不存在
1532
+ }
1533
+ console.$error(`check isPidAlive ${pid} failed`, err)
1534
+ return false;
1535
+ }
1536
+ }
1537
+
1536
1538
  function linuxAskAndKill(...keys){
1537
1539
  let rl = readline.createInterface({
1538
1540
  input: process.stdin,
@@ -2373,5 +2375,7 @@ module.exports = {
2373
2375
  aopAsync,
2374
2376
  processLock,
2375
2377
  hasTips,
2376
- tipKeys
2378
+ tipKeys,
2379
+ isPidAlive,
2380
+ cleanFileLocks
2377
2381
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsir",
3
- "version": "2.6.7",
3
+ "version": "2.6.9",
4
4
  "description": "JavaScript Script Management Tool",
5
5
  "main": "index.js",
6
6
  "scripts": {