@hapiness/proxy
Version:
Proxy extension for Hapiness
155 lines • 6.39 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@hapiness/core");
const rxjs_1 = require("rxjs");
const biim_1 = require("@hapiness/biim");
const Hapi = require("hapi");
const H2o2 = require("h2o2");
// import * as Wreck from 'wreck';
class ProxyManager {
constructor(module, config) {
this.server = new Hapi.Server(config);
}
start(module) {
return rxjs_1.Observable
.fromPromise(this.server.register({ plugin: H2o2 }))
.flatMap(() => this.server.start())
.flatMap(() => this.instantiateHandler(module).do(_ => this.handler = _))
.flatMap(() => this.instantiateProxyResponse(module).do(_ => this.response = _))
.flatMap(() => this.instantiateProxyAuth(module).do(_ => this.auth = _))
.do(() => {
if (this.auth) {
const meta = core_1.extractMetadataByDecorator(this.auth.token, 'ProxyAuth');
const scheme = (server, options) => {
return {
authenticate: (request, h) => {
// const authorization = request.headers.authorization;
// if (!authorization) {
// throw Biim.unauthorized(null, 'Custom');
// }
// return h.authenticated({ credentials: { user: 'john' } });
return this.triggerHook('onAuthenticate', this.auth.token, this.auth.instance, [request, h]);
}
};
};
this.server.auth.scheme(meta.schemeName, scheme);
this.server.auth.strategy('default', meta.schemeName);
this.server.auth.default('default');
}
this.server.route({
method: '*',
path: '/{p*}',
handler: {
proxy: {
passThrough: true,
mapUri: request => this.requestHandler(request),
onResponse: (err, res, req, reply) => {
if (err) {
return reply.response(biim_1.Biim.wrap(err));
}
const result = this.responseHandler(null, res, req, reply);
if (result === true) {
return reply.response(res)
.code(res.statusCode)
.passThrough(true);
}
else {
return result;
}
}
}
}
});
});
}
shutdown() {
return rxjs_1.Observable.fromPromise(this.server.stop());
}
instantiateHandler(module) {
const handler = this.getProxyHandler(module.declarations);
return core_1.DependencyInjection
.instantiateComponent(handler, module.di)
.map(_ => ({ token: handler, instance: _ }));
}
instantiateProxyResponse(module) {
const handler = this.getProxyResponse(module.declarations);
return core_1.DependencyInjection
.instantiateComponent(handler, module.di)
.map(_ => ({ token: handler, instance: _ }));
}
instantiateProxyAuth(module) {
const handler = this.getProxyAuth(module.declarations);
if (handler) {
return core_1.DependencyInjection
.instantiateComponent(handler, module.di)
.map(_ => ({ token: handler, instance: _ }));
}
else {
return rxjs_1.Observable.of(null);
}
}
requestHandler(request) {
const res = this.triggerHook('onMapUri', this.handler.token, this.handler.instance, [request]);
return this.mapUri(res.uri, res.headers)(request);
}
responseHandler(payload, req, res, reply) {
return this.triggerHook('onResponse', this.response.token, this.response.instance, [payload, req, res, reply]);
}
getProxyHandler(declarations) {
const res = []
.concat(declarations)
.filter(_ => !!_ && !!core_1.extractMetadataByDecorator(_, 'ProxyHandler'));
if (res.length !== 1) {
throw new Error('ProxyHandler need to have one definition');
}
return res.shift();
}
getProxyResponse(declarations) {
const res = []
.concat(declarations)
.filter(_ => !!_ && !!core_1.extractMetadataByDecorator(_, 'ProxyResponse'));
if (res.length !== 1) {
throw new Error('ProxyResponse need to have one definition');
}
return res.shift();
}
getProxyAuth(declarations) {
const res = []
.concat(declarations)
.filter(_ => !!_ && !!core_1.extractMetadataByDecorator(_, 'ProxyAuth'));
if (res.length > 1) {
throw new Error('ProxyAuth cannot have more than one definition');
}
return res.shift();
}
hasLifecycleHook(hook, token) {
return token instanceof core_1.Type && hook in token.prototype;
}
triggerHook(hook, token, instance, args) {
if (this.hasLifecycleHook(hook, token)) {
return Reflect.apply(instance[hook], instance, args || []);
}
throw new Error(`${hook} is not implemented on ${token.name}`);
}
mapUri(uri, headers) {
return function (request) {
if (uri.indexOf('{') === -1) {
return { uri };
}
let address = uri.replace(/{protocol}/g, request.server.info.protocol)
.replace(/{host}/g, request.server.info.host)
.replace(/{port}/g, request.server.info.port)
.replace(/{path}/g, request.url.path);
Object.keys(request.params).forEach((key) => {
const re = new RegExp(`{${key}}`, 'g');
address = address.replace(re, request.params[key]);
});
return {
uri: address,
headers
};
};
}
}
exports.ProxyManager = ProxyManager;
//# sourceMappingURL=manager.js.map