@abtnode/router-provider 1.6.29 → 1.7.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.
@@ -4,11 +4,7 @@ const fs = require('fs-extra');
4
4
  const get = require('lodash/get');
5
5
  const joinUrl = require('url-join');
6
6
  const checkDomainMatch = require('@abtnode/util/lib/check-domain-match');
7
- const {
8
- DEFAULT_IP_DNS_DOMAIN_SUFFIX,
9
- ROUTING_RULE_TYPES,
10
- WELLKNOWN_SERVICE_PATH_PREFIX,
11
- } = require('@abtnode/constant');
7
+ const { DEFAULT_IP_DOMAIN_SUFFIX, ROUTING_RULE_TYPES, WELLKNOWN_SERVICE_PATH_PREFIX } = require('@abtnode/constant');
12
8
 
13
9
  const logger = require('@abtnode/logger')('router:default:daemon', { filename: 'engine' });
14
10
 
@@ -65,15 +61,13 @@ const createRequestHandler = (id) => (req, res, target) => {
65
61
  }
66
62
  }
67
63
 
68
- // FIXME logic related to server gateway should not in provider
69
- const rewritePathPrefix = rule.prefix.replace(WELLKNOWN_SERVICE_PATH_PREFIX, '') || '/';
70
-
71
64
  if (rule.type === ROUTING_RULE_TYPES.GENERAL_PROXY) {
72
- // we do not need rewrite for internal servers
65
+ // do not rewrite for internal servers
66
+ } else if (rule.prefix.includes(WELLKNOWN_SERVICE_PATH_PREFIX)) {
67
+ // do not rewrite for service requests
73
68
  } else {
74
- req.url = req.url.substr(rewritePathPrefix.length);
69
+ req.url = joinUrl(rule.target, req.url.substr(rule.prefix.length));
75
70
  }
76
-
77
71
  if (req.url.startsWith('/') === false) {
78
72
  req.url = `/${req.url}`;
79
73
  }
@@ -86,7 +80,7 @@ const createRequestHandler = (id) => (req, res, target) => {
86
80
  req.headers['X-Blocklet-Real-Did'] = rule.realDid;
87
81
  }
88
82
 
89
- req.headers['X-Path-Prefix'] = rewritePathPrefix;
83
+ req.headers['X-Path-Prefix'] = rule.prefix.replace(WELLKNOWN_SERVICE_PATH_PREFIX, '') || '/';
90
84
  req.headers['X-Group-Path-Prefix'] = rule.groupPrefix || '/';
91
85
 
