xcraft-core-utils 4.3.6 → 4.3.7
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/.eslintrc.js +28 -28
- package/README.md +3 -3
- package/index.js +24 -24
- package/lib/.babelrc +8 -8
- package/lib/arrayCollector.js +33 -33
- package/lib/async.js +34 -34
- package/lib/batch.js +24 -24
- package/lib/crypto.js +92 -92
- package/lib/cursorPump.js +29 -29
- package/lib/eventDebouncer.js +21 -21
- package/lib/file-crypto.js +41 -41
- package/lib/files.js +144 -144
- package/lib/job-queue.js +113 -114
- package/lib/js.js +14 -14
- package/lib/json.js +12 -12
- package/lib/log.js +182 -182
- package/lib/modules.js +184 -184
- package/lib/os.js +13 -13
- package/lib/prop-types.js +154 -154
- package/lib/reflect.js +12 -12
- package/lib/regex.js +24 -24
- package/lib/runnerInstance.js +135 -134
- package/lib/string.js +15 -15
- package/lib/whereIs.js +13 -13
- package/lib/yaml.js +10 -10
- package/package.json +53 -53
- package/test/index.js +68 -68
- package/test/jobqueue.js +33 -33
package/lib/prop-types.js
CHANGED
|
@@ -1,154 +1,154 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const PropTypes = require('prop-types');
|
|
4
|
-
|
|
5
|
-
/******************************************************************************/
|
|
6
|
-
|
|
7
|
-
function getType(type) {
|
|
8
|
-
switch (type.type) {
|
|
9
|
-
case 'any':
|
|
10
|
-
return PropTypes.any;
|
|
11
|
-
case 'string':
|
|
12
|
-
case 'color':
|
|
13
|
-
case 'richColor':
|
|
14
|
-
case 'background':
|
|
15
|
-
case 'shortcut':
|
|
16
|
-
case 'angle':
|
|
17
|
-
case 'percentage':
|
|
18
|
-
case 'fontWeight':
|
|
19
|
-
case 'shape':
|
|
20
|
-
case 'horizontalSpacing':
|
|
21
|
-
case 'verticalSpacing':
|
|
22
|
-
case 'fontStyle':
|
|
23
|
-
case 'cursor':
|
|
24
|
-
case 'textTransform':
|
|
25
|
-
case 'justify':
|
|
26
|
-
case 'textJustify':
|
|
27
|
-
case 'date':
|
|
28
|
-
case 'time':
|
|
29
|
-
case 'datetime':
|
|
30
|
-
case 'price':
|
|
31
|
-
case 'weight':
|
|
32
|
-
case 'length':
|
|
33
|
-
case 'pixel':
|
|
34
|
-
case 'volume':
|
|
35
|
-
case 'percent':
|
|
36
|
-
case 'delay':
|
|
37
|
-
case 'place':
|
|
38
|
-
case 'transition':
|
|
39
|
-
return PropTypes.string;
|
|
40
|
-
case 'number':
|
|
41
|
-
return PropTypes.number;
|
|
42
|
-
case 'nabu':
|
|
43
|
-
return (props, propName, componentName) => {
|
|
44
|
-
const prop = props[propName];
|
|
45
|
-
if (prop !== null && prop !== undefined) {
|
|
46
|
-
if (typeof prop === 'object') {
|
|
47
|
-
let isNabu =
|
|
48
|
-
'nabuId' in prop ||
|
|
49
|
-
('_type' in prop &&
|
|
50
|
-
(prop['_type'] === 'translatableString' ||
|
|
51
|
-
prop['_type'] === 'translatableMarkdown'));
|
|
52
|
-
// Handle Map or OrderedMap
|
|
53
|
-
if (prop.get) {
|
|
54
|
-
isNabu = prop.get('nabuId') ? true : false;
|
|
55
|
-
if (!isNabu) {
|
|
56
|
-
isNabu =
|
|
57
|
-
prop.get('_type') === 'translatableString' ||
|
|
58
|
-
prop.get('_type') === 'translatableMarkdown';
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (!isNabu) {
|
|
62
|
-
return new Error(
|
|
63
|
-
'Invalid prop `' +
|
|
64
|
-
propName +
|
|
65
|
-
' of value "' +
|
|
66
|
-
prop +
|
|
67
|
-
'" supplied to' +
|
|
68
|
-
' `' +
|
|
69
|
-
componentName +
|
|
70
|
-
'`. Validation failed. Missing nabuId !'
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
} else if (typeof prop !== 'string' && typeof prop !== 'number') {
|
|
74
|
-
return new Error(
|
|
75
|
-
'Invalid prop `' +
|
|
76
|
-
propName +
|
|
77
|
-
' of value "' +
|
|
78
|
-
prop +
|
|
79
|
-
'" supplied to' +
|
|
80
|
-
' `' +
|
|
81
|
-
componentName +
|
|
82
|
-
'`. Validation failed.'
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
case 'glyph':
|
|
88
|
-
return PropTypes.oneOfType([
|
|
89
|
-
PropTypes.string,
|
|
90
|
-
PropTypes.shape({
|
|
91
|
-
glyph: PropTypes.string,
|
|
92
|
-
color: PropTypes.string,
|
|
93
|
-
}),
|
|
94
|
-
]);
|
|
95
|
-
case 'bool':
|
|
96
|
-
return PropTypes.oneOf([false, true]);
|
|
97
|
-
case 'enum':
|
|
98
|
-
return PropTypes.oneOf(type.values);
|
|
99
|
-
case 'component':
|
|
100
|
-
return PropTypes.node;
|
|
101
|
-
case 'function':
|
|
102
|
-
return PropTypes.func;
|
|
103
|
-
case 'grow':
|
|
104
|
-
return PropTypes.oneOfType([PropTypes.number, PropTypes.string]);
|
|
105
|
-
case 'oneOfType':
|
|
106
|
-
// eslint-disable-next-line no-case-declarations
|
|
107
|
-
const types = type.types.map((t) => getType(t));
|
|
108
|
-
return PropTypes.oneOfType(types);
|
|
109
|
-
default:
|
|
110
|
-
throw new Error(`Unknown prop type: '${type.type}'`);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function getPropType(prop) {
|
|
115
|
-
let propType = prop.type.propType || getType(prop.type);
|
|
116
|
-
if (prop.required && propType !== undefined) {
|
|
117
|
-
propType = propType.isRequired;
|
|
118
|
-
}
|
|
119
|
-
return propType;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function getDefaultProp(prop) {
|
|
123
|
-
if (prop.defaultValue !== undefined) {
|
|
124
|
-
return prop.defaultValue;
|
|
125
|
-
} else {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/******************************************************************************/
|
|
131
|
-
|
|
132
|
-
function makePropTypes(props) {
|
|
133
|
-
const propTypes = {};
|
|
134
|
-
for (const prop of props) {
|
|
135
|
-
propTypes[prop.name] = getPropType(prop);
|
|
136
|
-
}
|
|
137
|
-
return propTypes;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function makeDefaultProps(props) {
|
|
141
|
-
const defaultProps = {};
|
|
142
|
-
for (const prop of props) {
|
|
143
|
-
const d = getDefaultProp(prop);
|
|
144
|
-
if (d !== null) {
|
|
145
|
-
defaultProps[prop.name] = d;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return defaultProps;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
module.exports = {
|
|
152
|
-
makePropTypes,
|
|
153
|
-
makeDefaultProps,
|
|
154
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const PropTypes = require('prop-types');
|
|
4
|
+
|
|
5
|
+
/******************************************************************************/
|
|
6
|
+
|
|
7
|
+
function getType(type) {
|
|
8
|
+
switch (type.type) {
|
|
9
|
+
case 'any':
|
|
10
|
+
return PropTypes.any;
|
|
11
|
+
case 'string':
|
|
12
|
+
case 'color':
|
|
13
|
+
case 'richColor':
|
|
14
|
+
case 'background':
|
|
15
|
+
case 'shortcut':
|
|
16
|
+
case 'angle':
|
|
17
|
+
case 'percentage':
|
|
18
|
+
case 'fontWeight':
|
|
19
|
+
case 'shape':
|
|
20
|
+
case 'horizontalSpacing':
|
|
21
|
+
case 'verticalSpacing':
|
|
22
|
+
case 'fontStyle':
|
|
23
|
+
case 'cursor':
|
|
24
|
+
case 'textTransform':
|
|
25
|
+
case 'justify':
|
|
26
|
+
case 'textJustify':
|
|
27
|
+
case 'date':
|
|
28
|
+
case 'time':
|
|
29
|
+
case 'datetime':
|
|
30
|
+
case 'price':
|
|
31
|
+
case 'weight':
|
|
32
|
+
case 'length':
|
|
33
|
+
case 'pixel':
|
|
34
|
+
case 'volume':
|
|
35
|
+
case 'percent':
|
|
36
|
+
case 'delay':
|
|
37
|
+
case 'place':
|
|
38
|
+
case 'transition':
|
|
39
|
+
return PropTypes.string;
|
|
40
|
+
case 'number':
|
|
41
|
+
return PropTypes.number;
|
|
42
|
+
case 'nabu':
|
|
43
|
+
return (props, propName, componentName) => {
|
|
44
|
+
const prop = props[propName];
|
|
45
|
+
if (prop !== null && prop !== undefined) {
|
|
46
|
+
if (typeof prop === 'object') {
|
|
47
|
+
let isNabu =
|
|
48
|
+
'nabuId' in prop ||
|
|
49
|
+
('_type' in prop &&
|
|
50
|
+
(prop['_type'] === 'translatableString' ||
|
|
51
|
+
prop['_type'] === 'translatableMarkdown'));
|
|
52
|
+
// Handle Map or OrderedMap
|
|
53
|
+
if (prop.get) {
|
|
54
|
+
isNabu = prop.get('nabuId') ? true : false;
|
|
55
|
+
if (!isNabu) {
|
|
56
|
+
isNabu =
|
|
57
|
+
prop.get('_type') === 'translatableString' ||
|
|
58
|
+
prop.get('_type') === 'translatableMarkdown';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!isNabu) {
|
|
62
|
+
return new Error(
|
|
63
|
+
'Invalid prop `' +
|
|
64
|
+
propName +
|
|
65
|
+
' of value "' +
|
|
66
|
+
prop +
|
|
67
|
+
'" supplied to' +
|
|
68
|
+
' `' +
|
|
69
|
+
componentName +
|
|
70
|
+
'`. Validation failed. Missing nabuId !'
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
} else if (typeof prop !== 'string' && typeof prop !== 'number') {
|
|
74
|
+
return new Error(
|
|
75
|
+
'Invalid prop `' +
|
|
76
|
+
propName +
|
|
77
|
+
' of value "' +
|
|
78
|
+
prop +
|
|
79
|
+
'" supplied to' +
|
|
80
|
+
' `' +
|
|
81
|
+
componentName +
|
|
82
|
+
'`. Validation failed.'
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
case 'glyph':
|
|
88
|
+
return PropTypes.oneOfType([
|
|
89
|
+
PropTypes.string,
|
|
90
|
+
PropTypes.shape({
|
|
91
|
+
glyph: PropTypes.string,
|
|
92
|
+
color: PropTypes.string,
|
|
93
|
+
}),
|
|
94
|
+
]);
|
|
95
|
+
case 'bool':
|
|
96
|
+
return PropTypes.oneOf([false, true]);
|
|
97
|
+
case 'enum':
|
|
98
|
+
return PropTypes.oneOf(type.values);
|
|
99
|
+
case 'component':
|
|
100
|
+
return PropTypes.node;
|
|
101
|
+
case 'function':
|
|
102
|
+
return PropTypes.func;
|
|
103
|
+
case 'grow':
|
|
104
|
+
return PropTypes.oneOfType([PropTypes.number, PropTypes.string]);
|
|
105
|
+
case 'oneOfType':
|
|
106
|
+
// eslint-disable-next-line no-case-declarations
|
|
107
|
+
const types = type.types.map((t) => getType(t));
|
|
108
|
+
return PropTypes.oneOfType(types);
|
|
109
|
+
default:
|
|
110
|
+
throw new Error(`Unknown prop type: '${type.type}'`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function getPropType(prop) {
|
|
115
|
+
let propType = prop.type.propType || getType(prop.type);
|
|
116
|
+
if (prop.required && propType !== undefined) {
|
|
117
|
+
propType = propType.isRequired;
|
|
118
|
+
}
|
|
119
|
+
return propType;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function getDefaultProp(prop) {
|
|
123
|
+
if (prop.defaultValue !== undefined) {
|
|
124
|
+
return prop.defaultValue;
|
|
125
|
+
} else {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/******************************************************************************/
|
|
131
|
+
|
|
132
|
+
function makePropTypes(props) {
|
|
133
|
+
const propTypes = {};
|
|
134
|
+
for (const prop of props) {
|
|
135
|
+
propTypes[prop.name] = getPropType(prop);
|
|
136
|
+
}
|
|
137
|
+
return propTypes;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function makeDefaultProps(props) {
|
|
141
|
+
const defaultProps = {};
|
|
142
|
+
for (const prop of props) {
|
|
143
|
+
const d = getDefaultProp(prop);
|
|
144
|
+
if (d !== null) {
|
|
145
|
+
defaultProps[prop.name] = d;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return defaultProps;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = {
|
|
152
|
+
makePropTypes,
|
|
153
|
+
makeDefaultProps,
|
|
154
|
+
};
|
package/lib/reflect.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/gm;
|
|
4
|
-
const ARGUMENT_NAMES = /([^\s,]+)/g;
|
|
5
|
-
|
|
6
|
-
exports.funcParams = (func) => {
|
|
7
|
-
const fnStr = func.toString().replace(STRIP_COMMENTS, '');
|
|
8
|
-
const result = fnStr
|
|
9
|
-
.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')'))
|
|
10
|
-
.match(ARGUMENT_NAMES);
|
|
11
|
-
return result || [];
|
|
12
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const STRIP_COMMENTS = /(\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s*=[^,\)]*(('(?:\\'|[^'\r\n])*')|("(?:\\"|[^"\r\n])*"))|(\s*=[^,\)]*))/gm;
|
|
4
|
+
const ARGUMENT_NAMES = /([^\s,]+)/g;
|
|
5
|
+
|
|
6
|
+
exports.funcParams = (func) => {
|
|
7
|
+
const fnStr = func.toString().replace(STRIP_COMMENTS, '');
|
|
8
|
+
const result = fnStr
|
|
9
|
+
.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')'))
|
|
10
|
+
.match(ARGUMENT_NAMES);
|
|
11
|
+
return result || [];
|
|
12
|
+
};
|
package/lib/regex.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const escape = require('escape-regexp');
|
|
4
|
-
|
|
5
|
-
exports.toRegexp = function (value) {
|
|
6
|
-
if (value instanceof RegExp) {
|
|
7
|
-
return value;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
var escapeStringRegexp = require('escape-string-regexp');
|
|
11
|
-
return new RegExp('^' + escapeStringRegexp(value) + '$');
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
exports.toAxonRegExpStr = function (str) {
|
|
15
|
-
str = escape(str).replace(/\\\*/g, '(.+)');
|
|
16
|
-
return '^' + str + '$';
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
exports.toXcraftRegExpStr = function (str) {
|
|
20
|
-
str = escape(str)
|
|
21
|
-
.replace(/\\\((.+)\\\)/g, (m) => m.replace(/\\/g, ''))
|
|
22
|
-
.replace(/\\\*/g, '(.+)');
|
|
23
|
-
return '^' + str + '$';
|
|
24
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const escape = require('escape-regexp');
|
|
4
|
+
|
|
5
|
+
exports.toRegexp = function (value) {
|
|
6
|
+
if (value instanceof RegExp) {
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
var escapeStringRegexp = require('escape-string-regexp');
|
|
11
|
+
return new RegExp('^' + escapeStringRegexp(value) + '$');
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
exports.toAxonRegExpStr = function (str) {
|
|
15
|
+
str = escape(str).replace(/\\\*/g, '(.+)');
|
|
16
|
+
return '^' + str + '$';
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
exports.toXcraftRegExpStr = function (str) {
|
|
20
|
+
str = escape(str)
|
|
21
|
+
.replace(/\\\((.+)\\\)/g, (m) => m.replace(/\\/g, ''))
|
|
22
|
+
.replace(/\\\*/g, '(.+)');
|
|
23
|
+
return '^' + str + '$';
|
|
24
|
+
};
|
package/lib/runnerInstance.js
CHANGED
|
@@ -1,134 +1,135 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// create a unique, global symbol name
|
|
4
|
-
// -----------------------------------
|
|
5
|
-
const RUNNER_INSTANCE_KEY = Symbol.for('xcraft-core-utils.runnerInstance');
|
|
6
|
-
const watt = require('gigawatts');
|
|
7
|
-
|
|
8
|
-
class Runner {
|
|
9
|
-
constructor() {
|
|
10
|
-
this.totalRunning = 0;
|
|
11
|
-
this.runningsGroups = [];
|
|
12
|
-
this.runnings = {};
|
|
13
|
-
this.run = this.run.bind(this);
|
|
14
|
-
watt.wrapAll(this);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
run(jobQueue) {
|
|
18
|
-
//must be postponed?
|
|
19
|
-
if (jobQueue.waitOn.length > 0) {
|
|
20
|
-
const mustWait = this.runningsGroups.some((q) =>
|
|
21
|
-
jobQueue.waitOn.includes(q)
|
|
22
|
-
);
|
|
23
|
-
if (mustWait) {
|
|
24
|
-
if (!jobQueue.maxAttemptReached) {
|
|
25
|
-
jobQueue.attempt++;
|
|
26
|
-
setTimeout(this.run, jobQueue.waitDelay, jobQueue);
|
|
27
|
-
return;
|
|
28
|
-
} else {
|
|
29
|
-
jobQueue.attempt = 0;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
//queue is draining?
|
|
35
|
-
if (jobQueue.running > 0 && jobQueue.waiting.size === 0) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
//jobqueue releasing
|
|
40
|
-
for (let x = jobQueue.running; x < jobQueue.parallelLimit; x++) {
|
|
41
|
-
const nextEntry = jobQueue.waiting.entries().next();
|
|
42
|
-
if (nextEntry.done) {
|
|
43
|
-
//we can leave, nothing is waiting us
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
//remove the jobEntry from queue
|
|
48
|
-
const jobEntry = Object.assign({}, nextEntry.value);
|
|
49
|
-
jobQueue.waiting.delete(jobEntry[0]);
|
|
50
|
-
|
|
51
|
-
//log for journal inspections
|
|
52
|
-
if (this.totalRunning === 0 && jobQueue.parallelLimit > 1) {
|
|
53
|
-
jobQueue._dbg(`system are running new jobs`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
//priority tracking
|
|
57
|
-
if (jobQueue.priorityGroup !== 'default' && jobQueue.running === 0) {
|
|
58
|
-
if (!this.runnings[jobQueue.priorityGroup]) {
|
|
59
|
-
this.runnings[jobQueue.priorityGroup] = {};
|
|
60
|
-
}
|
|
61
|
-
this.runnings[jobQueue.priorityGroup][jobQueue.name] = true;
|
|
62
|
-
//update runnings group
|
|
63
|
-
this.runningsGroups = Object.entries(this.runnings)
|
|
64
|
-
.filter((e) => Object.values(e[1]).some((r) => r === true))
|
|
65
|
-
.map((e) => e[0]);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
//update counters
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
//
|
|
134
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// create a unique, global symbol name
|
|
4
|
+
// -----------------------------------
|
|
5
|
+
const RUNNER_INSTANCE_KEY = Symbol.for('xcraft-core-utils.runnerInstance');
|
|
6
|
+
const watt = require('gigawatts');
|
|
7
|
+
|
|
8
|
+
class Runner {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.totalRunning = 0;
|
|
11
|
+
this.runningsGroups = [];
|
|
12
|
+
this.runnings = {};
|
|
13
|
+
this.run = this.run.bind(this);
|
|
14
|
+
watt.wrapAll(this);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
run(jobQueue) {
|
|
18
|
+
//must be postponed?
|
|
19
|
+
if (jobQueue.waitOn.length > 0) {
|
|
20
|
+
const mustWait = this.runningsGroups.some((q) =>
|
|
21
|
+
jobQueue.waitOn.includes(q)
|
|
22
|
+
);
|
|
23
|
+
if (mustWait) {
|
|
24
|
+
if (!jobQueue.maxAttemptReached) {
|
|
25
|
+
jobQueue.attempt++;
|
|
26
|
+
setTimeout(this.run, jobQueue.waitDelay, jobQueue);
|
|
27
|
+
return;
|
|
28
|
+
} else {
|
|
29
|
+
jobQueue.attempt = 0;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//queue is draining?
|
|
35
|
+
if (jobQueue.running > 0 && jobQueue.waiting.size === 0) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//jobqueue releasing
|
|
40
|
+
for (let x = jobQueue.running; x < jobQueue.parallelLimit; x++) {
|
|
41
|
+
const nextEntry = jobQueue.waiting.entries().next();
|
|
42
|
+
if (nextEntry.done) {
|
|
43
|
+
//we can leave, nothing is waiting us
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//remove the jobEntry from queue
|
|
48
|
+
const jobEntry = Object.assign({}, nextEntry.value);
|
|
49
|
+
jobQueue.waiting.delete(jobEntry[0]);
|
|
50
|
+
|
|
51
|
+
//log for journal inspections
|
|
52
|
+
if (this.totalRunning === 0 && jobQueue.parallelLimit > 1) {
|
|
53
|
+
jobQueue._dbg(`system are running new jobs`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
//priority tracking
|
|
57
|
+
if (jobQueue.priorityGroup !== 'default' && jobQueue.running === 0) {
|
|
58
|
+
if (!this.runnings[jobQueue.priorityGroup]) {
|
|
59
|
+
this.runnings[jobQueue.priorityGroup] = {};
|
|
60
|
+
}
|
|
61
|
+
this.runnings[jobQueue.priorityGroup][jobQueue.name] = true;
|
|
62
|
+
//update runnings group
|
|
63
|
+
this.runningsGroups = Object.entries(this.runnings)
|
|
64
|
+
.filter((e) => Object.values(e[1]).some((r) => r === true))
|
|
65
|
+
.map((e) => e[0]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
//update counters
|
|
69
|
+
jobQueue.running++;
|
|
70
|
+
this.totalRunning++;
|
|
71
|
+
|
|
72
|
+
//trigger job start on queue runner
|
|
73
|
+
jobQueue.runner(jobEntry[1], (err) => {
|
|
74
|
+
if (err) {
|
|
75
|
+
jobQueue.err(err);
|
|
76
|
+
}
|
|
77
|
+
//end callback
|
|
78
|
+
|
|
79
|
+
jobQueue.notify(jobQueue.runningSamples);
|
|
80
|
+
|
|
81
|
+
//update counter
|
|
82
|
+
jobQueue.running--;
|
|
83
|
+
this.totalRunning--;
|
|
84
|
+
|
|
85
|
+
//priority tracking
|
|
86
|
+
if (jobQueue.priorityGroup !== 'default' && jobQueue.running === 0) {
|
|
87
|
+
this.runnings[jobQueue.priorityGroup][jobQueue.name] = false;
|
|
88
|
+
//update runnings group
|
|
89
|
+
this.runningsGroups = Object.entries(this.runnings)
|
|
90
|
+
.filter((e) => Object.values(e[1]).some((r) => r === true))
|
|
91
|
+
.map((e) => e[0]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
//log
|
|
95
|
+
if (this.totalRunning === 0 && jobQueue.waiting.size === 0) {
|
|
96
|
+
jobQueue._dbg(`no more jobs running`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
//schedule a new run for this queue if needed
|
|
100
|
+
if (jobQueue.waiting.size > 0) {
|
|
101
|
+
setTimeout(this.run, 0, jobQueue);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// check if the global object has this symbol
|
|
109
|
+
// add it if it does not have the symbol, yet
|
|
110
|
+
// ------------------------------------------
|
|
111
|
+
const globalSymbols = Object.getOwnPropertySymbols(global);
|
|
112
|
+
const hasInstance = globalSymbols.indexOf(RUNNER_INSTANCE_KEY) > -1;
|
|
113
|
+
if (!hasInstance) {
|
|
114
|
+
global[RUNNER_INSTANCE_KEY] = new Runner();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// define the singleton API
|
|
118
|
+
// ------------------------
|
|
119
|
+
|
|
120
|
+
const singleton = {};
|
|
121
|
+
|
|
122
|
+
Object.defineProperty(singleton, 'instance', {
|
|
123
|
+
get: function () {
|
|
124
|
+
return global[RUNNER_INSTANCE_KEY];
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// ensure the API is never changed
|
|
129
|
+
// -------------------------------
|
|
130
|
+
|
|
131
|
+
Object.freeze(singleton);
|
|
132
|
+
|
|
133
|
+
// export the singleton API only
|
|
134
|
+
// -----------------------------
|
|
135
|
+
module.exports = singleton;
|