@abtnode/router-provider 1.15.17 → 1.16.0-beta-8ee536d7
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/README.md +1 -1
- package/lib/base.js +14 -0
- package/lib/default/daemon.js +338 -0
- package/lib/default/index.js +252 -0
- package/lib/default/proxy.js +556 -0
- package/lib/index.js +32 -23
- package/lib/nginx/includes/cache +6 -0
- package/lib/nginx/includes/params +1 -10
- package/lib/nginx/includes/proxy +8 -0
- package/lib/nginx/index.js +397 -281
- package/lib/nginx/util.js +77 -67
- package/lib/util.js +214 -0
- package/lib/www/502.html +1 -1
- package/lib/www/5xx.html +1 -1
- package/package.json +29 -19
- package/lib/none/index.js +0 -50
package/lib/nginx/util.js
CHANGED
|
@@ -8,13 +8,16 @@ const { NginxConfFile } = require('nginx-conf');
|
|
|
8
8
|
const shelljs = require('shelljs');
|
|
9
9
|
const findProcess = require('find-process');
|
|
10
10
|
const moment = require('moment');
|
|
11
|
-
const { MAX_UPLOAD_FILE_SIZE,
|
|
12
|
-
const
|
|
13
|
-
const {
|
|
14
|
-
const logger = require('@abtnode/logger')(`${require('../../package.json').name}:provider:nginx:util`);
|
|
11
|
+
const { MAX_UPLOAD_FILE_SIZE, MAX_NGINX_WORKER_CONNECTIONS, ROUTER_CACHE_GROUPS } = require('@abtnode/constant');
|
|
12
|
+
const formatBackSlash = require('@abtnode/util/lib/format-back-slash');
|
|
13
|
+
const { deleteOldLogfiles } = require('@abtnode/logger');
|
|
15
14
|
|
|
15
|
+
const logger = require('@abtnode/logger')('router:nginx:util');
|
|
16
|
+
|
|
17
|
+
const MAX_WORKER_CONNECTIONS = process.env.MAX_NGINX_WORKER_CONNECTIONS
|
|
18
|
+
? Number(process.env.MAX_NGINX_WORKER_CONNECTIONS)
|
|
19
|
+
: MAX_NGINX_WORKER_CONNECTIONS;
|
|
16
20
|
const CLIENT_MAX_BODY_SIZE = process.env.MAX_UPLOAD_FILE_SIZE || MAX_UPLOAD_FILE_SIZE;
|
|
17
|
-
const WORKER_CONNECTIONS = 4096;
|
|
18
21
|
|
|
19
22
|
const formatError = (errStr) => {
|
|
20
23
|
if (!errStr) {
|
|
@@ -43,10 +46,10 @@ const formatError = (errStr) => {
|
|
|
43
46
|
).join(';');
|
|
44
47
|
};
|
|
45
48
|
|
|
46
|
-
const addTestServer = ({
|
|
49
|
+
const addTestServer = ({ configPath, port, upstreamPort }) =>
|
|
47
50
|
new Promise((resolve, reject) => {
|
|
48
51
|
// eslint-disable-next-line consistent-return
|
|
49
|
-
NginxConfFile.create(
|
|
52
|
+
NginxConfFile.create(configPath, async (err, conf) => {
|
|
50
53
|
if (err) {
|
|
51
54
|
return reject(err);
|
|
52
55
|
}
|
|
@@ -58,23 +61,27 @@ const addTestServer = ({ configFilePath, port, upstreamPort }) =>
|
|
|
58
61
|
|
|
59
62
|
location / {
|
|
60
63
|
if ($uri = /admin/did-connect) {include includes/cors-strict; include includes/security;}
|
|
61
|
-
return 200 'Hello
|
|
64
|
+
return 200 'Hello Blocklet Server!';
|
|
62
65
|
}
|
|
63
66
|
`
|
|
64
67
|
);
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
if (upstreamPort && os.platform() !== 'win32') {
|
|
70
|
+
conf.nginx._addVerbatimBlock(
|
|
71
|
+
'stream',
|
|
72
|
+
`
|
|
69
73
|
server {
|
|
70
74
|
listen ${upstreamPort} udp;
|
|
75
|
+
proxy_responses 1;
|
|
76
|
+
proxy_timeout 1s;
|
|
71
77
|
proxy_pass 127.0.0.1:${port};
|
|
72
78
|
}
|
|
73
79
|
`
|
|
74
|
-
|
|
80
|
+
);
|
|
81
|
+
}
|
|
75
82
|
|
|
76
83
|
conf.on('flushed', () => resolve());
|
|
77
|
-
conf.live(
|
|
84
|
+
conf.live(configPath);
|
|
78
85
|
conf.flush();
|
|
79
86
|
});
|
|
80
87
|
});
|
|
@@ -129,9 +136,21 @@ const getUserGroup = (username) => {
|
|
|
129
136
|
return res.stdout.trim();
|
|
130
137
|
};
|
|
131
138
|
|
|
139
|
+
const getWorkerConnectionCount = (maxWorkerConnections, workerProcess) => {
|
|
140
|
+
const { stdout, code } = shelljs.exec('ulimit -n', { silent: true });
|
|
141
|
+
if (code !== 0) {
|
|
142
|
+
return maxWorkerConnections;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const ulimit = Number(stdout.trim());
|
|
146
|
+
|
|
147
|
+
return Math.min(maxWorkerConnections, Math.floor(ulimit / workerProcess));
|
|
148
|
+
};
|
|
149
|
+
|
|
132
150
|
const getMainTemplate = ({
|
|
133
151
|
logDir,
|
|
134
|
-
|
|
152
|
+
tmpDir,
|
|
153
|
+
cacheDir,
|
|
135
154
|
nginxLoadModules = '',
|
|
136
155
|
workerProcess,
|
|
137
156
|
maxBodySize = CLIENT_MAX_BODY_SIZE,
|
|
@@ -144,37 +163,55 @@ user ${os.userInfo().username} ${getUserGroup(os.userInfo().username)};
|
|
|
144
163
|
pid nginx.pid;
|
|
145
164
|
|
|
146
165
|
events {
|
|
147
|
-
worker_connections ${
|
|
166
|
+
worker_connections ${getWorkerConnectionCount(MAX_WORKER_CONNECTIONS, workerProcess)};
|
|
167
|
+
multi_accept on;
|
|
148
168
|
}
|
|
149
169
|
|
|
150
170
|
http {
|
|
151
171
|
map $http_upgrade $connection_upgrade {
|
|
152
172
|
default upgrade;
|
|
153
|
-
''
|
|
173
|
+
'' "";
|
|
154
174
|
}
|
|
155
|
-
client_body_temp_path ${path.join(
|
|
156
|
-
proxy_temp_path ${path.join(
|
|
157
|
-
fastcgi_temp_path ${path.join(
|
|
158
|
-
uwsgi_temp_path ${path.join(
|
|
159
|
-
scgi_temp_path ${path.join(
|
|
175
|
+
client_body_temp_path ${path.join(tmpDir, 'client_body')};
|
|
176
|
+
proxy_temp_path ${path.join(tmpDir, 'proxy')};
|
|
177
|
+
fastcgi_temp_path ${path.join(tmpDir, 'fastcgi')};
|
|
178
|
+
uwsgi_temp_path ${path.join(tmpDir, 'uwsgi')};
|
|
179
|
+
scgi_temp_path ${path.join(tmpDir, 'scgi')};
|
|
160
180
|
client_max_body_size ${maxBodySize}m;
|
|
181
|
+
variables_hash_max_size 2048;
|
|
182
|
+
variables_hash_bucket_size 128;
|
|
183
|
+
|
|
184
|
+
absolute_redirect off;
|
|
161
185
|
|
|
162
186
|
log_format compression '$remote_addr - $remote_user [$time_local] '
|
|
163
|
-
'"$request" $status $body_bytes_sent '
|
|
164
|
-
'"$http_referer" "$http_user_agent" "$
|
|
187
|
+
'"$host" "$request" $status $body_bytes_sent '
|
|
188
|
+
'"$http_referer" "$http_user_agent" "$http_x_forwarded_for" $request_time';
|
|
165
189
|
access_log ${path.join(logDir, 'access.log')} compression;
|
|
166
190
|
error_log ${path.join(logDir, 'error.log')} error;
|
|
167
191
|
|
|
168
192
|
include includes/params;
|
|
169
193
|
include includes/mime.types;
|
|
170
194
|
include includes/compression;
|
|
195
|
+
|
|
196
|
+
${Object.keys(ROUTER_CACHE_GROUPS)
|
|
197
|
+
.map((x) => getCachePathDirective(cacheDir, x))
|
|
198
|
+
.join('\n')}
|
|
171
199
|
}
|
|
172
200
|
`;
|
|
173
201
|
|
|
202
|
+
const getCachePathDirective = (cacheDir, group) => {
|
|
203
|
+
if (!ROUTER_CACHE_GROUPS[group]) {
|
|
204
|
+
return '';
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const config = ROUTER_CACHE_GROUPS[group];
|
|
208
|
+
return `proxy_cache_path ${cacheDir}/${group} levels=1:2 keys_zone=${group}:${config.minSize} inactive=${config.period} max_size=${config.maxSize};`;
|
|
209
|
+
};
|
|
210
|
+
|
|
174
211
|
const getNginxStatus = async (configPath) => {
|
|
175
212
|
const list = await findProcess('name', /nginx:/);
|
|
176
213
|
const result = {
|
|
177
|
-
|
|
214
|
+
managed: false,
|
|
178
215
|
pid: 0,
|
|
179
216
|
running: false,
|
|
180
217
|
};
|
|
@@ -184,7 +221,7 @@ const getNginxStatus = async (configPath) => {
|
|
|
184
221
|
result.running = true;
|
|
185
222
|
|
|
186
223
|
if (abtnodeNginxProcess) {
|
|
187
|
-
result.
|
|
224
|
+
result.managed = true;
|
|
188
225
|
result.pid = abtnodeNginxProcess.pid;
|
|
189
226
|
}
|
|
190
227
|
|
|
@@ -194,37 +231,6 @@ const getNginxStatus = async (configPath) => {
|
|
|
194
231
|
return result;
|
|
195
232
|
};
|
|
196
233
|
|
|
197
|
-
const decideHttpPort = (port) => port || process.env.ABT_NODE_HTTP_PORT || DEFAULT_HTTP_PORT;
|
|
198
|
-
const decideHttpsPort = (port) => port || process.env.ABT_NODE_HTTPS_PORT || DEFAULT_HTTPS_PORT;
|
|
199
|
-
|
|
200
|
-
const findCertificate = (certs, domain) => {
|
|
201
|
-
const results = certs
|
|
202
|
-
.filter((cert) => [cert.domain, ...(cert.sans || [])].some((d) => checkDomainMatch(d, domain)))
|
|
203
|
-
.sort((d1) => (d1.domain[0] === '*' ? 1 : -1)); // will first match a.b.com, then *.b.com
|
|
204
|
-
return results[0];
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* trim tail slash
|
|
209
|
-
* @param {string} str
|
|
210
|
-
* @returns {string}
|
|
211
|
-
*/
|
|
212
|
-
const trimEndSlash = (str) => {
|
|
213
|
-
if (str && str.length > 1 && str[str.length - 1] === '/') {
|
|
214
|
-
return str.substr(0, str.length - 1);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return str;
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
const concatPath = (prefix = '', suffix = '') => {
|
|
221
|
-
if (prefix === '/') {
|
|
222
|
-
return suffix ? `~* .*${suffix}$` : '/';
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return suffix ? `~* ^${prefix}.*${suffix}$` : prefix;
|
|
226
|
-
};
|
|
227
|
-
|
|
228
234
|
const compressFile = ({ sourceFile, targetFile, options = {} }) => {
|
|
229
235
|
if (fs.existsSync(targetFile)) {
|
|
230
236
|
fs.unlinkSync(targetFile);
|
|
@@ -242,7 +248,7 @@ const compressFile = ({ sourceFile, targetFile, options = {} }) => {
|
|
|
242
248
|
* rotate log files: access file and access log
|
|
243
249
|
* refer: https://www.nginx.com/resources/wiki/start/topics/examples/logrotation/
|
|
244
250
|
*/
|
|
245
|
-
const rotateNginxLogFile = async ({ file, cwd, nginxPid }) => {
|
|
251
|
+
const rotateNginxLogFile = async ({ file, cwd, nginxPid, retain }) => {
|
|
246
252
|
const dateStr = moment().subtract(1, 'days').format('YYYY-MM-DD');
|
|
247
253
|
const uncompressedTargetLogfile = path.join(cwd, `${path.basename(file, '.log')}-${dateStr}.log`);
|
|
248
254
|
const targetLogfile = path.join(cwd, `${path.basename(file, '.log')}-${dateStr}.log.gz`);
|
|
@@ -271,6 +277,8 @@ const rotateNginxLogFile = async ({ file, cwd, nginxPid }) => {
|
|
|
271
277
|
}
|
|
272
278
|
}
|
|
273
279
|
}
|
|
280
|
+
|
|
281
|
+
deleteOldLogfiles(file, retain);
|
|
274
282
|
};
|
|
275
283
|
|
|
276
284
|
const getMissingModules = (configParams) => {
|
|
@@ -290,23 +298,25 @@ const getMissingModules = (configParams) => {
|
|
|
290
298
|
return missingModules;
|
|
291
299
|
};
|
|
292
300
|
|
|
301
|
+
const getUpstreamName = (port) => `server_${port}`;
|
|
302
|
+
|
|
303
|
+
const joinNginxPath = (...args) => {
|
|
304
|
+
const result = path.join(...args);
|
|
305
|
+
return formatBackSlash(result);
|
|
306
|
+
};
|
|
307
|
+
|
|
293
308
|
module.exports = {
|
|
294
309
|
addTestServer,
|
|
310
|
+
formatError,
|
|
295
311
|
getMainTemplate,
|
|
296
312
|
getNginxLoadModuleDirectives,
|
|
297
|
-
formatError,
|
|
298
313
|
getMissingModules,
|
|
299
314
|
parseNginxConfigArgs,
|
|
300
|
-
decideHttpPort,
|
|
301
|
-
decideHttpsPort,
|
|
302
|
-
concatPath,
|
|
303
|
-
trimEndSlash,
|
|
304
|
-
findCertificate,
|
|
305
315
|
getNginxStatus,
|
|
306
316
|
rotateNginxLogFile,
|
|
307
317
|
getUserGroup,
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
318
|
+
getWorkerConnectionCount,
|
|
319
|
+
getCachePathDirective,
|
|
320
|
+
getUpstreamName,
|
|
321
|
+
joinNginxPath,
|
|
312
322
|
};
|
package/lib/util.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/* eslint-disable no-await-in-loop */
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const getPort = require('get-port');
|
|
5
|
+
const portUsed = require('port-used');
|
|
6
|
+
const sortBy = require('lodash/sortBy');
|
|
7
|
+
const isValidDomain = require('is-valid-domain');
|
|
8
|
+
const checkDomainMatch = require('@abtnode/util/lib/check-domain-match');
|
|
9
|
+
const normalizePathPrefix = require('@abtnode/util/lib/normalize-path-prefix');
|
|
10
|
+
const { template404, template502, template5xx, templateWelcome } = require('@abtnode/router-templates');
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
IP,
|
|
14
|
+
DEFAULT_HTTP_PORT,
|
|
15
|
+
DEFAULT_HTTPS_PORT,
|
|
16
|
+
DEFAULT_IP_DOMAIN_SUFFIX,
|
|
17
|
+
DOMAIN_FOR_DEFAULT_SITE,
|
|
18
|
+
ROUTING_RULE_TYPES,
|
|
19
|
+
SLOT_FOR_IP_DNS_SITE,
|
|
20
|
+
} = require('@abtnode/constant');
|
|
21
|
+
|
|
22
|
+
const decideHttpPort = (port) => port || process.env.ABT_NODE_HTTP_PORT || DEFAULT_HTTP_PORT;
|
|
23
|
+
const decideHttpsPort = (port) => port || process.env.ABT_NODE_HTTPS_PORT || DEFAULT_HTTPS_PORT;
|
|
24
|
+
|
|
25
|
+
const findCertificate = (certs, domain) => {
|
|
26
|
+
const results = certs
|
|
27
|
+
.filter((cert) => [cert.domain, ...(cert.sans || [])].some((d) => checkDomainMatch(d, domain)))
|
|
28
|
+
.sort((d1) => (d1.domain[0] === '*' ? 1 : -1)); // will first match a.b.com, then *.b.com
|
|
29
|
+
return results[0];
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const trimEndSlash = (str) => {
|
|
33
|
+
if (str && str.length > 1 && str[str.length - 1] === '/') {
|
|
34
|
+
return str.substr(0, str.length - 1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return str;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const concatPath = (prefix = '', suffix = '') => {
|
|
41
|
+
if (prefix === '/') {
|
|
42
|
+
return suffix ? `~* .*${suffix}$` : '/';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return suffix ? `~* ^${prefix}.*${suffix}$` : prefix;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const formatRoutingTable = (routingTable, onRule) => {
|
|
49
|
+
const sites = {};
|
|
50
|
+
const configs = [];
|
|
51
|
+
|
|
52
|
+
routingTable.forEach((site) => {
|
|
53
|
+
let { domain } = site;
|
|
54
|
+
if (site.domain === DOMAIN_FOR_DEFAULT_SITE) {
|
|
55
|
+
domain = '_';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let corsAllowedOrigins = Array.isArray(site.corsAllowedOrigins) ? site.corsAllowedOrigins : [];
|
|
59
|
+
if (corsAllowedOrigins.includes('*')) {
|
|
60
|
+
corsAllowedOrigins = ['*'];
|
|
61
|
+
}
|
|
62
|
+
configs.push({ domain, corsAllowedOrigins });
|
|
63
|
+
|
|
64
|
+
if (!sites[domain]) {
|
|
65
|
+
sites[domain] = {
|
|
66
|
+
domain,
|
|
67
|
+
blockletDid: site.blockletDid,
|
|
68
|
+
rules: [],
|
|
69
|
+
port: site.port,
|
|
70
|
+
corsAllowedOrigins: site.corsAllowedOrigins,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
(site.rules || []).forEach((x) => {
|
|
75
|
+
const prefix = trimEndSlash(x.from.pathPrefix || '/');
|
|
76
|
+
const groupPrefix = trimEndSlash(x.from.groupPathPrefix || '/');
|
|
77
|
+
const suffix = trimEndSlash(x.from.pathSuffix || '');
|
|
78
|
+
|
|
79
|
+
const rule = {
|
|
80
|
+
ruleId: x.id,
|
|
81
|
+
type: x.to.type,
|
|
82
|
+
prefix,
|
|
83
|
+
groupPrefix,
|
|
84
|
+
suffix,
|
|
85
|
+
response: x.to.response,
|
|
86
|
+
};
|
|
87
|
+
if (x.to.type === ROUTING_RULE_TYPES.REDIRECT) {
|
|
88
|
+
rule.redirectCode = x.to.redirectCode || 302;
|
|
89
|
+
rule.url = x.to.url;
|
|
90
|
+
} else {
|
|
91
|
+
rule.port = +x.to.port;
|
|
92
|
+
rule.did = x.to.did;
|
|
93
|
+
rule.cacheGroup = x.to.cacheGroup;
|
|
94
|
+
rule.componentId = x.to.componentId;
|
|
95
|
+
rule.target = trimEndSlash(normalizePathPrefix(x.to.target || '/'));
|
|
96
|
+
rule.targetPrefix = x.to.targetPrefix || '';
|
|
97
|
+
rule.services = x.services || [];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const tmpPath = concatPath(prefix, suffix);
|
|
101
|
+
const tmpRules = sites[domain].rules;
|
|
102
|
+
if (!tmpRules.find(({ prefix: p, suffix: s }) => concatPath(p, s) === tmpPath)) {
|
|
103
|
+
sites[domain].rules.push(rule);
|
|
104
|
+
if (typeof onRule === 'function') {
|
|
105
|
+
onRule(sites[domain].rules, rule);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const { rules } = sites[domain];
|
|
111
|
+
const rulesWithoutSuffix = sortBy(rules.filter((x) => !x.suffix), (x) => -x.prefix.length); // prettier-ignore
|
|
112
|
+
const rulesWithSuffix = sortBy(rules.filter((x) => x.suffix), (x) => -x.prefix.length); // prettier-ignore
|
|
113
|
+
|
|
114
|
+
sites[domain].rules = rulesWithoutSuffix.concat(rulesWithSuffix);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return { sites: Object.values(sites), configs };
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
*
|
|
121
|
+
*
|
|
122
|
+
* @param {string} domain
|
|
123
|
+
* @return {boolean}
|
|
124
|
+
*/
|
|
125
|
+
const isSpecificDomain = (domain) => {
|
|
126
|
+
if (isValidDomain(domain) === false) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return !domain.endsWith(DEFAULT_IP_DOMAIN_SUFFIX);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const toSlotDomain = (domain) => {
|
|
134
|
+
if (domain.endsWith(DEFAULT_IP_DOMAIN_SUFFIX)) {
|
|
135
|
+
const subDomain = domain.split('.').shift();
|
|
136
|
+
const matches = subDomain.match(IP);
|
|
137
|
+
if (matches) {
|
|
138
|
+
return domain.replace(matches[0].slice(1), SLOT_FOR_IP_DNS_SITE);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return domain;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const findRule = (rules, url) =>
|
|
146
|
+
rules.find((x) => {
|
|
147
|
+
const { prefix, suffix = '' } = x;
|
|
148
|
+
if (suffix) {
|
|
149
|
+
return url.startsWith(prefix) && url.endsWith(suffix);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (prefix === '/' && prefix === url) {
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return url.startsWith(prefix);
|
|
157
|
+
});
|
|
158
|
+
const matchRule = (rules, url) => {
|
|
159
|
+
const rulesWithSuffix = rules.filter((x) => x.suffix);
|
|
160
|
+
const rulesWithoutSuffix = rules.filter((x) => !x.suffix);
|
|
161
|
+
return findRule(rulesWithSuffix, url) || findRule(rulesWithoutSuffix, url);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const isPortOccupied = (port) => portUsed.check(port);
|
|
165
|
+
const getUsablePort = async (preferredPorts, hasPortPermission) => {
|
|
166
|
+
for (const port of preferredPorts) {
|
|
167
|
+
const occupied = await isPortOccupied(port);
|
|
168
|
+
if (!occupied) {
|
|
169
|
+
const listenable = await hasPortPermission(port);
|
|
170
|
+
if (listenable) {
|
|
171
|
+
return port;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return getPort();
|
|
177
|
+
};
|
|
178
|
+
const getUsablePorts = async (provider, hasPortPermission) => {
|
|
179
|
+
const file = path.join(process.env.PM2_HOME, `${provider}-preferred-ports.json`);
|
|
180
|
+
if (fs.existsSync(file)) {
|
|
181
|
+
const config = fs.readJsonSync(file);
|
|
182
|
+
if (config.httpPort && config.httpsPort) {
|
|
183
|
+
return config;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const [httpPort, httpsPort] = await Promise.all([
|
|
188
|
+
getUsablePort([80, 8080], hasPortPermission),
|
|
189
|
+
getUsablePort([443, 8443], hasPortPermission),
|
|
190
|
+
]);
|
|
191
|
+
|
|
192
|
+
const config = { httpPort, httpsPort };
|
|
193
|
+
fs.writeJsonSync(file, config);
|
|
194
|
+
return config;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
module.exports = {
|
|
198
|
+
decideHttpPort,
|
|
199
|
+
decideHttpsPort,
|
|
200
|
+
getUsablePorts,
|
|
201
|
+
getUsablePort,
|
|
202
|
+
isPortOccupied,
|
|
203
|
+
findCertificate,
|
|
204
|
+
concatPath,
|
|
205
|
+
trimEndSlash,
|
|
206
|
+
formatRoutingTable,
|
|
207
|
+
isSpecificDomain,
|
|
208
|
+
toSlotDomain,
|
|
209
|
+
matchRule,
|
|
210
|
+
get404Template: (info) => template404(info),
|
|
211
|
+
get502Template: (info) => template502(info),
|
|
212
|
+
get5xxTemplate: (info) => template5xx(info),
|
|
213
|
+
getWelcomeTemplate: (info) => templateWelcome(info),
|
|
214
|
+
};
|
package/lib/www/502.html
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<h2>Bad gateway: Upstream Blocklet or Daemon service is not available!</h2>
|
|
23
23
|
<div>
|
|
24
24
|
Checkout Blocklet Server Documentation:
|
|
25
|
-
<a href="https://
|
|
25
|
+
<a href="https://developer.blocklet.io/docs">https://developer.blocklet.io/docs</a>
|
|
26
26
|
</div>
|
|
27
27
|
</center>
|
|
28
28
|
</body>
|
package/lib/www/5xx.html
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<h2>Something went wrong</h2>
|
|
23
23
|
<div>
|
|
24
24
|
Checkout Blocklet Server Documentation:
|
|
25
|
-
<a href="https://
|
|
25
|
+
<a href="https://developer.blocklet.io/docs">https://developer.blocklet.io/docs</a>
|
|
26
26
|
</div>
|
|
27
27
|
</center>
|
|
28
28
|
</body>
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abtnode/router-provider",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0-beta-8ee536d7",
|
|
4
4
|
"description": "Routing engine implementations for abt node",
|
|
5
5
|
"author": "polunzh <polunzh@gmail.com>",
|
|
6
|
-
"homepage": "https://github.com/ArcBlock/
|
|
6
|
+
"homepage": "https://github.com/ArcBlock/blocklet-server#readme",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"publishConfig": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
],
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
|
-
"url": "git+https://github.com/ArcBlock/
|
|
21
|
+
"url": "git+https://github.com/ArcBlock/blocklet-server.git"
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
24
|
"lint": "eslint tests lib",
|
|
@@ -29,28 +29,38 @@
|
|
|
29
29
|
"coverage": "npm run test -- --coverage"
|
|
30
30
|
},
|
|
31
31
|
"bugs": {
|
|
32
|
-
"url": "https://github.com/ArcBlock/
|
|
32
|
+
"url": "https://github.com/ArcBlock/blocklet-server/issues"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@abtnode/constant": "1.
|
|
36
|
-
"@abtnode/logger": "1.
|
|
37
|
-
"@abtnode/router-templates": "1.
|
|
38
|
-
"@abtnode/util": "1.
|
|
39
|
-
"axios": "^0.
|
|
40
|
-
"debug": "^4.3.
|
|
41
|
-
"find-process": "^1.4.
|
|
42
|
-
"fkill": "^7.
|
|
43
|
-
"fs-extra": "^10.
|
|
35
|
+
"@abtnode/constant": "1.16.0-beta-8ee536d7",
|
|
36
|
+
"@abtnode/logger": "1.16.0-beta-8ee536d7",
|
|
37
|
+
"@abtnode/router-templates": "1.16.0-beta-8ee536d7",
|
|
38
|
+
"@abtnode/util": "1.16.0-beta-8ee536d7",
|
|
39
|
+
"axios": "^0.27.2",
|
|
40
|
+
"debug": "^4.3.4",
|
|
41
|
+
"find-process": "^1.4.7",
|
|
42
|
+
"fkill": "^7.2.1",
|
|
43
|
+
"fs-extra": "^10.1.0",
|
|
44
44
|
"get-port": "^5.1.1",
|
|
45
|
+
"http-proxy": "^1.18.1",
|
|
46
|
+
"is-valid-domain": "^0.1.6",
|
|
45
47
|
"lodash": "^4.17.21",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
+
"lru-cache": "^7.14.0",
|
|
49
|
+
"moment": "^2.29.4",
|
|
50
|
+
"nginx-conf": "^1.7.0",
|
|
51
|
+
"object-hash": "^3.0.0",
|
|
52
|
+
"port-used": "^2.0.8",
|
|
48
53
|
"promise-retry": "^2.0.1",
|
|
49
|
-
"shelljs": "^0.8.
|
|
50
|
-
"tar": "^6.1.
|
|
54
|
+
"shelljs": "^0.8.5",
|
|
55
|
+
"tar": "^6.1.11",
|
|
56
|
+
"url-join": "^4.0.1",
|
|
57
|
+
"uuid": "^8.3.2",
|
|
58
|
+
"valid-url": "^1.0.9"
|
|
51
59
|
},
|
|
52
60
|
"devDependencies": {
|
|
53
|
-
"
|
|
61
|
+
"bluebird": "^3.7.2",
|
|
62
|
+
"fs-extra": "^10.1.0",
|
|
63
|
+
"needle": "^3.1.0"
|
|
54
64
|
},
|
|
55
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "57d0c45be311a5fbc1c0fffa2814b62c1a3ee34c"
|
|
56
66
|
}
|
package/lib/none/index.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-empty-function */
|
|
2
|
-
const BaseProvider = require('../base');
|
|
3
|
-
|
|
4
|
-
class NoneProvider extends BaseProvider {
|
|
5
|
-
constructor() {
|
|
6
|
-
super('none');
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
async update() {}
|
|
10
|
-
|
|
11
|
-
async reload() {}
|
|
12
|
-
|
|
13
|
-
async start() {}
|
|
14
|
-
|
|
15
|
-
async restart() {}
|
|
16
|
-
|
|
17
|
-
async stop() {}
|
|
18
|
-
|
|
19
|
-
initialize() {}
|
|
20
|
-
|
|
21
|
-
async validateConfig() {}
|
|
22
|
-
|
|
23
|
-
async rotateLogs() {}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
NoneProvider.describe = () => {
|
|
27
|
-
const result = NoneProvider.check();
|
|
28
|
-
return {
|
|
29
|
-
name: 'none',
|
|
30
|
-
description: 'This provider does nothing, you must access blocklets through IP + Port',
|
|
31
|
-
error: result.error,
|
|
32
|
-
available: result.available,
|
|
33
|
-
running: result.running,
|
|
34
|
-
};
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
NoneProvider.check = () => ({
|
|
38
|
-
available: true,
|
|
39
|
-
running: true,
|
|
40
|
-
error: '',
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
NoneProvider.getStatus = () => ({
|
|
44
|
-
pid: 0,
|
|
45
|
-
running: false,
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
NoneProvider.exists = () => true;
|
|
49
|
-
|
|
50
|
-
module.exports = NoneProvider;
|