92
86
  if (rule.type === ROUTING_RULE_TYPES.BLOCKLET) {
@@ -281,7 +275,7 @@ const updateConfig = (reload = false) => {
281
275
  updateConfig();
282
276
 
283
277
  // create main server
284
- const defaultCert = config.certs.find((x) => x.domain.endsWith(DEFAULT_IP_DNS_DOMAIN_SUFFIX));
278
+ const defaultCert = config.certs.find((x) => x.domain.endsWith(DEFAULT_IP_DOMAIN_SUFFIX));
285
279
  const main = new ProxyServer({
286
280
  xfwd: true,
287
281
  onError,
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs-extra');
2
2
  const path = require('path');
3
+ const http = require('http');
3
4
  const shelljs = require('shelljs');
4
5
  const get = require('lodash/get');
5
6
  const omit = require('lodash/omit');
@@ -15,6 +16,7 @@ const BaseProvider = require('../base');
15
16
  const {
16
17
  decideHttpPort,
17
18
  decideHttpsPort,
19
+ getUsablePorts,
18
20
  get404Template,
19
21
  get502Template,
20
22
  get5xxTemplate,
@@ -70,6 +72,10 @@ class DefaultProvider extends BaseProvider {
70
72
  }
71
73
 
72
74
  async reload() {
75
+ if (process.env.NODE_ENV === 'development') {
76
+ return this.start();
77
+ }
78
+
73
79
  await pm2.connectAsync();
74
80
 
75
81
  // ensure daemon is live
@@ -218,4 +224,27 @@ DefaultProvider.check = async ({ configDir = '' } = {}) => {
218
224
  return result;
219
225
  };
220
226
 
227
+ DefaultProvider.getUsablePorts = async () =>
228
+ getUsablePorts(
229
+ 'default',
230
+ (port) =>
231
+ new Promise((resolve) => {
232
+ try {
233
+ const server = http.createServer();
234
+
235
+ server.once('error', () => {
236
+ server.close();
237
+ resolve(false);
238
+ });
239
+
240
+ server.listen(port, (err) => {
241
+ server.close();
242
+ resolve(!err);
243
+ });
244
+ } catch (err) {
245
+ resolve(false);
246
+ }
247
+ })
248
+ );
249
+
221
250
  module.exports = DefaultProvider;
@@ -93,6 +93,7 @@ module.exports = class ReverseProxy {
93
93
 
94
94
  // @link: https://github.com/http-party/node-http-proxy/issues/1401
95
95
  this.proxy.on('proxyRes', (proxyRes) => {
96
+ delete proxyRes.headers['x-powered-by'];
96
97
  this.opts.headers.forEach((x) => {
97
98
  proxyRes.headers[x.key] = x.value;
98
99
  });
@@ -38,6 +38,7 @@ const {
38
38
  const {
39
39
  decideHttpPort,
40
40
  decideHttpsPort,
41
+ getUsablePorts,
41
42
  get404Template,
42
43
  get502Template,
43
44
  get5xxTemplate,
@@ -781,7 +782,6 @@ NginxProvider.describe = async ({ configDir = '' } = {}) => {
781
782
  * @param {string} param.configDir nginx config directory
782
783
  */
783
784
  NginxProvider.check = async ({ configDir = '' } = {}) => {
784
- logger.info('check nginx provider');
785
785
  logger.info('check formal config directory', { configDir });
786
786
  const binPath = shelljs.which('nginx');
787
787
  const result = {
@@ -823,24 +823,24 @@ NginxProvider.check = async ({ configDir = '' } = {}) => {
823
823
  }
824
824
  }
825
825
 
826
- const tempConfigDirectory = path.join(
826
+ const tmpDir = path.join(
827
827
  os.tmpdir(),
828
- `test_abtnode_nginx_provider-${Date.now()}-${Math.ceil(Math.random() * 100)}`,
828
+ `test_nginx_provider-${Date.now()}-${Math.ceil(Math.random() * 10000)}`,
829
829
  CONFIG_FOLDER_NAME
830
830
  );
831
- fs.mkdirSync(tempConfigDirectory, { recursive: true });
831
+ fs.mkdirSync(tmpDir, { recursive: true });
832
832
 
833
- const nginxProvider = new NginxProvider({ configDir: tempConfigDirectory, isTest: true });
834
- nginxProvider.initialize();
833
+ const provider = new NginxProvider({ configDir: tmpDir, isTest: true });
834
+ provider.initialize();
835
835
 
836
- logger.info('check:addTestServer', { configPath: nginxProvider.configPath });
836
+ logger.info('check:addTestServer', { configPath: provider.configPath });
837
837
  await addTestServer({
838
- configPath: nginxProvider.configPath,
838
+ configPath: provider.configPath,
839
839
  port: await getPort(),
840
840
  upstreamPort: await getPort(),
841
841
  });
842
842
 
843
- const missingModules = getMissingModules(nginxProvider.readNginxConfigParams());
843
+ const missingModules = getMissingModules(provider.readNginxConfigParams());
844
844
 
845
845
  if (missingModules.length > 0) {
846
846
  result.available = false;
@@ -850,9 +850,10 @@ NginxProvider.check = async ({ configDir = '' } = {}) => {
850
850
  return result;
851
851
  }
852
852
 
853
- await nginxProvider.start();
853
+ await provider.start();
854
+ await provider.stop();
854
855
 
855
- await nginxProvider.stop();
856
+ fs.rmdirSync(tmpDir, { recursive: true });
856
857
 
857
858
  return result;
858
859
  };
@@ -860,4 +861,29 @@ NginxProvider.check = async ({ configDir = '' } = {}) => {
860
861
  NginxProvider.getStatus = getNginxStatus;
861
862
  NginxProvider.exists = () => !!shelljs.which('nginx');
862
863
 
864
+ NginxProvider.getUsablePorts = async () =>
865
+ getUsablePorts('nginx', async (port) => {
866
+ try {
867
+ const configDir = path.join(
868
+ os.tmpdir(),
869
+ `test_nginx_provider-${Date.now()}-${Math.ceil(Math.random() * 10000)}`,
870
+ CONFIG_FOLDER_NAME
871
+ );
872
+ fs.mkdirSync(configDir, { recursive: true });
873
+
874
+ const provider = new NginxProvider({ configDir, isTest: true });
875
+ provider.initialize();
876
+
877
+ await addTestServer({ configPath: provider.configPath, port });
878
+ await provider.start();
879
+ await provider.stop();
880
+
881
+ fs.rmdirSync(configDir, { recursive: true });
882
+
883
+ return true;
884
+ } catch (err) {
885
+ return false;
886
+ }
887
+ });
888
+
863
889
  module.exports = NginxProvider;
package/lib/nginx/util.js CHANGED
@@ -57,20 +57,22 @@ const addTestServer = ({ configPath, port, upstreamPort }) =>
57
57
 
58
58
  location / {
59
59
  if ($uri = /admin/did-connect) {include includes/cors-strict; include includes/security;}
60
- return 200 'Hello AbtNode!';
60
+ return 200 'Hello Blocklet Server!';
61
61
  }
62
62
  `
63
63
  );
64
64
 
65
- conf.nginx._addVerbatimBlock(
66
- 'stream',
67
- `
65
+ if (upstreamPort) {
66
+ conf.nginx._addVerbatimBlock(
67
+ 'stream',
68
+ `
68
69
  server {
69
70
  listen ${upstreamPort} udp;
70
71
  proxy_pass 127.0.0.1:${port};
71
72
  }
72
73
  `
73
- );
74
+ );
75
+ }
74
76
 
75
77
  conf.on('flushed', () => resolve());
76
78
  conf.live(configPath);
package/lib/util.js CHANGED
@@ -1,3 +1,8 @@
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');
1
6
  const sortBy = require('lodash/sortBy');
2
7
  const isValidDomain = require('is-valid-domain');
3
8
  const checkDomainMatch = require('@abtnode/util/lib/check-domain-match');
@@ -8,7 +13,7 @@ const {
8
13
  IP,
9
14
  DEFAULT_HTTP_PORT,
10
15
  DEFAULT_HTTPS_PORT,
11
- DEFAULT_IP_DNS_DOMAIN_SUFFIX,
16
+ DEFAULT_IP_DOMAIN_SUFFIX,
12
17
  DOMAIN_FOR_DEFAULT_SITE,
13
18
  ROUTING_RULE_TYPES,
14
19
  SLOT_FOR_IP_DNS_SITE,
@@ -110,7 +115,7 @@ const isSpecificDomain = (domain) => {
110
115
  return false;
111
116
  }
112
117
 
113
- if (domain.endsWith(DEFAULT_IP_DNS_DOMAIN_SUFFIX)) {
118
+ if (domain.endsWith(DEFAULT_IP_DOMAIN_SUFFIX)) {
114
119
  return false;
115
120
  }
116
121
 
@@ -118,7 +123,7 @@ const isSpecificDomain = (domain) => {
118
123
  };
119
124
 
120
125
  const toSlotDomain = (domain) => {
121
- if (domain.endsWith(DEFAULT_IP_DNS_DOMAIN_SUFFIX)) {
126
+ if (domain.endsWith(DEFAULT_IP_DOMAIN_SUFFIX)) {
122
127
  const subDomain = domain.split('.').shift();
123
128
  const matches = subDomain.match(IP);
124
129
  if (matches) {
@@ -148,9 +153,45 @@ const matchRule = (rules, url) => {
148
153
  return findRule(rulesWithSuffix, url) || findRule(rulesWithoutSuffix, url);
149
154
  };
150
155
 
156
+ const isPortOccupied = (port) => portUsed.check(port);
157
+ const getUsablePort = async (preferredPorts, hasPortPermission) => {
158
+ for (const port of preferredPorts) {
159
+ const occupied = await isPortOccupied(port);
160
+ if (!occupied) {
161
+ const listenable = await hasPortPermission(port);
162
+ if (listenable) {
163
+ return port;
164
+ }
165
+ }
166
+ }
167
+
168
+ return getPort();
169
+ };
170
+ const getUsablePorts = async (provider, hasPortPermission) => {
171
+ const file = path.join(process.env.PM2_HOME, `${provider}-preferred-ports.json`);
172
+ if (fs.existsSync(file)) {
173
+ const config = fs.readJsonSync(file);
174
+ if (config.httpPort && config.httpsPort) {
175
+ return config;
176
+ }
177
+ }
178
+
179
+ const [httpPort, httpsPort] = await Promise.all([
180
+ getUsablePort([80, 8080], hasPortPermission),
181
+ getUsablePort([443, 8443], hasPortPermission),
182
+ ]);
183
+
184
+ const config = { httpPort, httpsPort };
185
+ fs.writeJsonSync(file, config);
186
+ return config;
187
+ };
188
+
151
189
  module.exports = {
152
190
  decideHttpPort,
153
191
  decideHttpsPort,
192
+ getUsablePorts,
193
+ getUsablePort,
194
+ isPortOccupied,
154
195
  findCertificate,
155
196
  concatPath,
156
197
  trimEndSlash,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abtnode/router-provider",
3
- "version": "1.6.29",
3
+ "version": "1.7.0",
4
4
  "description": "Routing engine implementations for abt node",
5
5
  "author": "polunzh <polunzh@gmail.com>",
6
6
  "homepage": "https://github.com/ArcBlock/blocklet-server#readme",
@@ -32,10 +32,10 @@
32
32
  "url": "https://github.com/ArcBlock/blocklet-server/issues"
33
33
  },
34
34
  "dependencies": {
35
- "@abtnode/constant": "1.6.29",
36
- "@abtnode/logger": "1.6.29",
37
- "@abtnode/router-templates": "1.6.29",
38
- "@abtnode/util": "1.6.29",
35
+ "@abtnode/constant": "1.7.0",
36
+ "@abtnode/logger": "1.7.0",
37
+ "@abtnode/router-templates": "1.7.0",
38
+ "@abtnode/util": "1.7.0",
39
39
  "axios": "^0.25.0",
40
40
  "debug": "^4.3.3",
41
41
  "find-process": "^1.4.3",
@@ -49,6 +49,7 @@
49
49
  "moment": "^2.29.1",
50
50
  "nginx-conf": "^1.5.0",
51
51
  "object-hash": "^3.0.0",
52
+ "port-used": "^2.0.8",
52
53
  "promise-retry": "^2.0.1",
53
54
  "shelljs": "^0.8.4",
54
55
  "tar": "^6.1.0",
@@ -61,5 +62,5 @@
61
62
  "fs-extra": "^10.0.0",
62
63
  "needle": "^3.0.0"
63
64
  },
64
- "gitHead": "0d02246307d364e952990b3e64b608dfefc80efe"
65
+ "gitHead": "fc949a5e8a1017fbe17533d3bd78b166c7dad132"
65
66
  }