Skip to content

Commit

Permalink
feat: Use ES private properties instead of Symbols and defineProperty…
Browse files Browse the repository at this point in the history
…() for privacy (#84)

BREAKING CHANGE: Due to dropping node 10.x support we use ES private properties instead of Symbols and `.defineProperty()`.

Co-authored-by: Trygve Lie <trygve.lie@finn.no>
  • Loading branch information
trygve-lie and Trygve Lie authored Jul 29, 2020
1 parent 34fd3bf commit 37fd140
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 85 deletions.
14 changes: 5 additions & 9 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
{
"env": {
"node": true,
"jest": true
},
"extends": ["airbnb-base", "prettier"],
"plugins": ["prettier"],
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 2018
"ecmaVersion": 11,
"sourceType": "module"
},
"plugins": ["prettier"],
"root": true,
"rules": {
"lines-between-class-members": [0],
"class-methods-use-this": [0],
"indent": [1, 4],
"prettier/prettier": ["error"],
"strict": [0, "global"]
}
}
141 changes: 67 additions & 74 deletions lib/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,100 +10,81 @@ const Cache = require('ttl-mem-cache');
const Proxy = require('http-proxy');

const PodiumProxy = class PodiumProxy {
#pathname;
#prefix;
#log;
#registry;
#proxy;
#metrics;
#histogram;
#pathnameEntries;
#pathnameParser;
constructor({
pathname = '/',
prefix = '/podium-resource',
timeout = 20000,
maxAge = Infinity,
logger = null,
} = {}) {
Object.defineProperty(this, 'pathname', {
enumerable: true,
value: utils.pathnameBuilder(pathname),
});

Object.defineProperty(this, 'prefix', {
enumerable: true,
value: utils.pathnameBuilder(prefix),
});

Object.defineProperty(this, 'log', {
value: abslog(logger),
});

Object.defineProperty(this, 'registry', {
value: new Cache({
ttl: maxAge,
}),
});

this.registry.on('error', (error) => {
this.log.error(
'Error emitted by the registry in @podium/proxy module',
error,
);
});

Object.defineProperty(this, 'proxy', {
// eslint-disable-next-line new-cap
value: new Proxy.createProxy({
proxyTimeout: timeout,
}),
});

Object.defineProperty(this, 'metrics', {
enumerable: true,
value: new Metrics(),
});

Object.defineProperty(this, 'pathnameEntries', {
value: [],
});

const regExPath = utils.pathnameBuilder(
this.pathname,
this.prefix,
this.#pathname = utils.pathnameBuilder(pathname);
this.#prefix = utils.pathnameBuilder(prefix);
this.#log = abslog(logger);

this.#pathnameEntries = [];
this.#pathnameParser = pathToRegexp(utils.pathnameBuilder(
this.#pathname,
this.#prefix,
':podiumPodletName',
':podiumProxyName',
':podiumProxyExtras*',
);
Object.defineProperty(this, 'pathnameParser', {
value: pathToRegexp(regExPath, this.pathnameEntries),
});
), this.#pathnameEntries);

this.metrics.on('error', (error) => {
this.log.error(
'Error emitted by metric stream in @podium/proxy module',
// eslint-disable-next-line new-cap
this.#proxy = new Proxy.createProxy({
proxyTimeout: timeout,
});
this.#proxy.on('error', (error) => {
this.#log.error(
'Error emitted by proxy in @podium/proxy module',
error,
);
});

this.proxy.on('error', (error) => {
this.log.error(
'Error emitted by proxy in @podium/proxy module',
this.#registry = new Cache({
ttl: maxAge,
});
this.#registry.on('error', (error) => {
this.#log.error(
'Error emitted by the registry in @podium/proxy module',
error,
);
});

this.registry.on('set', (key, item) => {
this.#registry.on('set', (key, item) => {
Object.keys(item.proxy).forEach((name) => {
const path = utils.pathnameBuilder(
this.pathname,
this.prefix,
this.#pathname,
this.#prefix,
key,
name,
);
this.log.debug(
this.#log.debug(
`a proxy endpoint is mounted at pathname: ${path} pointing to: ${item.proxy[name]}`,
);
});
});

