@abtnode/router-provider 1.16.14-beta-3127f514 → 1.16.14-beta-5ac0c68b

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.
@@ -0,0 +1,20 @@
1
+ map $arg_w $image_width {
2
+ default 1200;
3
+ ~^(\d+)$ $1;
4
+ }
5
+ map $arg_h $image_height {
6
+ default -;
7
+ ~^(\d+)$ $1;
8
+ }
9
+ map $arg_r $image_rotate {
10
+ default 0;
11
+ ~^(\d+)$ $1;
12
+ }
13
+ map $arg_q $image_quality {
14
+ default 90;
15
+ ~^(\d+)$ $1;
16
+ }
17
+ map $arg_s $image_sharpen {
18
+ default 0;
19
+ ~^(\d+)$ $1;
20
+ }
@@ -0,0 +1,13 @@
1
+ image_filter_buffer 16M;
2
+ image_filter rotate $image_rotate;
3
+ image_filter crop $image_width $image_height;
4
+ # FIXME: @wangshijun turn on this will improve jpeg and breaks png
5
+ image_filter_interlace on;
6
+ image_filter_transparency on;
7
+ image_filter_jpeg_quality $image_quality;
8
+ image_filter_webp_quality $image_quality;
9
+ image_filter_sharpen $image_sharpen;
10
+
11
+ add_header x-image-filter "c/w/$image_width/h/$image_height/q/$image_quality/s/$image_sharpen";
12
+
13
+ error_page 415 = /error.svg;
@@ -0,0 +1,13 @@
1
+ image_filter_buffer 16M;
2
+ image_filter rotate $image_rotate;
3
+ image_filter resize $image_width $image_height;
4
+ # FIXME: @wangshijun turn on this will improve jpeg and breaks png
5
+ image_filter_interlace on;
6
+ image_filter_transparency on;
7
+ image_filter_jpeg_quality $image_quality;
8
+ image_filter_webp_quality $image_quality;
9
+ image_filter_sharpen $image_sharpen;
10
+
11
+ add_header x-image-filter "r/w/$image_width/h/$image_height/q/$image_quality/s/$image_sharpen";
12
+
13
+ error_page 415 = /error.svg;
@@ -8,6 +8,7 @@ const shelljs = require('shelljs');
8
8
  const kill = require('fkill');
9
9
  const getPort = require('get-port');
10
10
  const uniqBy = require('lodash/uniqBy');
11
+ const camelCase = require('lodash/camelCase');
11
12
  const isEmpty = require('lodash/isEmpty');
12
13
  const formatBackSlash = require('@abtnode/util/lib/format-back-slash');
