jsir 2.6.13 → 3.0.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 +117 -104
- package/deps/evalCode.js +4 -2
- package/deps/room.js +32 -32
- package/deps/server.js +6 -13
- package/deps/setting.js +4 -1
- package/deps/util.js +207 -297
- package/package.json +1 -1
package/deps/util.js
CHANGED
|
@@ -2,7 +2,6 @@ const setting = require('./setting')
|
|
|
2
2
|
const os = require('os')
|
|
3
3
|
const home = os.homedir()
|
|
4
4
|
const {exec, spawnSync, spawn} = require('child_process');
|
|
5
|
-
const readline = require('readline')
|
|
6
5
|
const fs = require('fs')
|
|
7
6
|
const fp = require('fs').promises
|
|
8
7
|
const BigNumber = require('bignumber.js');
|
|
@@ -24,7 +23,6 @@ let roomsDir;
|
|
|
24
23
|
let dataDir;
|
|
25
24
|
let console = global.console
|
|
26
25
|
|
|
27
|
-
|
|
28
26
|
function isRunningInBackground() {
|
|
29
27
|
return !(process.stdout.isTTY && process.stdin.isTTY);
|
|
30
28
|
}
|
|
@@ -61,42 +59,73 @@ function hasFormat(str) {
|
|
|
61
59
|
return /%[sdjifoO%]/.test(str);
|
|
62
60
|
}
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
62
|
+
async function taskQueue(task, { key, size = 1, runner = 1 } = {}) {
|
|
63
|
+
if (size < 1) throw new Error('invalid queue size');
|
|
64
|
+
if (runner < 1) throw new Error('invalid queue runner');
|
|
65
|
+
key = trim(key);
|
|
66
|
+
|
|
67
|
+
let ins = getOr(setting.syncQueues, key, {
|
|
68
|
+
name: key,
|
|
69
|
+
queue: [],
|
|
70
|
+
isProcessing: false,
|
|
71
|
+
waiter: null
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
ins.size = size;
|
|
75
|
+
ins.runner = runner;
|
|
76
|
+
|
|
77
|
+
// 如果队列满了,等待空位
|
|
78
|
+
while (ins.size !== Infinity && ins.queue.length >= ins.size) {
|
|
79
|
+
if (!ins.waiter) {
|
|
80
|
+
ins.waiter = {};
|
|
81
|
+
ins.waiter.promise = new Promise(resolve => ins.waiter.resolve = resolve);
|
|
85
82
|
}
|
|
86
|
-
|
|
83
|
+
await ins.waiter.promise;
|
|
87
84
|
}
|
|
85
|
+
|
|
86
|
+
ins.queue.push(task);
|
|
87
|
+
_processQueue(ins);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
90
|
+
async function _processQueue(ins) {
|
|
91
|
+
if (ins.isProcessing) return;
|
|
92
|
+
ins.isProcessing = true;
|
|
93
|
+
|
|
94
|
+
const runs = new Set();
|
|
95
|
+
|
|
96
|
+
while (ins.queue.length > 0 || runs.size > 0) {
|
|
97
|
+
// 启动任务,控制并发数量
|
|
98
|
+
while (ins.queue.length > 0 && runs.size < ins.runner) {
|
|
99
|
+
const task = ins.queue.shift();
|
|
100
|
+
|
|
101
|
+
const promise = (async () => {
|
|
102
|
+
try {
|
|
103
|
+
await task();
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.$error(`Error during [${ins.name}] SyncQueue`, error);
|
|
106
|
+
}
|
|
107
|
+
})();
|
|
108
|
+
|
|
109
|
+
promise.finally(() => {
|
|
110
|
+
runs.delete(promise);
|
|
111
|
+
|
|
112
|
+
// 唤醒等待者
|
|
113
|
+
if (ins.waiter && ins.queue.length < ins.size) {
|
|
114
|
+
ins.waiter.resolve();
|
|
115
|
+
ins.waiter = null;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
runs.add(promise);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (runs.size > 0) {
|
|
123
|
+
await Promise.race(runs);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
ins.isProcessing = false;
|
|
128
|
+
delete setting.syncQueues[ins.name];
|
|
100
129
|
}
|
|
101
130
|
|
|
102
131
|
const $log = createLimitLogger(`${setting.name}.log`, {
|
|
@@ -107,15 +136,18 @@ const $error = createLimitLogger(`${setting.name}.error`, {
|
|
|
107
136
|
error: true,
|
|
108
137
|
syncLogs: [$log]
|
|
109
138
|
});
|
|
139
|
+
const $errorOnly = createLimitLogger(`${setting.name}.error`, {
|
|
140
|
+
logInfo: false,
|
|
141
|
+
error: true
|
|
142
|
+
});
|
|
110
143
|
|
|
111
144
|
const roomLog = createLimitLogger(`room.log`, {
|
|
112
|
-
logInfo: false
|
|
113
|
-
syncLogs: [$log]
|
|
145
|
+
logInfo: false
|
|
114
146
|
});
|
|
115
147
|
const roomError = createLimitLogger(`room.error`, {
|
|
116
148
|
logInfo: false,
|
|
117
149
|
error: true,
|
|
118
|
-
syncLogs: [roomLog
|
|
150
|
+
syncLogs: [roomLog]
|
|
119
151
|
});
|
|
120
152
|
|
|
121
153
|
let _globalDraft= createLimitLogger(`draft.log`, {
|
|
@@ -246,23 +278,23 @@ function createConfig(uniqueName) {
|
|
|
246
278
|
return result;
|
|
247
279
|
}
|
|
248
280
|
|
|
249
|
-
function createConsole(uniqueName) {
|
|
281
|
+
function createConsole(uniqueName, _logToFile, _errorToFile) {
|
|
250
282
|
let result = Object.assign({}, _console);
|
|
251
|
-
|
|
252
|
-
|
|
283
|
+
let logToFile = _logToFile || $log;
|
|
284
|
+
let errorToFile = _errorToFile || $error;
|
|
253
285
|
result.$draft = draftLog;
|
|
254
286
|
result.$abort = () => false;
|
|
255
287
|
if (uniqueName) {
|
|
256
288
|
let pair = parseUniqueName(uniqueName)
|
|
257
289
|
let fileName = pair[0] + '/' + pair[1].split(".")[0]
|
|
258
|
-
|
|
290
|
+
logToFile = createLimitLogger(fileName + '.log', {
|
|
259
291
|
logInfo: false,
|
|
260
|
-
syncLogs: [
|
|
292
|
+
syncLogs: [$log]
|
|
261
293
|
});
|
|
262
|
-
|
|
294
|
+
errorToFile = createLimitLogger(fileName + '.error', {
|
|
263
295
|
logInfo: false,
|
|
264
296
|
error: true,
|
|
265
|
-
syncLogs: [
|
|
297
|
+
syncLogs: [logToFile, $errorOnly]
|
|
266
298
|
});
|
|
267
299
|
const promptId = setting.promptId;
|
|
268
300
|
result.$abort = () => promptId !== setting.promptId;
|
|
@@ -272,8 +304,14 @@ function createConsole(uniqueName) {
|
|
|
272
304
|
if (uniqueName) {
|
|
273
305
|
promptId = setting.promptId;
|
|
274
306
|
}
|
|
275
|
-
for (let key of Object.keys(_consoleFns)) {
|
|
276
|
-
|
|
307
|
+
for (let key of [...Object.keys(_consoleFns), ...Object.keys(_consoleFns).map(i => '$' + i)]) {
|
|
308
|
+
let fnKey = key;
|
|
309
|
+
result[fnKey] = (...args) => {
|
|
310
|
+
let is$ = false;
|
|
311
|
+
if (fnKey.startsWith("$")) {
|
|
312
|
+
is$ = true;
|
|
313
|
+
key = fnKey.substring(1)
|
|
314
|
+
}
|
|
277
315
|
if (promptId !== setting.promptId) {
|
|
278
316
|
quite = true;
|
|
279
317
|
}
|
|
@@ -295,15 +333,15 @@ function createConsole(uniqueName) {
|
|
|
295
333
|
}
|
|
296
334
|
setting.lastChangeFlag = flag
|
|
297
335
|
}
|
|
298
|
-
if (uniqueName && quite) {
|
|
336
|
+
if (is$ || (uniqueName && quite) || (setting.lastOutput && !hasFlag && 'debug' === key)) {
|
|
299
337
|
if ((key === 'table' || key === 'nable') && typeof args[0] === "object") {
|
|
300
338
|
args = ['', ...args]
|
|
301
339
|
}
|
|
302
340
|
let _args = _consoleFns[key].args(args);
|
|
303
341
|
if ("error" === key) {
|
|
304
|
-
|
|
342
|
+
errorToFile(..._args)
|
|
305
343
|
} else {
|
|
306
|
-
|
|
344
|
+
logToFile(..._args)
|
|
307
345
|
}
|
|
308
346
|
} else {
|
|
309
347
|
let _args = _consoleFns[key].args(args);
|
|
@@ -321,12 +359,7 @@ function createConsole(uniqueName) {
|
|
|
321
359
|
}
|
|
322
360
|
|
|
323
361
|
_consoleFns[key].fn(..._args);
|
|
324
|
-
|
|
325
|
-
if (hasFlag) {
|
|
326
|
-
setting.lastOutput = lastOutput;
|
|
327
|
-
} else {
|
|
328
|
-
setting.lastOutput = null;
|
|
329
|
-
}
|
|
362
|
+
setting.lastOutput = lastOutput;
|
|
330
363
|
}
|
|
331
364
|
}
|
|
332
365
|
}
|
|
@@ -594,7 +627,7 @@ async function draftModify(fLine) {
|
|
|
594
627
|
if (isEdit && results.length === 1) {
|
|
595
628
|
let tempPath = getLibDataDir() + "/log/draft.temp";
|
|
596
629
|
fs.writeFileSync(tempPath, results[0].split(/\n/).slice(1).join('\n'))
|
|
597
|
-
await eia(getEditor(), [tempPath])
|
|
630
|
+
await eia(getEditor(), [`"${tempPath}"`], true)
|
|
598
631
|
let tempText = String(fs.readFileSync(tempPath))
|
|
599
632
|
let lineRange = lineRanges.get(results[0]);
|
|
600
633
|
let before = allLines.filter((_, index) => {
|
|
@@ -640,6 +673,10 @@ function getEditor() {
|
|
|
640
673
|
return getConfig("defaultEditor", "vi")
|
|
641
674
|
}
|
|
642
675
|
|
|
676
|
+
function getFileOpenExe() {
|
|
677
|
+
return getConfig("defaultExe", "open")
|
|
678
|
+
}
|
|
679
|
+
|
|
643
680
|
function timeStr(fmt, date) {
|
|
644
681
|
return dayJs(date || new Date()).format(fmt || 'YYYY-MM-DD HH:mm:ss')
|
|
645
682
|
}
|
|
@@ -663,31 +700,29 @@ function getVl(...obj) {
|
|
|
663
700
|
}
|
|
664
701
|
}
|
|
665
702
|
|
|
666
|
-
const $fnCache = {}
|
|
667
703
|
async function cacheFn(key, fn, validMs = 0, awaitRefresh = true) {
|
|
668
|
-
getOr(
|
|
669
|
-
|
|
704
|
+
const cacheItem = getOr(setting.fnCache, key, {
|
|
705
|
+
createdAt: 0,
|
|
670
706
|
});
|
|
671
|
-
if (Date.now()
|
|
672
|
-
//
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
$fnCache[key].promise = (async () => {
|
|
707
|
+
if (Date.now() - cacheItem.createdAt > validMs) {
|
|
708
|
+
// 临时设为已创建,防止并发请求多次调用 fn
|
|
709
|
+
cacheItem.createdAt = Infinity;
|
|
710
|
+
cacheItem.promise = (async () => {
|
|
676
711
|
let val;
|
|
677
712
|
try {
|
|
678
713
|
val = await fn()
|
|
679
714
|
} finally {
|
|
680
|
-
|
|
715
|
+
cacheItem.createdAt = 0; // 恢复为无效状态
|
|
681
716
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
717
|
+
cacheItem.val = val;
|
|
718
|
+
cacheItem.valInit = true;
|
|
719
|
+
cacheItem.createdAt = Date.now(); // 设置新的创建时间
|
|
685
720
|
})();
|
|
686
721
|
}
|
|
687
|
-
if (awaitRefresh ||
|
|
688
|
-
await
|
|
722
|
+
if (awaitRefresh || !cacheItem.valInit) {
|
|
723
|
+
await cacheItem.promise;
|
|
689
724
|
}
|
|
690
|
-
return
|
|
725
|
+
return cacheItem.val;
|
|
691
726
|
}
|
|
692
727
|
|
|
693
728
|
function getFnVl(...fns) {
|
|
@@ -703,9 +738,9 @@ function getFnVl(...fns) {
|
|
|
703
738
|
function randomInt(min,max){
|
|
704
739
|
switch(arguments.length){
|
|
705
740
|
case 1:
|
|
706
|
-
return
|
|
741
|
+
return Math.floor(Math.random()*min+1);
|
|
707
742
|
case 2:
|
|
708
|
-
return
|
|
743
|
+
return Math.floor(Math.random()*(max-min+1)+min);
|
|
709
744
|
default:
|
|
710
745
|
return 0;
|
|
711
746
|
}
|
|
@@ -713,8 +748,12 @@ function randomInt(min,max){
|
|
|
713
748
|
|
|
714
749
|
async function timeLimit(proms, mills) {
|
|
715
750
|
let tIds = []
|
|
716
|
-
let result
|
|
717
|
-
|
|
751
|
+
let result
|
|
752
|
+
try {
|
|
753
|
+
result = await Promise.race([Promise.all(proms), sleep(mills, tIds)])
|
|
754
|
+
} finally {
|
|
755
|
+
clearTimeout(tIds[0])
|
|
756
|
+
}
|
|
718
757
|
if (!result) {
|
|
719
758
|
throw new Error(`timeLimit: exceed ${mills} ms`)
|
|
720
759
|
}
|
|
@@ -807,7 +846,7 @@ function createLimitLogger(fileName, {
|
|
|
807
846
|
if (time) {
|
|
808
847
|
text = `${timeStr('YYYY-MM-DD HH:mm:ss.SSS')} ${String(process.pid%1000).padStart(3, '0')}> ${text}`
|
|
809
848
|
}
|
|
810
|
-
|
|
849
|
+
fp.appendFile(logPath, text + '\n')
|
|
811
850
|
let _minNum = (Date.now()/(1000 * 60 * 10)).toFixed(0)
|
|
812
851
|
if (_minNum !== minNum) {
|
|
813
852
|
minNum = _minNum
|
|
@@ -850,17 +889,20 @@ function dataFile(fileName, fn, fmt, defaultObj = {}, returnStr = false) {
|
|
|
850
889
|
if (fileName.startsWith("/")) {
|
|
851
890
|
path = fileName
|
|
852
891
|
} else {
|
|
892
|
+
if (fileName.includes('/')) {
|
|
893
|
+
throw 'invalid fileName';
|
|
894
|
+
}
|
|
853
895
|
path = dataDir + "/" + fileName
|
|
854
896
|
}
|
|
855
897
|
let prefixStr = returnStr ? 'return ' : '';
|
|
856
898
|
if (!fs.existsSync(path)) {
|
|
857
|
-
|
|
899
|
+
createDirs(dataDir)
|
|
858
900
|
fs.writeFileSync(path, prefixStr + JSON.stringify(defaultObj, null, fmt ? 2:null))
|
|
859
901
|
}
|
|
860
902
|
|
|
861
903
|
let text = String(fs.readFileSync(path));
|
|
862
904
|
if (returnStr) {
|
|
863
|
-
text = text.replace(/^return\s
|
|
905
|
+
text = text.replace(/^return\s*/, '')
|
|
864
906
|
}
|
|
865
907
|
let obj = JSON.parse(text)
|
|
866
908
|
if (!fn) {
|
|
@@ -900,13 +942,16 @@ async function fileJson(key, fn = null, fmt = true) {
|
|
|
900
942
|
`
|
|
901
943
|
let dataDir = getDataDir()
|
|
902
944
|
let fileName = trim(key)
|
|
945
|
+
if (fileName.includes('/')) {
|
|
946
|
+
throw 'invalid fileName';
|
|
947
|
+
}
|
|
903
948
|
let path = dataDir + "/" + fileName;
|
|
904
949
|
let homeDir = setting.workspaceMap[setting.defaultSpace]
|
|
905
950
|
let isInit = getJsirTypeKey(fileName) === setting.initKey;
|
|
906
951
|
if (isInit) {
|
|
907
952
|
path = homeDir + '/' + toJsirFileName(fileName);
|
|
908
953
|
}
|
|
909
|
-
let prefixStr = isInit ? '
|
|
954
|
+
let prefixStr = isInit ? 'module.exports = ' : '';
|
|
910
955
|
let result = null;
|
|
911
956
|
await fileLock(path, async () => {
|
|
912
957
|
if (!await fileExist(path)) {
|
|
@@ -914,7 +959,7 @@ async function fileJson(key, fn = null, fmt = true) {
|
|
|
914
959
|
}
|
|
915
960
|
let text = String(await fp.readFile(path));
|
|
916
961
|
if (isInit) {
|
|
917
|
-
text = text.replace(/^
|
|
962
|
+
text = text.replace(/^module\.exports =\s*/, '')
|
|
918
963
|
}
|
|
919
964
|
result = JSON.parse(text)
|
|
920
965
|
if (!fn) {
|
|
@@ -1097,7 +1142,7 @@ function _getConfig(key, defaultVal, uniqueName) {
|
|
|
1097
1142
|
return config
|
|
1098
1143
|
}
|
|
1099
1144
|
if (uniqueName) {
|
|
1100
|
-
console
|
|
1145
|
+
console.$debug(`use ${uniqueName} config "${key}"`)
|
|
1101
1146
|
}
|
|
1102
1147
|
let writeFlag = false
|
|
1103
1148
|
if (!(key in config)) {
|
|
@@ -1122,7 +1167,7 @@ function _getConfig(key, defaultVal, uniqueName) {
|
|
|
1122
1167
|
return val
|
|
1123
1168
|
}
|
|
1124
1169
|
|
|
1125
|
-
function setConfig(key, val) {
|
|
1170
|
+
function setConfig(key, val, uniqueName) {
|
|
1126
1171
|
if (typeof val === "string") {
|
|
1127
1172
|
val = trim(val)
|
|
1128
1173
|
}
|
|
@@ -1131,6 +1176,9 @@ function setConfig(key, val) {
|
|
|
1131
1176
|
configInit[key] = val
|
|
1132
1177
|
}
|
|
1133
1178
|
let configFile = getLibDataDir() + '/config.json';
|
|
1179
|
+
if (uniqueName) {
|
|
1180
|
+
configFile = getConfigDir() + "/" + md5(uniqueName + (global.$TEST ? ".test":"")) + ".json"
|
|
1181
|
+
}
|
|
1134
1182
|
if (!fs.existsSync(configFile)) {
|
|
1135
1183
|
fs.writeFileSync(configFile, JSON.stringify(configInit, null, 2));
|
|
1136
1184
|
return val
|
|
@@ -1369,7 +1417,6 @@ function removeFirst(array, obj) {
|
|
|
1369
1417
|
return array.splice(deleteIndex, 1)
|
|
1370
1418
|
}
|
|
1371
1419
|
|
|
1372
|
-
const _tipsOnRm = {}
|
|
1373
1420
|
function setTips(key, value, onRm) {
|
|
1374
1421
|
`
|
|
1375
1422
|
可以设置相同的key, value值,会在左侧提示符体现出来
|
|
@@ -1378,17 +1425,22 @@ function setTips(key, value, onRm) {
|
|
|
1378
1425
|
throw "invalid tip key";
|
|
1379
1426
|
}
|
|
1380
1427
|
key = trim(key)
|
|
1381
|
-
|
|
1428
|
+
value = vl(value) ? value:key
|
|
1429
|
+
if (typeof value === 'string') {
|
|
1430
|
+
value = trim(value)
|
|
1431
|
+
}
|
|
1432
|
+
getOr(setting.tips, key, []).push(value);
|
|
1382
1433
|
if (onRm) {
|
|
1383
|
-
getOr(
|
|
1434
|
+
getOr(setting.tipsOnRm, key, []).push(onRm)
|
|
1384
1435
|
}
|
|
1385
1436
|
}
|
|
1386
1437
|
|
|
1387
1438
|
function delTips(...keys) {
|
|
1439
|
+
keys = keys.map(trim).filter(i => i)
|
|
1388
1440
|
let pros = []
|
|
1389
1441
|
for (let key of Object.keys(setting.tips)) {
|
|
1390
1442
|
if (keys.length === 0) {
|
|
1391
|
-
if (
|
|
1443
|
+
if (['TEST', 'DEBUG'].includes(key)) {
|
|
1392
1444
|
continue
|
|
1393
1445
|
}
|
|
1394
1446
|
delete setting.tips[key]
|
|
@@ -1399,8 +1451,8 @@ function delTips(...keys) {
|
|
|
1399
1451
|
}
|
|
1400
1452
|
}
|
|
1401
1453
|
if (keys.length === 0) {
|
|
1402
|
-
for (let key of Object.keys(
|
|
1403
|
-
if (
|
|
1454
|
+
for (let key of Object.keys(setting.tipsOnRm)) {
|
|
1455
|
+
if (['TEST', 'DEBUG'].includes(key)) {
|
|
1404
1456
|
continue
|
|
1405
1457
|
}
|
|
1406
1458
|
pros.push(tipsOnRmCallback(key))
|
|
@@ -1415,6 +1467,9 @@ function delTips(...keys) {
|
|
|
1415
1467
|
function hasTips(key, value) {
|
|
1416
1468
|
key = trim(key)
|
|
1417
1469
|
if (vl(value)) {
|
|
1470
|
+
if (typeof value === 'string') {
|
|
1471
|
+
value = trim(value)
|
|
1472
|
+
}
|
|
1418
1473
|
return setting.tips.hasOwnProperty(key) && setting.tips[key].includes(value);
|
|
1419
1474
|
} else {
|
|
1420
1475
|
return setting.tips.hasOwnProperty(key);
|
|
@@ -1426,18 +1481,18 @@ function tipKeys() {
|
|
|
1426
1481
|
}
|
|
1427
1482
|
|
|
1428
1483
|
function tipsOnRmCallback(key) {
|
|
1429
|
-
let callbacks =
|
|
1430
|
-
delete
|
|
1484
|
+
let callbacks = setting.tipsOnRm[key]
|
|
1485
|
+
delete setting.tipsOnRm[key]
|
|
1431
1486
|
const pros = [];
|
|
1432
1487
|
if (callbacks && callbacks.length > 0) {
|
|
1433
1488
|
for (let callback of callbacks) {
|
|
1434
1489
|
try {
|
|
1435
1490
|
let result = callback()
|
|
1436
1491
|
if (getType(result) === 'Promise') {
|
|
1437
|
-
pros.push(result.catch(e =>
|
|
1492
|
+
pros.push(result.catch(e => console.$error(`[${key}] OnRmCallback`, e)))
|
|
1438
1493
|
}
|
|
1439
1494
|
} catch (e) {
|
|
1440
|
-
|
|
1495
|
+
console.$error(`[${key}] OnRmCallback`, e)
|
|
1441
1496
|
}
|
|
1442
1497
|
}
|
|
1443
1498
|
}
|
|
@@ -1446,66 +1501,12 @@ function tipsOnRmCallback(key) {
|
|
|
1446
1501
|
}
|
|
1447
1502
|
}
|
|
1448
1503
|
|
|
1449
|
-
async function
|
|
1450
|
-
`
|
|
1451
|
-
定时控制器
|
|
1452
|
-
clear tips退出
|
|
1453
|
-
fn方法返回true退出
|
|
1454
|
-
return void;
|
|
1455
|
-
`
|
|
1456
|
-
if (!(key && ms && fn)) {
|
|
1457
|
-
throw 'invalid args'
|
|
1458
|
-
}
|
|
1459
|
-
let ids = []
|
|
1460
|
-
let showLabel = vl(label) ? label : key;
|
|
1461
|
-
let flag = [...new Set([key, showLabel].map(trim))].filter(i => i).join(' ')
|
|
1462
|
-
setTips(key, showLabel, () => {
|
|
1463
|
-
clearTimeout(ids[0])
|
|
1464
|
-
ids[0] = false
|
|
1465
|
-
if (printInfo) {
|
|
1466
|
-
console.info(`${flag} stop`)
|
|
1467
|
-
}
|
|
1468
|
-
})
|
|
1469
|
-
if (printInfo) {
|
|
1470
|
-
console.info(`${flag} start`)
|
|
1471
|
-
}
|
|
1472
|
-
await timeLoop(fn, ms, ids)
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
const cleanFiles = {}
|
|
1476
|
-
function fileCleaner(path, maxChars) {
|
|
1477
|
-
`
|
|
1478
|
-
文件清理器,提示符为sys f
|
|
1479
|
-
`
|
|
1480
|
-
cleanFiles[path] = Date.now() + (1000 * 60)
|
|
1481
|
-
let flag = "sys"
|
|
1482
|
-
if (!setting.tips.hasOwnProperty(flag)) {
|
|
1483
|
-
timer(flag, 1000 * 9, () => {
|
|
1484
|
-
for (let aPath of Object.keys(cleanFiles)) {
|
|
1485
|
-
if (cleanFiles[aPath] < Date.now()) {
|
|
1486
|
-
delete cleanFiles[path]
|
|
1487
|
-
continue;
|
|
1488
|
-
}
|
|
1489
|
-
try {
|
|
1490
|
-
cleanFile(path, maxChars)
|
|
1491
|
-
} catch (e) {
|
|
1492
|
-
console.$error(e)
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
}, "f", false);
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
function cleanFile(path, maxChars = 9 * 1024 * 1024) {
|
|
1500
|
-
`
|
|
1501
|
-
进入文件操作队列,不会同步去做
|
|
1502
|
-
`
|
|
1504
|
+
async function cleanFile(path, maxChars = 9 * 1024 * 1024) {
|
|
1503
1505
|
path = trim(path);
|
|
1504
1506
|
if (!path) {
|
|
1505
1507
|
return
|
|
1506
1508
|
}
|
|
1507
|
-
|
|
1508
|
-
maxChars = maxChars || 1024 * 1024
|
|
1509
|
+
await fileLock(path, async () => {
|
|
1509
1510
|
// 获取文件信息
|
|
1510
1511
|
let stats;
|
|
1511
1512
|
try {
|
|
@@ -1519,46 +1520,15 @@ function cleanFile(path, maxChars = 9 * 1024 * 1024) {
|
|
|
1519
1520
|
if (fileSize <= maxChars) {
|
|
1520
1521
|
return;
|
|
1521
1522
|
}
|
|
1522
|
-
await fileLock(path, async () => {
|
|
1523
|
-
const bakFile = `${path}.bak`;
|
|
1524
|
-
// 备份日志
|
|
1525
|
-
try {
|
|
1526
|
-
await fp.rename(path, bakFile);
|
|
1527
|
-
} catch (e) {
|
|
1528
|
-
console.$error(`Failed to rename ${path} -> ${bakFile}`, e);
|
|
1529
|
-
}
|
|
1530
|
-
}, false)
|
|
1531
|
-
}, path)
|
|
1532
|
-
}
|
|
1533
1523
|
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
let pidFile = `${dir}/${name}.pid`
|
|
1541
|
-
fs.writeFileSync(pidFile, String(process.pid))
|
|
1542
|
-
let beforeExit = () => {
|
|
1543
|
-
fs.writeFileSync(pidFile, '')
|
|
1544
|
-
process.exit()
|
|
1545
|
-
}
|
|
1546
|
-
process.on('SIGINT', beforeExit)
|
|
1547
|
-
process.on('exit', beforeExit)
|
|
1548
|
-
timeLoop(()=>{
|
|
1549
|
-
if (fs.existsSync(pidFile) && String(process.pid) !== String(fs.readFileSync(pidFile))) {
|
|
1550
|
-
process.exit(0)
|
|
1524
|
+
const bakFile = `${path}.bak`;
|
|
1525
|
+
// 备份日志
|
|
1526
|
+
try {
|
|
1527
|
+
await fp.rename(path, bakFile);
|
|
1528
|
+
} catch (e) {
|
|
1529
|
+
console.$error(`Failed to rename ${path} -> ${bakFile}`, e);
|
|
1551
1530
|
}
|
|
1552
|
-
},
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1555
|
-
function getLisPidDir() {
|
|
1556
|
-
let home = getLibDataDir()
|
|
1557
|
-
let dir = `${home}/pid`
|
|
1558
|
-
try {
|
|
1559
|
-
fs.mkdirSync(dir)
|
|
1560
|
-
} catch(e) {}
|
|
1561
|
-
return dir
|
|
1531
|
+
}, false)
|
|
1562
1532
|
}
|
|
1563
1533
|
|
|
1564
1534
|
function isPidAlive(pid) {
|
|
@@ -1574,72 +1544,6 @@ function isPidAlive(pid) {
|
|
|
1574
1544
|
}
|
|
1575
1545
|
}
|
|
1576
1546
|
|
|
1577
|
-
function linuxAskAndKill(...keys){
|
|
1578
|
-
let rl = readline.createInterface({
|
|
1579
|
-
input: process.stdin,
|
|
1580
|
-
output: process.stdout
|
|
1581
|
-
})
|
|
1582
|
-
rl.on('line', (str) => {
|
|
1583
|
-
str = trim(str)
|
|
1584
|
-
if (str) {
|
|
1585
|
-
if (['q', 'exit', 'bye'].indexOf(str) !== -1) {
|
|
1586
|
-
rl.close()
|
|
1587
|
-
return;
|
|
1588
|
-
}
|
|
1589
|
-
e(`kill -9 ${str}`).then(() => {
|
|
1590
|
-
_linuxAskAndKill(rl, keys)
|
|
1591
|
-
})
|
|
1592
|
-
} else {
|
|
1593
|
-
process.stdout.write("> ")
|
|
1594
|
-
}
|
|
1595
|
-
})
|
|
1596
|
-
rl.on('close', () => {
|
|
1597
|
-
process.exit(0)
|
|
1598
|
-
})
|
|
1599
|
-
_linuxAskAndKill(rl, keys)
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
function timeLoop(fn, timestamp, lastIds = []){
|
|
1603
|
-
`
|
|
1604
|
-
fn的结果===true, 则退出;
|
|
1605
|
-
lastIds[0]===false, 则退出;
|
|
1606
|
-
return lastIds;
|
|
1607
|
-
`
|
|
1608
|
-
let val
|
|
1609
|
-
try {
|
|
1610
|
-
val = fn()
|
|
1611
|
-
} catch (e) {
|
|
1612
|
-
$error(e)
|
|
1613
|
-
}
|
|
1614
|
-
if (vl(val) && getType(val) === 'Promise') {
|
|
1615
|
-
return val.then(result => {
|
|
1616
|
-
if (lastIds[0] !== false && result !== true) {
|
|
1617
|
-
lastIds[0] = setTimeout(() => timeLoop(fn, timestamp, lastIds), timestamp)
|
|
1618
|
-
}
|
|
1619
|
-
return lastIds
|
|
1620
|
-
}).catch(e => {
|
|
1621
|
-
$error(e)
|
|
1622
|
-
|
|
1623
|
-
if (lastIds[0] !== false) {
|
|
1624
|
-
lastIds[0] = setTimeout(() => timeLoop(fn, timestamp, lastIds), timestamp)
|
|
1625
|
-
}
|
|
1626
|
-
return lastIds
|
|
1627
|
-
})
|
|
1628
|
-
} else {
|
|
1629
|
-
if (lastIds[0] !== false && val !== true) {
|
|
1630
|
-
lastIds[0] = setTimeout(() => timeLoop(fn, timestamp, lastIds), timestamp)
|
|
1631
|
-
}
|
|
1632
|
-
return lastIds
|
|
1633
|
-
}
|
|
1634
|
-
}
|
|
1635
|
-
|
|
1636
|
-
function _linuxAskAndKill(rl, keys){
|
|
1637
|
-
e(`ps -ef | ${keys.filter(item => item).map(item => 'grep ' + item).join(' | ')}`).then(resp => {
|
|
1638
|
-
console.log(resp.replace(/\n\s+/g, '\n'))
|
|
1639
|
-
process.stdout.write("> ")
|
|
1640
|
-
})
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
1547
|
function trim(obj) {
|
|
1644
1548
|
`
|
|
1645
1549
|
返回值一定是string
|
|
@@ -1801,14 +1705,14 @@ function range(start, end, step) {
|
|
|
1801
1705
|
}
|
|
1802
1706
|
|
|
1803
1707
|
function getOr(obj, key, defaultVal) {
|
|
1804
|
-
if (!vl(obj[key])) {
|
|
1708
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key) || !vl(obj[key])) {
|
|
1805
1709
|
obj[key] = defaultVal
|
|
1806
1710
|
}
|
|
1807
1711
|
return obj[key]
|
|
1808
1712
|
}
|
|
1809
1713
|
|
|
1810
1714
|
function getOrFn(obj, key, defaultValFn) {
|
|
1811
|
-
if (!vl(obj[key])) {
|
|
1715
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key) || !vl(obj[key])) {
|
|
1812
1716
|
obj[key] = defaultValFn()
|
|
1813
1717
|
}
|
|
1814
1718
|
return obj[key]
|
|
@@ -2111,7 +2015,10 @@ function errorTag(e, tag) {
|
|
|
2111
2015
|
}
|
|
2112
2016
|
let newError = isError(e) ? e:new Error(e);
|
|
2113
2017
|
let stack = newError.stack
|
|
2114
|
-
|
|
2018
|
+
let append = ` at ${tag}`;
|
|
2019
|
+
if (!stack.endsWith(append)) {
|
|
2020
|
+
newError.stack = stack + '\n' + append
|
|
2021
|
+
}
|
|
2115
2022
|
return newError
|
|
2116
2023
|
}
|
|
2117
2024
|
|
|
@@ -2157,7 +2064,8 @@ function getTextComments(text) {
|
|
|
2157
2064
|
|
|
2158
2065
|
function wrapperJsirText(text) {
|
|
2159
2066
|
return text
|
|
2160
|
-
.replace(/^require\s*\(\s*(["'`][ei][^a-zA-Z]+)/mg, 'await $require($
|
|
2067
|
+
.replace(/^require\s*\(\s*(["'`][ei][^a-zA-Z]+)/mg, 'await $require($1')
|
|
2068
|
+
.replace(/([\s=;]require\s*\(\s*["'`])\.\/([ei][^a-zA-Z]+)/g, '$1$2')
|
|
2161
2069
|
.replace(/([\s=;])require\s*\(\s*(["'`][ei][^a-zA-Z]+)/g, '$1await $require($2')
|
|
2162
2070
|
.replace(/([\s=;])import\s*\(/g, '$1$import(')
|
|
2163
2071
|
.replace(/^import\s*\(/mg, '$import(')
|
|
@@ -2165,24 +2073,6 @@ function wrapperJsirText(text) {
|
|
|
2165
2073
|
;
|
|
2166
2074
|
}
|
|
2167
2075
|
|
|
2168
|
-
async function terminalRun(cmd) {
|
|
2169
|
-
`
|
|
2170
|
-
打开新的苹果终端并执行命令
|
|
2171
|
-
`
|
|
2172
|
-
const scriptText = `tell application "Terminal"
|
|
2173
|
-
activate
|
|
2174
|
-
do script "${cmd}"
|
|
2175
|
-
end tell
|
|
2176
|
-
`;
|
|
2177
|
-
let tempScriptPath = getTempDir() + `/terminalRun_${Date.now()}.scpt`
|
|
2178
|
-
fs.writeFileSync(tempScriptPath, scriptText);
|
|
2179
|
-
try {
|
|
2180
|
-
console.log(await e(`osascript ${tempScriptPath}`))
|
|
2181
|
-
} finally {
|
|
2182
|
-
fs.unlinkSync(tempScriptPath)
|
|
2183
|
-
}
|
|
2184
|
-
}
|
|
2185
|
-
|
|
2186
2076
|
function getKeyTips() {
|
|
2187
2077
|
let items = [];
|
|
2188
2078
|
for (let key of Object.keys(setting.tips)) {
|
|
@@ -2200,7 +2090,7 @@ function getValTips() {
|
|
|
2200
2090
|
if (key.startsWith("_")) {
|
|
2201
2091
|
continue;
|
|
2202
2092
|
}
|
|
2203
|
-
let
|
|
2093
|
+
let vals = setting.tips[key].map(i => {
|
|
2204
2094
|
if (typeof i === 'function') {
|
|
2205
2095
|
try {
|
|
2206
2096
|
i = i();
|
|
@@ -2214,8 +2104,18 @@ function getValTips() {
|
|
|
2214
2104
|
item = `[${item}]`;
|
|
2215
2105
|
}
|
|
2216
2106
|
return item;
|
|
2217
|
-
})
|
|
2218
|
-
|
|
2107
|
+
});
|
|
2108
|
+
let valMap = {}
|
|
2109
|
+
for (let val of vals) {
|
|
2110
|
+
valMap[val] = getOr(valMap, val, 0) + 1
|
|
2111
|
+
}
|
|
2112
|
+
items.push(Object.keys(valMap).map(i => {
|
|
2113
|
+
if (valMap[i] > 1) {
|
|
2114
|
+
return i + '*' + valMap[i]
|
|
2115
|
+
} else {
|
|
2116
|
+
return i;
|
|
2117
|
+
}
|
|
2118
|
+
}).join("|"))
|
|
2219
2119
|
}
|
|
2220
2120
|
return items
|
|
2221
2121
|
}
|
|
@@ -2263,13 +2163,21 @@ function interceptStdStreams() {
|
|
|
2263
2163
|
};
|
|
2264
2164
|
}
|
|
2265
2165
|
|
|
2266
|
-
function
|
|
2267
|
-
|
|
2166
|
+
function formatMb(mb) {
|
|
2167
|
+
if (typeof mb !== 'number') {
|
|
2168
|
+
return mb;
|
|
2169
|
+
}
|
|
2170
|
+
return mb > 1024 ? ((mb/1024).toFixed(2) + 'G') : (mb + 'M')
|
|
2171
|
+
}
|
|
2268
2172
|
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2173
|
+
function formatSec(sec) {
|
|
2174
|
+
if (typeof sec !== 'number') {
|
|
2175
|
+
return sec;
|
|
2176
|
+
}
|
|
2177
|
+
const days = Math.floor(sec / (3600 * 24)); // 计算天数
|
|
2178
|
+
const hours = Math.floor((sec % (3600 * 24)) / 3600); // 计算小时
|
|
2179
|
+
const minutes = Math.floor((sec % 3600) / 60); // 计算分钟
|
|
2180
|
+
const seconds = Math.floor(sec % 60); // 计算秒数
|
|
2273
2181
|
|
|
2274
2182
|
if (days > 0) {
|
|
2275
2183
|
return `${days}d${hours}h`;
|
|
@@ -2286,22 +2194,28 @@ function aop(items, fn, args) {
|
|
|
2286
2194
|
let runners = [fn]
|
|
2287
2195
|
let i = 0
|
|
2288
2196
|
for (let item of [...items].reverse()) {
|
|
2197
|
+
if (!item.run) {
|
|
2198
|
+
throw `${item.constructor.name} not suitable for sync function`
|
|
2199
|
+
}
|
|
2289
2200
|
const j = i;
|
|
2290
|
-
runners.push((
|
|
2201
|
+
runners.push(() => item.run(runners[j], args))
|
|
2291
2202
|
i ++;
|
|
2292
2203
|
}
|
|
2293
|
-
return runners[i](
|
|
2204
|
+
return runners[i]()
|
|
2294
2205
|
}
|
|
2295
2206
|
|
|
2296
2207
|
async function aopAsync(items, fn, args) {
|
|
2297
2208
|
let runners = [fn]
|
|
2298
2209
|
let i = 0
|
|
2299
2210
|
for (let item of [...items].reverse()) {
|
|
2211
|
+
if (!item.runAsync) {
|
|
2212
|
+
throw `${item.constructor.name} not suitable for async function`
|
|
2213
|
+
}
|
|
2300
2214
|
const j = i;
|
|
2301
|
-
runners.push(async (
|
|
2215
|
+
runners.push(async () => await item.runAsync(runners[j], args))
|
|
2302
2216
|
i ++;
|
|
2303
2217
|
}
|
|
2304
|
-
return await runners[i](
|
|
2218
|
+
return await runners[i]()
|
|
2305
2219
|
}
|
|
2306
2220
|
|
|
2307
2221
|
function getMd5Key(str) {
|
|
@@ -2320,7 +2234,7 @@ const tipFns = {
|
|
|
2320
2234
|
}
|
|
2321
2235
|
|
|
2322
2236
|
module.exports = {
|
|
2323
|
-
|
|
2237
|
+
formatSec,
|
|
2324
2238
|
wrapperJsirText,
|
|
2325
2239
|
run,
|
|
2326
2240
|
reget,
|
|
@@ -2329,13 +2243,8 @@ module.exports = {
|
|
|
2329
2243
|
ee,
|
|
2330
2244
|
regEach,
|
|
2331
2245
|
runSync,
|
|
2332
|
-
linuxAskAndKill,
|
|
2333
2246
|
cleanFile,
|
|
2334
|
-
fileCleaner,
|
|
2335
2247
|
getLibDataDir,
|
|
2336
|
-
lisPid,
|
|
2337
|
-
timeLoop,
|
|
2338
|
-
getLisPidDir,
|
|
2339
2248
|
mkdir,
|
|
2340
2249
|
bAdd,
|
|
2341
2250
|
bDiv,
|
|
@@ -2400,12 +2309,11 @@ module.exports = {
|
|
|
2400
2309
|
createConsole,
|
|
2401
2310
|
setTips,
|
|
2402
2311
|
delTips,
|
|
2403
|
-
timer,
|
|
2404
2312
|
createConfig,
|
|
2405
2313
|
getEditor,
|
|
2406
2314
|
setConfig,
|
|
2407
2315
|
trimEmptyLine,
|
|
2408
|
-
|
|
2316
|
+
taskQueue,
|
|
2409
2317
|
getLogDir,
|
|
2410
2318
|
getConfigDir,
|
|
2411
2319
|
getFullPath,
|
|
@@ -2418,7 +2326,6 @@ module.exports = {
|
|
|
2418
2326
|
getAlias,
|
|
2419
2327
|
createDirs,
|
|
2420
2328
|
getTempDir,
|
|
2421
|
-
terminalRun,
|
|
2422
2329
|
eia,
|
|
2423
2330
|
getKeyTips,
|
|
2424
2331
|
getValTips,
|
|
@@ -2440,5 +2347,8 @@ module.exports = {
|
|
|
2440
2347
|
getMd5Key,
|
|
2441
2348
|
isMd5Key,
|
|
2442
2349
|
terminalTitle,
|
|
2443
|
-
tipFns
|
|
2350
|
+
tipFns,
|
|
2351
|
+
getFileOpenExe,
|
|
2352
|
+
roomConsole: createConsole(null, roomLog, roomError),
|
|
2353
|
+
formatMb
|
|
2444
2354
|
}
|