jsir 2.6.4 → 2.6.6
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 +39 -15
- package/deps/evalCode.js +2 -0
- package/deps/room.js +57 -60
- package/deps/setting.js +4 -2
- package/deps/util.js +101 -5
- package/package.json +1 -1
package/cmd/oaa.js
CHANGED
|
@@ -13,7 +13,7 @@ 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
|
|
16
|
+
draftModify, isRunningInBackground, fileJson, fileLock, processLock
|
|
17
17
|
} = $lib;
|
|
18
18
|
const _args = process.argv.slice(2).map(trim);
|
|
19
19
|
const evalCode = require('../deps/evalCode')
|
|
@@ -130,7 +130,8 @@ const $data = {
|
|
|
130
130
|
key: () => Object.keys(_data),
|
|
131
131
|
has: (key) => vl(_data[key]),
|
|
132
132
|
json: fileJson,
|
|
133
|
-
lock: fileLock
|
|
133
|
+
lock: fileLock,
|
|
134
|
+
pLock: processLock
|
|
134
135
|
}
|
|
135
136
|
const $homeDir = getLibDataDir()
|
|
136
137
|
|
|
@@ -703,7 +704,6 @@ async function execLibFn(fn, fnArgs) {
|
|
|
703
704
|
}
|
|
704
705
|
|
|
705
706
|
async function joinServer(uniqueName, isApi, exportLib) {
|
|
706
|
-
Room.onRoom();
|
|
707
707
|
if (!setting.serviceReg.test(uniqueName)) {
|
|
708
708
|
throw 'invalid service name';
|
|
709
709
|
}
|
|
@@ -730,6 +730,7 @@ async function joinServer(uniqueName, isApi, exportLib) {
|
|
|
730
730
|
}, isApi)
|
|
731
731
|
}
|
|
732
732
|
console.msg(uniqueName, `has become a ${isApi ? "api ":""}service.`);
|
|
733
|
+
Room.onRoom();
|
|
733
734
|
}
|
|
734
735
|
|
|
735
736
|
async function offServer(uniqueName) {
|
|
@@ -913,8 +914,10 @@ function dealStarCmd(rows, cmd, filterStr) {
|
|
|
913
914
|
let commentContent = trimText(comments.join('\n'));
|
|
914
915
|
let row = getInfo(functionContent, fnName, fnType);
|
|
915
916
|
let pair = parseUniqueName(cmd);
|
|
916
|
-
row.value =
|
|
917
|
-
|
|
917
|
+
row.value = [
|
|
918
|
+
infoStr(pair[0] + '/' + trimJsirFileName(pair[1])) + ' ' + getCmdMd5Key(parseUniqueName(cmd)[1]),
|
|
919
|
+
[commentContent, row.value].filter(i => trim(i)).join("\n")
|
|
920
|
+
].filter(i => trim(i)).join("\n");
|
|
918
921
|
rows.push(row);
|
|
919
922
|
|
|
920
923
|
resetState();
|
|
@@ -1281,6 +1284,7 @@ const keywordDef = {
|
|
|
1281
1284
|
if (!fs.existsSync(path)) {
|
|
1282
1285
|
let cmds = filterCmd(uniqueName);
|
|
1283
1286
|
if (cmds.length === 1) {
|
|
1287
|
+
uniqueName = cmds[0];
|
|
1284
1288
|
path = getFullPath(cmds[0])
|
|
1285
1289
|
} else {
|
|
1286
1290
|
console.warn("no items")
|
|
@@ -2048,6 +2052,7 @@ async function getScriptArgs(argDef, oriArgs) {
|
|
|
2048
2052
|
let argNames = Object.keys(argDef)
|
|
2049
2053
|
let exactArgs = {}
|
|
2050
2054
|
let scriptArgs = {}
|
|
2055
|
+
let argIdx = 0;
|
|
2051
2056
|
for (let i = 0; i<oriArgs.length; i++) {
|
|
2052
2057
|
let arg = oriArgs[i]
|
|
2053
2058
|
let needTrans
|
|
@@ -2079,12 +2084,13 @@ async function getScriptArgs(argDef, oriArgs) {
|
|
|
2079
2084
|
}
|
|
2080
2085
|
pair[1] = needTrans ? await evalText( 'return ' + pair[1]):pair[1]
|
|
2081
2086
|
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2087
|
+
scriptArgs["$" + argIdx] = pair[1]
|
|
2088
|
+
argIdx ++;
|
|
2089
|
+
if (argNames[i]) {
|
|
2090
|
+
scriptArgs[argNames[i]] = pair[1]
|
|
2085
2091
|
}
|
|
2086
2092
|
if (pair[0] && argNames.indexOf(pair[0]) !== -1) {
|
|
2087
|
-
delete scriptArgs[argNames[
|
|
2093
|
+
delete scriptArgs[argNames[i]]
|
|
2088
2094
|
exactArgs[pair[0]] = pair[1]
|
|
2089
2095
|
}
|
|
2090
2096
|
}
|
|
@@ -2272,7 +2278,7 @@ async function _requireSource(currSpace, cmdMatchStr, force = false) {
|
|
|
2272
2278
|
let typeKey = getJsirTypeKey(pair[1]);
|
|
2273
2279
|
if (typeKey === setting.initKey) {
|
|
2274
2280
|
let pair = parseUniqueName(uniqueName)
|
|
2275
|
-
if (
|
|
2281
|
+
if (force) {
|
|
2276
2282
|
result = await evalText(text, uniqueName)
|
|
2277
2283
|
} else {
|
|
2278
2284
|
if (setting.serviceReg.test(uniqueName)) {
|
|
@@ -2310,26 +2316,44 @@ function addErrorTag(text) {
|
|
|
2310
2316
|
let lines = text.split(/\n/);
|
|
2311
2317
|
let functionEnd = true;
|
|
2312
2318
|
let fnName = '';
|
|
2319
|
+
let wrapperFn = [];
|
|
2313
2320
|
for (let i = 0; i < lines.length; i++) {
|
|
2314
2321
|
let line = lines[i];
|
|
2315
|
-
|
|
2316
|
-
|
|
2322
|
+
if (line.startsWith("@")) {
|
|
2323
|
+
wrapperFn.push(line.substring(1).trim())
|
|
2324
|
+
result.push(null);
|
|
2325
|
+
} else {
|
|
2326
|
+
result.push(line);
|
|
2327
|
+
}
|
|
2328
|
+
let isAsyncFn = line.startsWith('async function');
|
|
2329
|
+
let isSyncFn = line.startsWith('function');
|
|
2330
|
+
if (isAsyncFn || isSyncFn) {
|
|
2317
2331
|
fnName = reget(line, /function\s+([\s\S]+)\s*\(/)
|
|
2318
2332
|
}
|
|
2319
2333
|
if (functionEnd && fnName && (/\)\s*\{$/.test(trim(line)) || (line.startsWith("{") && trim(line) === '{'))) {
|
|
2320
2334
|
result[i] += 'try{';
|
|
2335
|
+
if (wrapperFn.length > 0) {
|
|
2336
|
+
let defaultArgsList = '("'+ fnName +'")';
|
|
2337
|
+
let runner = `([${wrapperFn.map(i => 'new ' + i + (i.endsWith(")") ? '':defaultArgsList)).join(",")}],`
|
|
2338
|
+
if (isAsyncFn) {
|
|
2339
|
+
result[i] += `return await $aopAsync${runner}async ()=>{`;
|
|
2340
|
+
} else if (isSyncFn) {
|
|
2341
|
+
result[i] += `return $aop${runner}()=>{`;
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2321
2344
|
functionEnd = false;
|
|
2322
2345
|
}
|
|
2323
2346
|
if (line.startsWith("}") && !functionEnd) {
|
|
2324
|
-
result[i] =
|
|
2347
|
+
result[i] = `${wrapperFn.length > 0 ? '},arguments)':''}}catch(e){throw($errorTag(e,$cmdName+'[${fnName}]'))}` + line;
|
|
2325
2348
|
functionEnd = true;
|
|
2326
2349
|
fnName = '';
|
|
2350
|
+
wrapperFn = []
|
|
2327
2351
|
}
|
|
2328
2352
|
}
|
|
2329
|
-
return result.join('\n');
|
|
2353
|
+
return result.filter(i => i !== null).join('\n');
|
|
2330
2354
|
}
|
|
2331
2355
|
|
|
2332
|
-
async function evalText($text = '', $cmdName = '', $args =
|
|
2356
|
+
async function evalText($text = '', $cmdName = '', $args = {}) {
|
|
2333
2357
|
if ($cmdName) {
|
|
2334
2358
|
console.$log(`Execute ${$cmdName}`);
|
|
2335
2359
|
}
|
package/deps/evalCode.js
CHANGED
|
@@ -20,6 +20,8 @@ module.exports = async ($text = '', $cmdName = '', $args = [],
|
|
|
20
20
|
const $setTips = $lib.setTips;
|
|
21
21
|
const $delTips = $lib.delTips;
|
|
22
22
|
const $errorTag = $lib.errorTag;
|
|
23
|
+
const $aop = $lib.aop;
|
|
24
|
+
const $aopAsync = $lib.aopAsync;
|
|
23
25
|
|
|
24
26
|
const $context = {
|
|
25
27
|
$defArgs,
|
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
|
|
5
|
+
fileExist, formatUptime, processLock
|
|
6
6
|
} = require('./util');
|
|
7
7
|
const {setRoute, createSign} = require('../deps/server')
|
|
8
8
|
const roomDataFile = "jsirRoom.json"
|
|
@@ -121,9 +121,12 @@ async function initNodes() {
|
|
|
121
121
|
if (configNodes.length > 0) {
|
|
122
122
|
for (const node of configNodes) {
|
|
123
123
|
let ss = node.split("@").map(trim).filter(i => i);
|
|
124
|
-
nodes[ss[1]] = {}
|
|
125
124
|
if (ss.length > 1) {
|
|
126
|
-
nodes[ss[1]]
|
|
125
|
+
nodes[ss[1]] = {
|
|
126
|
+
account: ss[0]
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
nodes[ss[0]] = {}
|
|
127
130
|
}
|
|
128
131
|
}
|
|
129
132
|
} else {
|
|
@@ -143,23 +146,21 @@ async function initNodes() {
|
|
|
143
146
|
setting.nodeMap = await fileJson("jsirNodes.json", obj => nodes);
|
|
144
147
|
}
|
|
145
148
|
|
|
146
|
-
async function updateRoomInfo() {
|
|
149
|
+
async function updateRoomInfo(room) {
|
|
147
150
|
await initNodes();
|
|
148
151
|
let nodes = Object.keys(setting.nodeMap)
|
|
149
152
|
let ip = getSelfIP(nodes)
|
|
150
|
-
|
|
151
|
-
room
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return room;
|
|
162
|
-
})
|
|
153
|
+
room = {
|
|
154
|
+
jsirs: room.jsirs
|
|
155
|
+
}
|
|
156
|
+
// 设置roomName
|
|
157
|
+
room.name = setting.nodeMap[ip]?.name || os.hostname();
|
|
158
|
+
room.selfNode = ip;
|
|
159
|
+
room.lastUpdateTime = setting.roomTime
|
|
160
|
+
debug("init room", room.name)
|
|
161
|
+
|
|
162
|
+
await cleanRoom(room)
|
|
163
|
+
return room;
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
async function syncRooms() {
|
|
@@ -330,11 +331,11 @@ async function initRoom() {
|
|
|
330
331
|
await initRoomJsir(room)
|
|
331
332
|
if (!vl(room.lastUpdateTime) || (Date.now() - room.lastUpdateTime) > setting.roomTimer) {
|
|
332
333
|
roomUpdateTouchTime = true;
|
|
334
|
+
return await updateRoomInfo(room)
|
|
333
335
|
}
|
|
334
336
|
})
|
|
335
337
|
if (roomUpdateTouchTime) {
|
|
336
338
|
fileLock(updateRoomInfoLockKey, async () => {
|
|
337
|
-
await updateRoomInfo()
|
|
338
339
|
let pros = []
|
|
339
340
|
pros.push(syncRooms())
|
|
340
341
|
if (setting.serviceFns[setting.configMainFnKey] && !getConfig("configMain")) {
|
|
@@ -343,8 +344,8 @@ async function initRoom() {
|
|
|
343
344
|
await Promise.all(pros);
|
|
344
345
|
}, false)
|
|
345
346
|
}
|
|
346
|
-
if (defTasks) {
|
|
347
|
-
|
|
347
|
+
if (defTasks && Object.keys(defTasks).length > 0) {
|
|
348
|
+
processLock(roomTasksFile, processTasks, false)
|
|
348
349
|
}
|
|
349
350
|
await syncSetting();
|
|
350
351
|
}
|
|
@@ -502,58 +503,54 @@ async function reqNode(node, method, url, port, body) {
|
|
|
502
503
|
hostname: node,
|
|
503
504
|
port: port, // HTTP 默认端口
|
|
504
505
|
path: url,
|
|
505
|
-
method: method.toUpperCase()
|
|
506
|
-
headers: {
|
|
507
|
-
'sign': createSign()
|
|
508
|
-
}
|
|
506
|
+
method: method.toUpperCase()
|
|
509
507
|
};
|
|
510
508
|
let time = Date.now();
|
|
511
509
|
try {
|
|
512
510
|
return await new Promise((resolve, reject) => {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
});
|
|
523
|
-
// 响应结束
|
|
524
|
-
res.on('end', () => {
|
|
525
|
-
clearTimeout(timeout)
|
|
526
|
-
// 检查响应状态码
|
|
527
|
-
if (res.statusCode !== 200) {
|
|
528
|
-
reject(errorTag(new Error(data), decodeURIComponent(url)));
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
resolve(data)
|
|
532
|
-
});
|
|
511
|
+
let timeout = null
|
|
512
|
+
|
|
513
|
+
const req = http.request({...opt, headers: {
|
|
514
|
+
'sign': createSign()
|
|
515
|
+
}}, (res) => {
|
|
516
|
+
let data = '';
|
|
517
|
+
// 数据块接收
|
|
518
|
+
res.on('data', (chunk) => {
|
|
519
|
+
data += chunk;
|
|
533
520
|
});
|
|
521
|
+
// 响应结束
|
|
522
|
+
res.on('end', () => {
|
|
523
|
+
clearTimeout(timeout)
|
|
524
|
+
// 检查响应状态码
|
|
525
|
+
if (res.statusCode !== 200) {
|
|
526
|
+
reject(errorTag(new Error(data), decodeURIComponent(url)));
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
resolve(data)
|
|
530
|
+
});
|
|
531
|
+
});
|
|
534
532
|
|
|
535
|
-
|
|
533
|
+
// 设置超时逻辑
|
|
534
|
+
if (setting.reqNodeTimeouts[url]) {
|
|
536
535
|
timeout = setTimeout(() => {
|
|
537
536
|
req.destroy(); // 中断请求
|
|
538
|
-
},
|
|
539
|
-
|
|
540
|
-
// 错误处理
|
|
541
|
-
req.on('error', (e) => {
|
|
542
|
-
clearTimeout(timeout); // 清除超时定时器
|
|
543
|
-
if (room) {
|
|
544
|
-
setting.disableConnect[node + ":" + port] = Date.now() + setting.disableConnectLimit
|
|
545
|
-
}
|
|
546
|
-
reject(e)
|
|
547
|
-
});
|
|
537
|
+
}, setting.reqNodeTimeouts[url]); // 10秒超时
|
|
538
|
+
}
|
|
548
539
|
|
|
549
|
-
|
|
550
|
-
|
|
540
|
+
// 错误处理
|
|
541
|
+
req.on('error', (e) => {
|
|
542
|
+
clearTimeout(timeout); // 清除超时定时器
|
|
543
|
+
if (room) {
|
|
544
|
+
setting.disableConnect[node + ":" + port] = Date.now() + setting.disableConnectLimit
|
|
551
545
|
}
|
|
552
|
-
// 结束请求
|
|
553
|
-
req.end();
|
|
554
|
-
} catch (e) {
|
|
555
546
|
reject(e)
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
if (body) {
|
|
550
|
+
req.write(body)
|
|
556
551
|
}
|
|
552
|
+
// 结束请求
|
|
553
|
+
req.end();
|
|
557
554
|
});
|
|
558
555
|
} finally {
|
|
559
556
|
debug(`Request cost ${Date.now() - time}ms`, JSON.stringify(opt))
|
package/deps/setting.js
CHANGED
|
@@ -34,7 +34,6 @@ module.exports = {
|
|
|
34
34
|
serviceFns: {},
|
|
35
35
|
enterOutputs: null,
|
|
36
36
|
defaultPort: 52108,
|
|
37
|
-
reqNodeDefaultTimeout: 33000,
|
|
38
37
|
reqNodeTimeouts: {
|
|
39
38
|
'/': 2000
|
|
40
39
|
},
|
|
@@ -44,5 +43,8 @@ module.exports = {
|
|
|
44
43
|
roomHeartbeatExpire: 9000,
|
|
45
44
|
configMainFnKey: "config/main",
|
|
46
45
|
serviceReg: /[^a-zA-Z]service[^a-zA-Z]|[^a-zA-Z]service$/i,
|
|
47
|
-
wrapperInput: null
|
|
46
|
+
wrapperInput: null,
|
|
47
|
+
lastOutput: null,
|
|
48
|
+
locks: {},
|
|
49
|
+
lastChangeFlag: null
|
|
48
50
|
}
|
package/deps/util.js
CHANGED
|
@@ -45,7 +45,7 @@ function consoleStrs(...args) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// 格式化第一个参数
|
|
48
|
-
if (typeof args[0] === 'string') {
|
|
48
|
+
if (args.length > 1 && typeof args[0] === 'string' && hasFormat(args[0])) {
|
|
49
49
|
return util.format(...args); // 处理格式化字符串 (%s, %d 等)
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -59,6 +59,12 @@ function consoleStrs(...args) {
|
|
|
59
59
|
.join(' ');
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
// 判断是否包含格式化占位符的函数
|
|
63
|
+
function hasFormat(str) {
|
|
64
|
+
// 检查是否有 %s, %d, %j 等占位符
|
|
65
|
+
return /%[sdjifoO%]/.test(str);
|
|
66
|
+
}
|
|
67
|
+
|
|
62
68
|
class SyncQueue {
|
|
63
69
|
constructor() {
|
|
64
70
|
this.queue = [];
|
|
@@ -194,7 +200,7 @@ const _console =Object.assign({}, global.console);
|
|
|
194
200
|
const _consoleFns= {
|
|
195
201
|
log: {
|
|
196
202
|
fn: _console.log,
|
|
197
|
-
args: args => args
|
|
203
|
+
args: args => [consoleStrs(...args)]
|
|
198
204
|
},
|
|
199
205
|
table: {
|
|
200
206
|
fn: _console.log,
|
|
@@ -209,7 +215,7 @@ const _consoleFns= {
|
|
|
209
215
|
args: args => [infoStr('[info]'), dealLevelArgs(infoStr, args)]
|
|
210
216
|
},
|
|
211
217
|
msg: {
|
|
212
|
-
fn: _console.
|
|
218
|
+
fn: _console.info,
|
|
213
219
|
args: args => [msgStr('[msg]'), dealLevelArgs(msgStr, args)]
|
|
214
220
|
},
|
|
215
221
|
warn: {
|
|
@@ -277,6 +283,18 @@ function createConsole(uniqueName) {
|
|
|
277
283
|
if ('error' === key) {
|
|
278
284
|
global.$newError = true;
|
|
279
285
|
}
|
|
286
|
+
let hasFlag = false;
|
|
287
|
+
let sameFlag = false;
|
|
288
|
+
if (args.length > 1 && typeof args[0] === 'string' && args[0].startsWith("*") && args[0].endsWith("*")) {
|
|
289
|
+
hasFlag = true;
|
|
290
|
+
let flag = args[0]
|
|
291
|
+
args = args.slice(1)
|
|
292
|
+
|
|
293
|
+
if (!setting.lastChangeFlag || setting.lastChangeFlag === flag) {
|
|
294
|
+
sameFlag = true;
|
|
295
|
+
}
|
|
296
|
+
setting.lastChangeFlag = flag
|
|
297
|
+
}
|
|
280
298
|
if (uniqueName && quite) {
|
|
281
299
|
if ((key === 'table' || key === 'nable') && typeof args[0] === "object") {
|
|
282
300
|
args = ['', ...args]
|
|
@@ -289,7 +307,22 @@ function createConsole(uniqueName) {
|
|
|
289
307
|
}
|
|
290
308
|
} else {
|
|
291
309
|
let _args = _consoleFns[key].args(args);
|
|
310
|
+
|
|
311
|
+
if (hasFlag && !isRunningInBackground() && setting.lastOutput && sameFlag) {
|
|
312
|
+
let lines = (setting.lastOutput.match(/\n/g) || []).length + 1;
|
|
313
|
+
for (let i = 0; i < lines; i++) {
|
|
314
|
+
process.stdout.write('\x1b[A\r'+ ' '.repeat(process.stdout.columns))
|
|
315
|
+
}
|
|
316
|
+
_args[0] = '\r' + _args[0]
|
|
317
|
+
}
|
|
318
|
+
|
|
292
319
|
_consoleFns[key].fn(..._args);
|
|
320
|
+
|
|
321
|
+
if (hasFlag) {
|
|
322
|
+
setting.lastOutput = _args.join(" ");
|
|
323
|
+
} else {
|
|
324
|
+
setting.lastOutput = null;
|
|
325
|
+
}
|
|
293
326
|
}
|
|
294
327
|
}
|
|
295
328
|
}
|
|
@@ -1044,6 +1077,9 @@ function _getConfig(key, defaultVal, uniqueName) {
|
|
|
1044
1077
|
if (key === undefined) {
|
|
1045
1078
|
return config
|
|
1046
1079
|
}
|
|
1080
|
+
if (uniqueName) {
|
|
1081
|
+
console.debug(`use ${uniqueName} config "${key}"`)
|
|
1082
|
+
}
|
|
1047
1083
|
let writeFlag = false
|
|
1048
1084
|
if (!(key in config)) {
|
|
1049
1085
|
writeFlag = true
|
|
@@ -1250,7 +1286,7 @@ async function _fileLock(key, fn, expireMs = 49000) {
|
|
|
1250
1286
|
|
|
1251
1287
|
// 4. 成功加锁后执行 fn
|
|
1252
1288
|
try {
|
|
1253
|
-
await fn()
|
|
1289
|
+
await timeLimit([fn()], expireMs)
|
|
1254
1290
|
return true;
|
|
1255
1291
|
} finally {
|
|
1256
1292
|
// 5. 执行完毕后,手动释放锁目录(也可选择保留到过期自动失效,但一般都建议主动释放)
|
|
@@ -1278,6 +1314,41 @@ async function fileLock(key, fn, wait = true, expireMs = 49000) {
|
|
|
1278
1314
|
}
|
|
1279
1315
|
}
|
|
1280
1316
|
|
|
1317
|
+
async function processLock(key, fn, wait = true) {
|
|
1318
|
+
`
|
|
1319
|
+
内存锁, 默认一直等待直到加锁成功执行fn
|
|
1320
|
+
wait = false, 加锁失败则不执行fn
|
|
1321
|
+
return void
|
|
1322
|
+
`
|
|
1323
|
+
if (wait) {
|
|
1324
|
+
while (true) {
|
|
1325
|
+
if (await _processLock(key, fn)) {
|
|
1326
|
+
break;
|
|
1327
|
+
}
|
|
1328
|
+
await sleep(9);
|
|
1329
|
+
}
|
|
1330
|
+
} else {
|
|
1331
|
+
await _processLock(key, fn);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
async function _processLock(key, fn) {
|
|
1336
|
+
if (!key || typeof fn !== 'function') {
|
|
1337
|
+
throw new Error('invalid arguments');
|
|
1338
|
+
}
|
|
1339
|
+
key = key.trim();
|
|
1340
|
+
if (setting.locks.hasOwnProperty(key)) {
|
|
1341
|
+
return false;
|
|
1342
|
+
}
|
|
1343
|
+
setting.locks[key] = true;
|
|
1344
|
+
try {
|
|
1345
|
+
await fn();
|
|
1346
|
+
return true;
|
|
1347
|
+
} finally {
|
|
1348
|
+
delete setting.locks[key];
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1281
1352
|
function removeFirst(array, obj) {
|
|
1282
1353
|
let deleteIndex
|
|
1283
1354
|
for(let i = 0;i<array.length;i++) {
|
|
@@ -2149,6 +2220,28 @@ function formatUptime() {
|
|
|
2149
2220
|
}
|
|
2150
2221
|
}
|
|
2151
2222
|
|
|
2223
|
+
function aop(items, fn, args) {
|
|
2224
|
+
let runners = [fn]
|
|
2225
|
+
let i = 0
|
|
2226
|
+
for (let item of [...items].reverse()) {
|
|
2227
|
+
const j = i;
|
|
2228
|
+
runners.push((args) => item.run(runners[j], args))
|
|
2229
|
+
i ++;
|
|
2230
|
+
}
|
|
2231
|
+
return runners[i](args)
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
async function aopAsync(items, fn, args) {
|
|
2235
|
+
let runners = [fn]
|
|
2236
|
+
let i = 0
|
|
2237
|
+
for (let item of [...items].reverse()) {
|
|
2238
|
+
const j = i;
|
|
2239
|
+
runners.push(async (args) => await item.runAsync(runners[j], args))
|
|
2240
|
+
i ++;
|
|
2241
|
+
}
|
|
2242
|
+
return await runners[i](args)
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2152
2245
|
module.exports = {
|
|
2153
2246
|
formatUptime,
|
|
2154
2247
|
wrapperJsirText,
|
|
@@ -2260,5 +2353,8 @@ module.exports = {
|
|
|
2260
2353
|
createDetachedProcess,
|
|
2261
2354
|
interceptStdStreams,
|
|
2262
2355
|
draftModify,
|
|
2263
|
-
fileExist
|
|
2356
|
+
fileExist,
|
|
2357
|
+
aop,
|
|
2358
|
+
aopAsync,
|
|
2359
|
+
processLock
|
|
2264
2360
|
}
|