this.registry.on('dispose', (key) => {
this.log.debug(`dispose proxy item on key "${key}"`);
this.#registry.on('dispose', (key) => {
this.#log.debug(`dispose proxy item on key "${key}"`);
});

this.histogram = this.metrics.histogram({
this.#metrics = new Metrics();
this.#metrics.on('error', (error) => {
this.#log.error(
'Error emitted by metric stream in @podium/proxy module',
error,
);
});
this.#histogram = this.#metrics.histogram({
name: 'podium_proxy_process',
description: 'Measures time spent in the proxy process method',
labels: {
Expand All @@ -116,8 +97,16 @@ const PodiumProxy = class PodiumProxy {
});
}

get [Symbol.toStringTag]() {
return 'PodiumProxy';
get pathname() {
return this.#pathname;
}

get prefix() {
return this.#prefix;
}

get metrics() {
return this.#metrics;
}

register(manifest = {}) {
Expand All @@ -129,7 +118,7 @@ const PodiumProxy = class PodiumProxy {
'The value for the required argument "manifest" is not defined or not valid.',
);

this.registry.set(obj.name, obj, Infinity);
this.#registry.set(obj.name, obj, Infinity);
}

process(incoming) {
Expand All @@ -140,27 +129,27 @@ const PodiumProxy = class PodiumProxy {
throw TypeError('Argument must be of type "PodiumHttpIncoming"');
}

const endTimer = this.histogram.timer({
const endTimer = this.#histogram.timer({
labels: {
name: incoming.name,
},
});

return new Promise((resolve, reject) => {
const match = this.pathnameParser.exec(incoming.url.pathname);
const match = this.#pathnameParser.exec(incoming.url.pathname);
let errored = false;

if (match) {
// Turn matched uri parameters into an object of parameters
const params = {};
for (let i = 1; i < match.length; i += 1) {
const key = this.pathnameEntries[i - 1];
const key = this.#pathnameEntries[i - 1];
params[key.name] = match[i];
}

// See if "podiumPodletName" matches a podlet in registry.
// If so we might want to proxy. If not, skip rest of processing
const manifest = this.registry.get(params.podiumPodletName);
const manifest = this.#registry.get(params.podiumPodletName);
if (!manifest) {
endTimer({ labels: { podlet: params.podiumPodletName } });
resolve(incoming);
Expand Down Expand Up @@ -238,7 +227,7 @@ const PodiumProxy = class PodiumProxy {
resolve(incoming);
});

this.proxy.web(
this.#proxy.web(
incoming.request,
incoming.response,
config,
Expand All @@ -263,11 +252,15 @@ const PodiumProxy = class PodiumProxy {
}

dump() {
return this.registry.dump();
return this.#registry.dump();
}

load(dump) {
return this.registry.load(dump);
return this.#registry.load(dump);
}

get [Symbol.toStringTag]() {
return 'PodiumProxy';
}
};

Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"test": "tap tests/*.js"
"test": "tap --no-esm --no-cov --no-ts --no-jsx tests/*.js"
},
"dependencies": {
"@metrics/client": "2.5.0",
Expand All @@ -50,11 +50,12 @@
"@semantic-release/release-notes-generator": "9.0.1",
"semantic-release": "17.1.1",
"@podium/test-utils": "2.2.0",
"eslint": "7.3.1",
"eslint": "7.5.0",
"eslint-config-airbnb-base": "14.2.0",
"eslint-config-prettier": "6.11.0",
"eslint-plugin-import": "2.22.0",
"eslint-plugin-prettier": "3.1.4",
"babel-eslint": "10.1.0",
"prettier": "2.0.5",
"tap": "14.10.7"
}
Expand Down

0 comments on commit 37fd140

Please sign in to comment.