ee-core 2.0.3 → 2.1.0-beta.3
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/bin/tools.js +4 -0
- package/config/config.default.js +9 -0
- package/const/channel.js +10 -1
- package/core/lib/ee.js +1 -1
- package/core/lib/loader/file_loader.js +2 -2
- package/core/lib/loader/mixin/config.js +1 -1
- package/core/lib/utils/index.js +1 -1
- package/ee/eeApp.js +8 -7
- package/exception/index.js +40 -12
- package/httpclient/index.js +4 -12
- package/index.js +1 -1
- package/jobs/child/app.js +11 -2
- package/jobs/child/forkProcess.js +81 -6
- package/jobs/child/index.js +41 -45
- package/jobs/child-pool/index.js +205 -0
- package/jobs/index.js +3 -1
- package/jobs/load-balancer/algorithm/index.js +12 -0
- package/jobs/load-balancer/algorithm/minimumConnection.js +19 -0
- package/jobs/load-balancer/algorithm/polling.js +12 -0
- package/jobs/load-balancer/algorithm/random.js +10 -0
- package/jobs/load-balancer/algorithm/specify.js +15 -0
- package/jobs/load-balancer/algorithm/weights.js +22 -0
- package/jobs/load-balancer/algorithm/weightsMinimumConnection.js +30 -0
- package/jobs/load-balancer/algorithm/weightsPolling.js +23 -0
- package/jobs/load-balancer/algorithm/weightsRandom.js +17 -0
- package/jobs/load-balancer/consts.js +10 -0
- package/jobs/load-balancer/index.js +202 -0
- package/jobs/load-balancer/scheduler.js +32 -0
- package/loader/index.js +22 -2
- package/message/childMessage.js +23 -0
- package/package.json +1 -6
- package/ps/index.js +44 -0
- package/tools/encrypt.js +105 -45
- package/utils/co.js +237 -0
- package/utils/depd/index.js +538 -0
- package/utils/depd/lib/browser/index.js +77 -0
- package/utils/extend.js +73 -0
- package/utils/get-port/index.d.ts +64 -0
- package/utils/get-port/index.js +109 -0
- package/utils/helper.js +25 -1
- package/utils/index.js +46 -0
- package/utils/ip.js +261 -0
- package/utils/is.js +2 -1
- package/utils/time/index.js +20 -0
- package/utils/time/ms.js +162 -0
- package/jobs/childPool/app.js +0 -62
- package/jobs/childPool/forkProcess.js +0 -81
- package/jobs/childPool/index.js +0 -71
- package/jobs/childPool/pool.js +0 -67
- /package/{oldUtils → old-utils}/index.js +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/// <reference types="node"/>
|
|
2
|
+
import {ListenOptions} from 'net';
|
|
3
|
+
|
|
4
|
+
declare namespace getPort {
|
|
5
|
+
interface Options extends Omit<ListenOptions, 'port'> {
|
|
6
|
+
/**
|
|
7
|
+
A preferred port or an iterable of preferred ports to use.
|
|
8
|
+
*/
|
|
9
|
+
readonly port?: number | Iterable<number>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
The host on which port resolution should be performed. Can be either an IPv4 or IPv6 address.
|
|
13
|
+
*/
|
|
14
|
+
readonly host?: string;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare const getPort: {
|
|
19
|
+
/**
|
|
20
|
+
Get an available TCP port number.
|
|
21
|
+
|
|
22
|
+
@returns Port number.
|
|
23
|
+
|
|
24
|
+
@example
|
|
25
|
+
```
|
|
26
|
+
import getPort = require('get-port');
|
|
27
|
+
|
|
28
|
+
(async () => {
|
|
29
|
+
console.log(await getPort());
|
|
30
|
+
//=> 51402
|
|
31
|
+
|
|
32
|
+
// Pass in a preferred port
|
|
33
|
+
console.log(await getPort({port: 3000}));
|
|
34
|
+
// Will use 3000 if available, otherwise fall back to a random port
|
|
35
|
+
|
|
36
|
+
// Pass in an array of preferred ports
|
|
37
|
+
console.log(await getPort({port: [3000, 3001, 3002]}));
|
|
38
|
+
// Will use any element in the preferred ports array if available, otherwise fall back to a random port
|
|
39
|
+
})();
|
|
40
|
+
```
|
|
41
|
+
*/
|
|
42
|
+
(options?: getPort.Options): Promise<number>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
Make a range of ports `from`...`to`.
|
|
46
|
+
|
|
47
|
+
@param from - First port of the range. Must be in the range `1024`...`65535`.
|
|
48
|
+
@param to - Last port of the range. Must be in the range `1024`...`65535` and must be greater than `from`.
|
|
49
|
+
@returns The ports in the range.
|
|
50
|
+
|
|
51
|
+
@example
|
|
52
|
+
```
|
|
53
|
+
import getPort = require('get-port');
|
|
54
|
+
|
|
55
|
+
(async () => {
|
|
56
|
+
console.log(await getPort({port: getPort.makeRange(3000, 3100)}));
|
|
57
|
+
// Will use any port from 3000 to 3100, otherwise fall back to a random port
|
|
58
|
+
})();
|
|
59
|
+
```
|
|
60
|
+
*/
|
|
61
|
+
makeRange(from: number, to: number): Iterable<number>;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export = getPort;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const net = require('net');
|
|
3
|
+
|
|
4
|
+
class Locked extends Error {
|
|
5
|
+
constructor(port) {
|
|
6
|
+
super(`${port} is locked`);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const lockedPorts = {
|
|
11
|
+
old: new Set(),
|
|
12
|
+
young: new Set()
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// On this interval, the old locked ports are discarded,
|
|
16
|
+
// the young locked ports are moved to old locked ports,
|
|
17
|
+
// and a new young set for locked ports are created.
|
|
18
|
+
const releaseOldLockedPortsIntervalMs = 1000 * 15;
|
|
19
|
+
|
|
20
|
+
// Lazily create interval on first use
|
|
21
|
+
let interval;
|
|
22
|
+
|
|
23
|
+
const getAvailablePort = options => new Promise((resolve, reject) => {
|
|
24
|
+
const server = net.createServer();
|
|
25
|
+
server.unref();
|
|
26
|
+
server.on('error', reject);
|
|
27
|
+
server.listen(options, () => {
|
|
28
|
+
const {port} = server.address();
|
|
29
|
+
server.close(() => {
|
|
30
|
+
resolve(port);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const portCheckSequence = function * (ports) {
|
|
36
|
+
if (ports) {
|
|
37
|
+
yield * ports;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
yield 0; // Fall back to 0 if anything else failed
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
module.exports = async options => {
|
|
44
|
+
let ports;
|
|
45
|
+
|
|
46
|
+
if (options) {
|
|
47
|
+
ports = typeof options.port === 'number' ? [options.port] : options.port;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (interval === undefined) {
|
|
51
|
+
interval = setInterval(() => {
|
|
52
|
+
lockedPorts.old = lockedPorts.young;
|
|
53
|
+
lockedPorts.young = new Set();
|
|
54
|
+
}, releaseOldLockedPortsIntervalMs);
|
|
55
|
+
|
|
56
|
+
// Does not exist in some environments (Electron, Jest jsdom env, browser, etc).
|
|
57
|
+
if (interval.unref) {
|
|
58
|
+
interval.unref();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const port of portCheckSequence(ports)) {
|
|
63
|
+
try {
|
|
64
|
+
let availablePort = await getAvailablePort({...options, port}); // eslint-disable-line no-await-in-loop
|
|
65
|
+
while (lockedPorts.old.has(availablePort) || lockedPorts.young.has(availablePort)) {
|
|
66
|
+
if (port !== 0) {
|
|
67
|
+
throw new Locked(port);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
availablePort = await getAvailablePort({...options, port}); // eslint-disable-line no-await-in-loop
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
lockedPorts.young.add(availablePort);
|
|
74
|
+
return availablePort;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
if (!['EADDRINUSE', 'EACCES'].includes(error.code) && !(error instanceof Locked)) {
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
throw new Error('No available ports found');
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
module.exports.makeRange = (from, to) => {
|
|
86
|
+
if (!Number.isInteger(from) || !Number.isInteger(to)) {
|
|
87
|
+
throw new TypeError('`from` and `to` must be integer numbers');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (from < 1024 || from > 65535) {
|
|
91
|
+
throw new RangeError('`from` must be between 1024 and 65535');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (to < 1024 || to > 65536) {
|
|
95
|
+
throw new RangeError('`to` must be between 1024 and 65536');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (to < from) {
|
|
99
|
+
throw new RangeError('`to` must be greater than or equal to `from`');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const generator = function * (from, to) {
|
|
103
|
+
for (let port = from; port <= to; port++) {
|
|
104
|
+
yield port;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return generator(from, to);
|
|
109
|
+
};
|
package/utils/helper.js
CHANGED
|
@@ -2,7 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const mkdirp = require('mkdirp');
|
|
3
3
|
const convert = require('koa-convert');
|
|
4
4
|
const is = require('is-type-of');
|
|
5
|
-
const co = require('co');
|
|
5
|
+
const co = require('./co');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* fnDebounce
|
|
@@ -114,3 +114,27 @@ exports.callFn = async function (fn, args, ctx) {
|
|
|
114
114
|
exports.middleware = function (fn) {
|
|
115
115
|
return is.generatorFunction(fn) ? convert(fn) : fn;
|
|
116
116
|
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 序列化对象
|
|
120
|
+
*/
|
|
121
|
+
exports.stringify = function(obj, ignore = []) {
|
|
122
|
+
const result = {};
|
|
123
|
+
Object.keys(obj).forEach(key => {
|
|
124
|
+
if (!ignore.includes(key)) {
|
|
125
|
+
result[key] = obj[key];
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
return JSON.stringify(result);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 是否有效值
|
|
133
|
+
*/
|
|
134
|
+
exports.validValue = function(value) {
|
|
135
|
+
return (
|
|
136
|
+
value !== undefined &&
|
|
137
|
+
value !== null &&
|
|
138
|
+
value !== ''
|
|
139
|
+
);
|
|
140
|
+
}
|
package/utils/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const os = require("os");
|
|
1
4
|
const path = require('path');
|
|
2
5
|
const Ps = require('../ps');
|
|
3
6
|
const UtilsJson = require('./json');
|
|
@@ -11,5 +14,48 @@ exports.getPackage = function() {
|
|
|
11
14
|
return json;
|
|
12
15
|
};
|
|
13
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Get the first proper MAC address
|
|
19
|
+
* @param iface If provided, restrict MAC address fetching to this interface
|
|
20
|
+
*/
|
|
21
|
+
exports.getMAC = function(iface) {
|
|
22
|
+
const zeroRegex = /(?:[0]{1,2}[:-]){5}[0]{1,2}/;
|
|
23
|
+
const list = os.networkInterfaces();
|
|
24
|
+
if (iface) {
|
|
25
|
+
const parts = list[iface];
|
|
26
|
+
if (!parts) {
|
|
27
|
+
throw new Error(`interface ${iface} was not found`);
|
|
28
|
+
}
|
|
29
|
+
for (const part of parts) {
|
|
30
|
+
if (zeroRegex.test(part.mac) === false) {
|
|
31
|
+
return part.mac;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
throw new Error(`interface ${iface} had no valid mac addresses`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
for (const [key, parts] of Object.entries(list)) {
|
|
38
|
+
// for some reason beyond me, this is needed to satisfy typescript
|
|
39
|
+
// fix https://github.com/bevry/getmac/issues/100
|
|
40
|
+
if (!parts)
|
|
41
|
+
continue;
|
|
42
|
+
for (const part of parts) {
|
|
43
|
+
if (zeroRegex.test(part.mac) === false) {
|
|
44
|
+
return part.mac;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
throw new Error('failed to get the MAC address');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Check if the input is a valid MAC address
|
|
54
|
+
*/
|
|
55
|
+
exports.isMAC = function(macAddress) {
|
|
56
|
+
const macRegex = /(?:[a-z0-9]{1,2}[:-]){5}[a-z0-9]{1,2}/i;
|
|
57
|
+
return macRegex.test(macAddress);
|
|
58
|
+
}
|
|
59
|
+
|
|
14
60
|
|
|
15
61
|
|
package/utils/ip.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
const { promisify } = require('util');
|
|
2
|
+
const dgram = require('dgram');
|
|
3
|
+
const { isIPv6, isIPv4 } = require('net');
|
|
4
|
+
const dns = require('dns-socket');
|
|
5
|
+
const HttpClient = require('../httpclient');
|
|
6
|
+
|
|
7
|
+
const emptyIP = '';
|
|
8
|
+
const defaults = {
|
|
9
|
+
timeout: 3000,
|
|
10
|
+
type: 'http', // 'http' | 'dns' | 'all'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const dnsServers = [
|
|
14
|
+
{
|
|
15
|
+
v4: {
|
|
16
|
+
servers: [
|
|
17
|
+
'208.67.222.222',
|
|
18
|
+
'208.67.220.220',
|
|
19
|
+
'208.67.222.220',
|
|
20
|
+
'208.67.220.222',
|
|
21
|
+
],
|
|
22
|
+
name: 'myip.opendns.com',
|
|
23
|
+
type: 'A',
|
|
24
|
+
},
|
|
25
|
+
v6: {
|
|
26
|
+
servers: [
|
|
27
|
+
'2620:0:ccc::2',
|
|
28
|
+
'2620:0:ccd::2',
|
|
29
|
+
],
|
|
30
|
+
name: 'myip.opendns.com',
|
|
31
|
+
type: 'AAAA',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const type = {
|
|
37
|
+
v4: {
|
|
38
|
+
dnsServers: dnsServers.map(({v4: {servers, ...question}}) => ({
|
|
39
|
+
servers, question,
|
|
40
|
+
})),
|
|
41
|
+
httpsUrls: [
|
|
42
|
+
'https://icanhazip.com/',
|
|
43
|
+
'https://api.ipify.org/',
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
v6: {
|
|
47
|
+
dnsServers: dnsServers.map(({v6: {servers, ...question}}) => ({
|
|
48
|
+
servers, question,
|
|
49
|
+
})),
|
|
50
|
+
httpsUrls: [
|
|
51
|
+
'https://icanhazip.com/',
|
|
52
|
+
'https://api6.ipify.org/',
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const queryDns = (version, options) => {
|
|
58
|
+
const data = type[version];
|
|
59
|
+
const socket = dns({
|
|
60
|
+
retries: 0,
|
|
61
|
+
maxQueries: 1,
|
|
62
|
+
socket: dgram.createSocket(version === 'v6' ? 'udp6' : 'udp4'),
|
|
63
|
+
timeout: options.timeout,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const socketQuery = promisify(socket.query.bind(socket));
|
|
67
|
+
const promise = (async () => {
|
|
68
|
+
for (const dnsServerInfo of data.dnsServers) {
|
|
69
|
+
const {servers, question} = dnsServerInfo;
|
|
70
|
+
for (const server of servers) {
|
|
71
|
+
if (socket.destroyed) {
|
|
72
|
+
return emptyIP;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const {name, type, transform} = question;
|
|
77
|
+
const dnsResponse = await socketQuery({questions: [{name, type}]}, 53, server);
|
|
78
|
+
|
|
79
|
+
const {
|
|
80
|
+
answers: {
|
|
81
|
+
0: {
|
|
82
|
+
data,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
} = dnsResponse;
|
|
86
|
+
const response = (typeof data === 'string' ? data : data.toString()).trim();
|
|
87
|
+
const ip = (transform && version === 'v6') ? transform(response) : response;
|
|
88
|
+
const method = version === 'v6' ? isIPv6 : isIPv4;
|
|
89
|
+
|
|
90
|
+
if (ip && method(ip)) {
|
|
91
|
+
socket.destroy();
|
|
92
|
+
return ip;
|
|
93
|
+
}
|
|
94
|
+
} catch (error) {
|
|
95
|
+
// Log.coreLogger.error('[ee-core] [utils/ip] queryDns error:', error);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
socket.destroy();
|
|
101
|
+
return emptyIP;
|
|
102
|
+
})();
|
|
103
|
+
|
|
104
|
+
promise.cancel = () => {
|
|
105
|
+
socket.destroy();
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
return promise;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const queryHttps = (version, options) => {
|
|
112
|
+
let cancel;
|
|
113
|
+
const hc = new HttpClient();
|
|
114
|
+
|
|
115
|
+
const promise = (async () => {
|
|
116
|
+
const requestOptions = {
|
|
117
|
+
method: 'GET',
|
|
118
|
+
timeout: options.timeout,
|
|
119
|
+
dataType: 'text',
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const urls = [
|
|
123
|
+
...type[version].httpsUrls,
|
|
124
|
+
...(options.fallbackUrls ?? []),
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
for (const url of urls) {
|
|
128
|
+
try {
|
|
129
|
+
const gotPromise = hc.request(url, requestOptions);
|
|
130
|
+
gotPromise.cancel = () => {
|
|
131
|
+
// todo
|
|
132
|
+
}
|
|
133
|
+
cancel = gotPromise.cancel;
|
|
134
|
+
|
|
135
|
+
const response = await gotPromise;
|
|
136
|
+
let result = response.status == 200 ? response.data : '';
|
|
137
|
+
const ip = result.trim();
|
|
138
|
+
|
|
139
|
+
const method = version === 'v6' ? isIPv6 : isIPv4;
|
|
140
|
+
|
|
141
|
+
if (ip && method(ip)) {
|
|
142
|
+
return ip;
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
//Log.coreLogger.error('[ee-core] [utils/ip] queryHttps error:', error);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return emptyIP;
|
|
150
|
+
})();
|
|
151
|
+
|
|
152
|
+
promise.cancel = function () {
|
|
153
|
+
return cancel.apply(this);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
return promise;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const queryAll = (version, options) => {
|
|
160
|
+
let cancel;
|
|
161
|
+
const promise = (async () => {
|
|
162
|
+
let response;
|
|
163
|
+
const dnsPromise = queryDns(version, options);
|
|
164
|
+
cancel = dnsPromise.cancel;
|
|
165
|
+
try {
|
|
166
|
+
response = await dnsPromise;
|
|
167
|
+
} catch {
|
|
168
|
+
const httpsPromise = queryHttps(version, options);
|
|
169
|
+
cancel = httpsPromise.cancel;
|
|
170
|
+
response = await httpsPromise;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return response;
|
|
174
|
+
})();
|
|
175
|
+
|
|
176
|
+
promise.cancel = cancel;
|
|
177
|
+
|
|
178
|
+
return promise;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 查询 public ipv4
|
|
183
|
+
*/
|
|
184
|
+
function publicIpv4(options) {
|
|
185
|
+
options = {
|
|
186
|
+
...defaults,
|
|
187
|
+
...options,
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
if (options.type == 'http') {
|
|
191
|
+
return queryHttps('v4', options);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (options.type == 'dns') {
|
|
195
|
+
return queryDns('v4', options);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return queryAll('v4', options);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 查询public ipv6
|
|
203
|
+
*/
|
|
204
|
+
function publicIpv6(options) {
|
|
205
|
+
options = {
|
|
206
|
+
...defaults,
|
|
207
|
+
...options,
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
if (options.type == 'http') {
|
|
211
|
+
return queryHttps('v6', options);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (options.type == 'dns') {
|
|
215
|
+
return queryDns('v6', options);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return queryAll('v6', options);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* todo 未来趋势是ipv6优先,以后再放开
|
|
223
|
+
*/
|
|
224
|
+
const publicIp = createPublicIp(publicIpv4, publicIpv6);
|
|
225
|
+
function createPublicIp(publicIpv4, publicIpv6) {
|
|
226
|
+
return function publicIp(options) {
|
|
227
|
+
const ipv4Promise = publicIpv4(options);
|
|
228
|
+
const ipv6Promise = publicIpv6(options);
|
|
229
|
+
|
|
230
|
+
const promise = (async () => {
|
|
231
|
+
try {
|
|
232
|
+
const ipv6 = await ipv6Promise;
|
|
233
|
+
ipv4Promise.cancel();
|
|
234
|
+
return ipv6;
|
|
235
|
+
} catch (ipv6Error) {
|
|
236
|
+
//Log.coreLogger.error('[ee-core] [utils/ip] publicIp ipv6Error:', ipv6Error);
|
|
237
|
+
try {
|
|
238
|
+
return await ipv4Promise;
|
|
239
|
+
} catch (ipv4Error) {
|
|
240
|
+
//Log.coreLogger.error('[ee-core] [utils/ip] publicIp ipv4Error:', ipv4Error);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
})();
|
|
244
|
+
|
|
245
|
+
promise.cancel = () => {
|
|
246
|
+
ipv4Promise.cancel();
|
|
247
|
+
ipv6Promise.cancel();
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
return promise;
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const IP = {
|
|
255
|
+
//publicIp,
|
|
256
|
+
publicIpv4,
|
|
257
|
+
publicIpv6
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
module.exports = IP;
|
|
261
|
+
|
package/utils/is.js
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const util = require('util');
|
|
4
|
+
const ms = require('./ms');
|
|
5
|
+
|
|
6
|
+
function humanizeToMs (t) {
|
|
7
|
+
if (typeof t === 'number') return t;
|
|
8
|
+
var r = ms(t);
|
|
9
|
+
if (r === undefined) {
|
|
10
|
+
var err = new Error(util.format('humanize-ms(%j) result undefined', t));
|
|
11
|
+
console.warn(err.stack);
|
|
12
|
+
}
|
|
13
|
+
return r;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const TIME = {
|
|
17
|
+
humanizeToMs,
|
|
18
|
+
ms
|
|
19
|
+
}
|
|
20
|
+
module.exports = TIME;
|
package/utils/time/ms.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
var s = 1000;
|
|
6
|
+
var m = s * 60;
|
|
7
|
+
var h = m * 60;
|
|
8
|
+
var d = h * 24;
|
|
9
|
+
var w = d * 7;
|
|
10
|
+
var y = d * 365.25;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Parse or format the given `val`.
|
|
14
|
+
*
|
|
15
|
+
* Options:
|
|
16
|
+
*
|
|
17
|
+
* - `long` verbose formatting [false]
|
|
18
|
+
*
|
|
19
|
+
* @param {String|Number} val
|
|
20
|
+
* @param {Object} [options]
|
|
21
|
+
* @throws {Error} throw an error if val is not a non-empty string or a number
|
|
22
|
+
* @return {String|Number}
|
|
23
|
+
* @api public
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
module.exports = function(val, options) {
|
|
27
|
+
options = options || {};
|
|
28
|
+
var type = typeof val;
|
|
29
|
+
if (type === 'string' && val.length > 0) {
|
|
30
|
+
return parse(val);
|
|
31
|
+
} else if (type === 'number' && isFinite(val)) {
|
|
32
|
+
return options.long ? fmtLong(val) : fmtShort(val);
|
|
33
|
+
}
|
|
34
|
+
throw new Error(
|
|
35
|
+
'val is not a non-empty string or a valid number. val=' +
|
|
36
|
+
JSON.stringify(val)
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Parse the given `str` and return milliseconds.
|
|
42
|
+
*
|
|
43
|
+
* @param {String} str
|
|
44
|
+
* @return {Number}
|
|
45
|
+
* @api private
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
function parse(str) {
|
|
49
|
+
str = String(str);
|
|
50
|
+
if (str.length > 100) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
|
|
54
|
+
str
|
|
55
|
+
);
|
|
56
|
+
if (!match) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
var n = parseFloat(match[1]);
|
|
60
|
+
var type = (match[2] || 'ms').toLowerCase();
|
|
61
|
+
switch (type) {
|
|
62
|
+
case 'years':
|
|
63
|
+
case 'year':
|
|
64
|
+
case 'yrs':
|
|
65
|
+
case 'yr':
|
|
66
|
+
case 'y':
|
|
67
|
+
return n * y;
|
|
68
|
+
case 'weeks':
|
|
69
|
+
case 'week':
|
|
70
|
+
case 'w':
|
|
71
|
+
return n * w;
|
|
72
|
+
case 'days':
|
|
73
|
+
case 'day':
|
|
74
|
+
case 'd':
|
|
75
|
+
return n * d;
|
|
76
|
+
case 'hours':
|
|
77
|
+
case 'hour':
|
|
78
|
+
case 'hrs':
|
|
79
|
+
case 'hr':
|
|
80
|
+
case 'h':
|
|
81
|
+
return n * h;
|
|
82
|
+
case 'minutes':
|
|
83
|
+
case 'minute':
|
|
84
|
+
case 'mins':
|
|
85
|
+
case 'min':
|
|
86
|
+
case 'm':
|
|
87
|
+
return n * m;
|
|
88
|
+
case 'seconds':
|
|
89
|
+
case 'second':
|
|
90
|
+
case 'secs':
|
|
91
|
+
case 'sec':
|
|
92
|
+
case 's':
|
|
93
|
+
return n * s;
|
|
94
|
+
case 'milliseconds':
|
|
95
|
+
case 'millisecond':
|
|
96
|
+
case 'msecs':
|
|
97
|
+
case 'msec':
|
|
98
|
+
case 'ms':
|
|
99
|
+
return n;
|
|
100
|
+
default:
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Short format for `ms`.
|
|
107
|
+
*
|
|
108
|
+
* @param {Number} ms
|
|
109
|
+
* @return {String}
|
|
110
|
+
* @api private
|
|
111
|
+
*/
|
|
112
|
+
|
|
113
|
+
function fmtShort(ms) {
|
|
114
|
+
var msAbs = Math.abs(ms);
|
|
115
|
+
if (msAbs >= d) {
|
|
116
|
+
return Math.round(ms / d) + 'd';
|
|
117
|
+
}
|
|
118
|
+
if (msAbs >= h) {
|
|
119
|
+
return Math.round(ms / h) + 'h';
|
|
120
|
+
}
|
|
121
|
+
if (msAbs >= m) {
|
|
122
|
+
return Math.round(ms / m) + 'm';
|
|
123
|
+
}
|
|
124
|
+
if (msAbs >= s) {
|
|
125
|
+
return Math.round(ms / s) + 's';
|
|
126
|
+
}
|
|
127
|
+
return ms + 'ms';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Long format for `ms`.
|
|
132
|
+
*
|
|
133
|
+
* @param {Number} ms
|
|
134
|
+
* @return {String}
|
|
135
|
+
* @api private
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
function fmtLong(ms) {
|
|
139
|
+
var msAbs = Math.abs(ms);
|
|
140
|
+
if (msAbs >= d) {
|
|
141
|
+
return plural(ms, msAbs, d, 'day');
|
|
142
|
+
}
|
|
143
|
+
if (msAbs >= h) {
|
|
144
|
+
return plural(ms, msAbs, h, 'hour');
|
|
145
|
+
}
|
|
146
|
+
if (msAbs >= m) {
|
|
147
|
+
return plural(ms, msAbs, m, 'minute');
|
|
148
|
+
}
|
|
149
|
+
if (msAbs >= s) {
|
|
150
|
+
return plural(ms, msAbs, s, 'second');
|
|
151
|
+
}
|
|
152
|
+
return ms + ' ms';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Pluralization helper.
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
function plural(ms, msAbs, n, name) {
|
|
160
|
+
var isPlural = msAbs >= n * 1.5;
|
|
161
|
+
return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
|
|
162
|
+
}
|