13
14
  const {
@@ -38,6 +39,7 @@ const {
38
39
  getMainTemplate,
39
40
  getUpstreamName,
40
41
  joinNginxPath,
42
+ getDynamicModuleDirective,
41
43
  } = require('./util');
42
44
  const {
43
45
  decideHttpPort,
@@ -109,7 +111,9 @@ class NginxProvider extends BaseProvider {
109
111
  this.httpPort = decideHttpPort(httpPort);
110
112
  this.httpsPort = decideHttpsPort(httpsPort);
111
113
  this.cacheEnabled = !!cacheEnabled;
112
- this.isHttp2Supported = this._isHttp2Supported();
114
+
115
+ this.capabilities = this._checkCapabilities();
116
+
113
117
  this.conf = null; // nginx `conf` object
114
118
 
115
119
  logger.info('nginx provider config', {
@@ -142,6 +146,7 @@ class NginxProvider extends BaseProvider {
142
146
  cacheDir: this.getRelativeConfigDir(formatBackSlash(this.cacheDir)),
143
147
  workerProcess: this.getWorkerProcess(),
144
148
  nginxLoadModules: getNginxLoadModuleDirectives(REQUIRED_MODULES, this.readNginxConfigParams()).join(os.EOL),
149
+ capabilities: this.capabilities,
145
150
  });
146
151
  }
147
152
 
@@ -181,7 +186,7 @@ class NginxProvider extends BaseProvider {
181
186
  conf.on('flushed', () => resolve());
182
187
  conf.live(this.configPath);
183
188
 
184
- const { sites, configs: siteCorsConfigs } = formatRoutingTable(routingTable);
189
+ const { sites, configs: siteCorsConfigs } = formatRoutingTable(routingTable, this.capabilities);
185
190
 
186
191
  this._addCorsMap(conf, siteCorsConfigs);
187
192
  conf.nginx.http._add('server_tokens', 'off');
@@ -339,9 +344,31 @@ class NginxProvider extends BaseProvider {
339
344
  return result;
340
345
  }
341
346
 
342
- _isHttp2Supported() {
343
- const configArgs = this.readNginxConfigParams();
344
- return typeof configArgs['with-http_v2_module'] !== 'undefined';
347
+ _checkCapabilities() {
348
+ const config = this.readNginxConfigParams();
349
+ const capabilities = ['http_v2', 'http_image_filter', 'http_geoip'].reduce((acc, key) => {
350
+ const arg = `with-${key}_module`;
351
+ const capability = camelCase(key);
352
+
353
+ if (config[arg] === '') {
354
+ acc[capability] = 'static';
355
+ } else if (config[arg] === 'dynamic') {
356
+ acc[capability] = 'dynamic';
357
+ } else {
358
+ acc[capability] = false;
359
+ }
360
+
361
+ return acc;
362
+ }, {});
363
+
364
+ capabilities.modulesPath = config['modules-path'];
365
+ if (capabilities.modulesPath && getDynamicModuleDirective('httpBrotli', capabilities.modulesPath)) {
366
+ capabilities.httpBrotli = 'dynamic';
367
+ } else {
368
+ capabilities.httpBrotli = false;
369
+ }
370
+
371
+ return capabilities;
345
372
  }
346
373
 
347
374
  readNginxConfigParams() {
@@ -455,6 +482,7 @@ class NginxProvider extends BaseProvider {
455
482
  commonHeaders,
456
483
  cacheGroup,
457
484
  pageGroup,
485
+ filter,
458
486
  }) {
459
487
  server._add('location', concatPath(prefix, suffix));
460
488
 
@@ -489,6 +517,16 @@ class NginxProvider extends BaseProvider {
489
517
  location._add('proxy_cache_valid', `200 ${ROUTER_CACHE_GROUPS[cacheGroup].period}`);
490
518
  location._add('include', 'includes/cache');
491
519
  }
520
+ if (filter) {
521
+ location._add('include', `includes/image-filter-${filter}`);
522
+ } else if (ROUTER_CACHE_GROUPS[cacheGroup] && this.capabilities.httpImageFilter) {
523
+ location._add('set', '$filter "off"');
524
+ location._addVerbatimBlock(`if ($uri ~* "^${prefix}.*\\.(png|jpg|jpeg|webp)$")`, 'set $filter "on";');
525
+ location._addVerbatimBlock('if ($arg_imageFilter = "resize")', 'set $filter "${filter}resize";'); // eslint-disable-line no-template-curly-in-string
526
+ location._addVerbatimBlock('if ($arg_imageFilter = "crop")', 'set $filter "${filter}crop";'); // eslint-disable-line no-template-curly-in-string
527
+ location._addVerbatimBlock('if ($filter = "onresize")', `rewrite ${prefix}(.+) ${prefix}$1/resize last;`);
528
+ location._addVerbatimBlock('if ($filter = "oncrop")', `rewrite ${prefix}(.+) ${prefix}$1/crop last;`);
529
+ }
492
530
 
493
531
  // Redirect blocklet traffic
494
532
  if (type === ROUTING_RULE_TYPES.BLOCKLET) {
@@ -515,8 +553,12 @@ class NginxProvider extends BaseProvider {
515
553
  }
516
554
 
517
555
  // Rewrite path
518
- location._add('rewrite', `^${rewritePathPrefix}/?(.*) /$1 break`);
519
- location._add('proxy_pass', `http://${getUpstreamName(process.env.ABT_NODE_SERVICE_PORT)}/`);
556
+ if (filter) {
557
+ location._add('rewrite', `^${rewritePathPrefix}/?(.*)/${filter}$ /$1 break`);
558
+ } else {
559
+ location._add('rewrite', `^${rewritePathPrefix}/?(.*) /$1 break`);
560
+ }
561
+ location._add('proxy_pass', `http://${getUpstreamName(process.env.ABT_NODE_SERVICE_PORT)}`);
520
562
 
521
563
  return;
522
564
  }
@@ -809,7 +851,7 @@ class NginxProvider extends BaseProvider {
809
851
  const crtPath = `${joinNginxPath(this.certDir, certificateFileName.replace('*', '-'))}.crt`;
810
852
  const keyPath = `${joinNginxPath(this.certDir, certificateFileName.replace('*', '-'))}.key`;
811
853
 
812
- let listen = `${this.httpsPort} ssl ${this.isHttp2Supported ? 'http2' : ''}`.trim();
854
+ let listen = `${this.httpsPort} ssl ${this.capabilities.httpV2 ? 'http2' : ''}`.trim();
813
855
  if (serverName === '_') {
814
856
  listen = `${listen} default_server`;
815
857
  }
@@ -1008,6 +1050,9 @@ NginxProvider.check = async ({ configDir = '' } = {}) => {
1008
1050
 
1009
1051
  return result;
1010
1052
  } catch (error) {
1053
+ if (process.env.DEBUG) {
1054
+ console.error(error);
1055
+ }
1011
1056
  result.available = false;
1012
1057
  result.error = error.message;
1013
1058
  logger.error('check nginx failed', { error });
package/lib/nginx/util.js CHANGED
@@ -147,6 +147,26 @@ const getWorkerConnectionCount = (maxWorkerConnections, workerProcess) => {
147
147
  return Math.min(maxWorkerConnections, Math.floor(ulimit / workerProcess));
148
148
  };
149
149
 
150
+ const getDynamicModuleDirective = (moduleName, modulesPath) => {
151
+ const mapping = {
152
+ httpImageFilter: ['ngx_http_image_filter_module.so'],
153
+ httpGeoip: ['ngx_http_geoip_module.so', 'ngx_stream_geoip_module.so'],
154
+ httpBrotli: ['ngx_http_brotli_filter_module.so', 'ngx_http_brotli_static_module.so'],
155
+ };
156
+
157
+ return mapping[moduleName]
158
+ .filter((x) => fs.existsSync(path.join(modulesPath, x)))
159
+ .map((x) => `load_module ${modulesPath}/${x};`)
160
+ .join(os.EOL);
161
+ };
162
+
163
+ const getDynamicModulesDirective = (capabilities) => {
164
+ return Object.keys(capabilities)
165
+ .filter((x) => capabilities[x] === 'dynamic')
166
+ .map((x) => getDynamicModuleDirective(x, capabilities.modulesPath))
167
+ .join(os.EOL);
168
+ };
169
+
150
170
  const getMainTemplate = ({
151
171
  logDir,
152
172
  tmpDir,
@@ -154,9 +174,10 @@ const getMainTemplate = ({
154
174
  nginxLoadModules = '',
155
175
  workerProcess,
156
176
  maxBodySize = CLIENT_MAX_BODY_SIZE,
177
+ capabilities = {},
157
178
  }) =>
158
- `
159
- ${nginxLoadModules}
179
+ `${nginxLoadModules}
180
+ ${getDynamicModulesDirective(capabilities)}
160
181
  worker_processes ${workerProcess};
161
182
  error_log /dev/null crit;
162
183
  user ${os.userInfo().username} ${getUserGroup(os.userInfo().username)};
@@ -192,10 +213,11 @@ http {
192
213
  include includes/params;
193
214
  include includes/mime.types;
194
215
  include includes/compression;
216
+ ${capabilities.httpImageFilter ? 'include includes/image-filter-args;' : ''}
195
217
 
196
218
  ${Object.keys(ROUTER_CACHE_GROUPS)
197
219
  .map((x) => getCachePathDirective(cacheDir, x))
198
- .join('\n')}
220
+ .join(os.EOL)}
199
221
  }
200
222
  `;
201
223
 
@@ -316,6 +338,8 @@ module.exports = {
316
338
  getUserGroup,
317
339
  getWorkerConnectionCount,
318
340
  getCachePathDirective,
341
+ getDynamicModuleDirective,
342
+ getDynamicModulesDirective,
319
343
  getUpstreamName,
320
344
  joinNginxPath,
321
345
  };
package/lib/util.js CHANGED
@@ -3,6 +3,7 @@ const fs = require('fs-extra');
3
3
  const path = require('path');
4
4
  const getPort = require('get-port');
5
5
  const portUsed = require('port-used');
6
+ const cloneDeep = require('lodash/cloneDeep');
6
7
  const sortBy = require('lodash/sortBy');
7
8
  const isValidDomain = require('is-valid-domain');
8
9
  const checkDomainMatch = require('@abtnode/util/lib/check-domain-match');
@@ -45,7 +46,7 @@ const concatPath = (prefix = '', suffix = '') => {
45
46
  return suffix ? `~* ^${prefix}.*${suffix}$` : prefix;
46
47
  };
47
48
 
48
- const formatRoutingTable = (routingTable, onRule) => {
49
+ const formatRoutingTable = (routingTable, capabilities = {}) => {
49
50
  const sites = {};
50
51
  const configs = [];
51
52
 
@@ -105,13 +106,24 @@ const formatRoutingTable = (routingTable, onRule) => {
105
106
  rule.pageGroup = x.to.pageGroup;
106
107
  }
107
108
 
108
- const tmpPath = concatPath(prefix, suffix);
109
- const tmpRules = sites[domain].rules;
110
- if (!tmpRules.find(({ prefix: p, suffix: s }) => concatPath(p, s) === tmpPath)) {
111
- sites[domain].rules.push(rule);
112
- if (typeof onRule === 'function') {
113
- onRule(sites[domain].rules, rule);
109
+ const addRule = (r) => {
110
+ const tmpPath = concatPath(r.prefix, r.suffix);
111
+ const tmpRules = sites[domain].rules;
112
+ if (!tmpRules.find(({ prefix: p, suffix: s }) => concatPath(p, s) === tmpPath)) {
113
+ sites[domain].rules.push(r);
114
114
  }
115
+ };
116
+
117
+ addRule(rule);
118
+
119
+ // add image filter rules for each cacheable path
120
+ if (capabilities.httpImageFilter && rule.cacheGroup) {
121
+ ['resize', 'crop'].forEach((filter) => {
122
+ const filterRule = cloneDeep(rule);
123
+ rule.filter = filter;
124
+ rule.suffix = `\\.(png|jpg|jpeg|webp)/${filter}`;
125
+ addRule(filterRule);
126
+ });
115
127
  }
116
128
  });
117
129
 
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="300" height="200" viewBox="0 0 300 200"><rect width="100%" height="100%" fill="#DDDDDD"/><path fill="#999999" d="M112.5 94.58q0 5.4-1.79 10.01-1.78 4.61-5.05 7.97-3.26 3.37-7.85 5.26-4.59 1.88-10.2 1.88-5.58 0-10.17-1.88-4.59-1.89-7.87-5.26-3.28-3.36-5.08-7.97-1.8-4.61-1.8-10.01 0-5.41 1.8-10.02 1.8-4.6 5.08-7.97 3.28-3.36 7.87-5.25 4.59-1.89 10.17-1.89 3.74 0 7.04.87 3.29.87 6.05 2.45 2.75 1.58 4.94 3.84 2.2 2.26 3.73 5.05 1.53 2.79 2.33 6.05t.8 6.87Zm-9.35 0q0-4.05-1.09-7.26t-3.1-5.46q-2-2.24-4.88-3.43-2.87-1.19-6.47-1.19-3.61 0-6.48 1.19-2.87 1.19-4.9 3.43-2.02 2.25-3.11 5.46-1.08 3.21-1.08 7.26 0 4.04 1.08 7.26 1.09 3.21 3.11 5.44 2.03 2.22 4.9 3.41 2.87 1.19 6.48 1.19 3.6 0 6.47-1.19 2.88-1.19 4.88-3.41 2.01-2.23 3.1-5.44 1.09-3.22 1.09-7.26Zm31.51-10.85q3.88 0 7.06 1.26 3.18 1.26 5.44 3.57 2.26 2.31 3.48 5.64 1.23 3.34 1.23 7.45 0 4.15-1.23 7.48-1.22 3.33-3.48 5.68-2.26 2.34-5.44 3.6-3.18 1.26-7.06 1.26-3.91 0-7.1-1.26-3.2-1.26-5.46-3.6-2.26-2.35-3.5-5.68-1.24-3.33-1.24-7.48 0-4.11 1.24-7.45 1.24-3.33 3.5-5.64 2.26-2.31 5.46-3.57 3.19-1.26 7.1-1.26Zm0 29.48q4.36 0 6.45-2.92 2.09-2.93 2.09-8.57 0-5.65-2.09-8.6-2.09-2.96-6.45-2.96-4.42 0-6.54 2.97-2.13 2.98-2.13 8.59 0 5.61 2.13 8.55 2.12 2.94 6.54 2.94Zm32.03-18.73v15.64q1.43 1.73 3.11 2.44 1.69.72 3.66.72 1.9 0 3.43-.72 1.53-.71 2.6-2.17t1.65-3.69q.58-2.23.58-5.25 0-3.06-.49-5.19-.5-2.12-1.41-3.45-.92-1.33-2.23-1.94-1.31-.61-2.98-.61-2.61 0-4.45 1.1-1.84 1.11-3.47 3.12Zm-1.12-8.67.68 3.23q2.14-2.42 4.86-3.91 2.72-1.5 6.39-1.5 2.86 0 5.22 1.19 2.37 1.19 4.08 3.45 1.72 2.26 2.66 5.58.93 3.31.93 7.6 0 3.91-1.05 7.24-1.06 3.33-3.01 5.78-1.96 2.45-4.73 3.82-2.77 1.38-6.2 1.38-2.93 0-5-.9-2.08-.9-3.71-2.5v14.28h-8.4V84.28h5.14q1.63 0 2.14 1.53Zm54.54 2.24-1.91 3.03q-.34.54-.71.76-.38.22-.95.22-.62 0-1.31-.34-.7-.34-1.62-.76-.92-.43-2.09-.77t-2.77-.34q-2.48 0-3.89 1.06-1.41 1.05-1.41 2.75 0 1.12.73 1.89.73.76 1.93 1.34 1.21.58 2.74 1.04 1.53.46 3.11 1 1.58.54 3.11 1.24 1.53.7 2.74 1.77 1.21 1.07 1.94 2.57.73 1.49.73 3.6 0 2.52-.9 4.64-.9 2.13-2.67 3.67-1.77 1.55-4.37 2.42-2.6.86-6 .86-1.8 0-3.52-.32t-3.3-.9q-1.58-.58-2.92-1.36-1.34-.78-2.36-1.7l1.93-3.2q.38-.57.89-.88.51-.31 1.29-.31t1.48.45q.7.44 1.61.95.92.51 2.16.95 1.24.44 3.15.44 1.49 0 2.56-.36 1.08-.35 1.77-.93.7-.58 1.02-1.34.33-.77.33-1.58 0-1.23-.73-2.01-.74-.78-1.94-1.36-1.21-.58-2.76-1.04-1.54-.46-3.16-1-1.61-.54-3.16-1.27-1.55-.74-2.76-1.86-1.2-1.12-1.93-2.75t-.73-3.95q0-2.14.85-4.08.85-1.93 2.5-3.38 1.64-1.44 4.11-2.31 2.46-.87 5.69-.87 3.61 0 6.57 1.19 2.95 1.19 4.93 3.13ZM228.3 70h7.89v19.44q0 3.1-.31 6.07-.3 2.98-.78 6.31h-5.71q-.48-3.33-.78-6.31-.31-2.97-.31-6.07V70Zm-1.33 44.54q0-1.06.4-2.01.39-.95 1.08-1.63.7-.68 1.65-1.09.95-.41 2.04-.41 1.06 0 2.01.41.95.41 1.65 1.09.69.68 1.1 1.63.41.95.41 2.01 0 1.08-.41 2.02-.41.93-1.1 1.61-.7.68-1.65 1.08-.95.39-2.01.39-1.09 0-2.04-.39-.95-.4-1.65-1.08-.69-.68-1.08-1.61-.4-.94-.4-2.02Z"/></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abtnode/router-provider",
3
- "version": "1.16.14-beta-3127f514",
3
+ "version": "1.16.14-beta-5ac0c68b",
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.16.14-beta-3127f514",
36
- "@abtnode/logger": "1.16.14-beta-3127f514",
37
- "@abtnode/router-templates": "1.16.14-beta-3127f514",
38
- "@abtnode/util": "1.16.14-beta-3127f514",
35
+ "@abtnode/constant": "1.16.14-beta-5ac0c68b",
36
+ "@abtnode/logger": "1.16.14-beta-5ac0c68b",
37
+ "@abtnode/router-templates": "1.16.14-beta-5ac0c68b",
38
+ "@abtnode/util": "1.16.14-beta-5ac0c68b",
39
39
  "@arcblock/http-proxy": "^1.19.1",
40
40
  "axios": "^0.27.2",
41
41
  "debug": "^4.3.4",
@@ -59,5 +59,5 @@
59
59
  "bluebird": "^3.7.2",
60
60
  "fs-extra": "^10.1.0"
61
61
  },
62
- "gitHead": "cb397b94b752e71dfc0ba2c4ad08628cf03ce396"
62
+ "gitHead": "f38cb0f87e1eac8e5acf0106561972f4cc1207e8"
63
63
  }