jsir 2.6.8 → 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 +9 -1
- package/deps/room.js +4 -20
- package/deps/util.js +54 -50
- package/package.json +1 -1
package/cmd/oaa.js
CHANGED
|
@@ -606,12 +606,20 @@ function listCmd(tmpMap) {
|
|
|
606
606
|
}
|
|
607
607
|
}
|
|
608
608
|
|
|
609
|
-
async function wrapperInput(str) {
|
|
609
|
+
async function wrapperInput(str, packOutput = false) {
|
|
610
|
+
if (packOutput) {
|
|
611
|
+
setting.enterOutputs = []
|
|
612
|
+
}
|
|
610
613
|
try {
|
|
611
614
|
await _wrapperInput(str);
|
|
612
615
|
} catch (e) {
|
|
613
616
|
console.error(e)
|
|
614
617
|
}
|
|
618
|
+
if (packOutput) {
|
|
619
|
+
let outputs = setting.enterOutputs || [];
|
|
620
|
+
setting.enterOutputs = null;
|
|
621
|
+
return outputs.join('');
|
|
622
|
+
}
|
|
615
623
|
}
|
|
616
624
|
|
|
617
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
|
-
|
|
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(`
|
|
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
|
|
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
|
|
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
|
-
|
|
1215
|
-
|
|
1216
|
-
if (!expireFile) {
|
|
1209
|
+
const pidFile = files.find(name => name.startsWith('pid-'));
|
|
1210
|
+
if (!pidFile) {
|
|
1217
1211
|
return null;
|
|
1218
1212
|
}
|
|
1219
|
-
|
|
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
|
|
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
|
-
|
|
1271
|
-
|
|
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(
|
|
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
|
|
1278
|
+
await fn();
|
|
1287
1279
|
return true;
|
|
1288
1280
|
} finally {
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
}
|