Skip to content

Commit

Permalink
Merge pull request #80 from thiagobustamante/master
Browse files Browse the repository at this point in the history
accept id on middleware configs
  • Loading branch information
thiagobustamante committed Nov 23, 2017
2 parents 8f2f843 + 2a25e77 commit 4d8160d
Show file tree
Hide file tree
Showing 19 changed files with 90 additions and 49 deletions.
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tree-gateway",
"version": "1.2.2",
"version": "1.3.0",
"homepage": "http://treegateway.org",
"description": "The Tree Gateway API Gateway",
"author": "Thiago da Rosa de Bustamante <trbustamante@gmail.com>",
Expand Down Expand Up @@ -56,6 +56,7 @@
"argparse": "^1.0.9",
"bcrypt": "^1.0.2",
"body-parser": "^1.18.2",
"bson": "^1.0.4",
"cluster": "^0.7.7",
"compression": "^1.7.1",
"consul": "^0.30.0",
Expand All @@ -74,7 +75,6 @@
"joi": "^9.2.0",
"jsonata": "^1.3.0",
"lodash": "^4.17.4",
"memory-streams": "^0.1.2",
"minimatch": "^3.0.4",
"mustache": "^2.3.0",
"on-headers": "^1.0.1",
Expand All @@ -88,6 +88,7 @@
"request": "^2.83.0",
"requires-port": "1.x.x",
"serve-favicon": "~2.3.0",
"stream-buffers": "^3.0.1",
"swagger-client": "^3.3.0",
"typescript-ioc": "^1.0.2",
"typescript-rest": "^1.1.2",
Expand All @@ -103,6 +104,7 @@
"@types/argparse": "^1.0.33",
"@types/bcrypt": "^1.0.0",
"@types/body-parser": "^1.16.7",
"@types/bson": "^1.0.4",
"@types/chai": "^3.5.1",
"@types/compression": "0.0.33",
"@types/consul": "^0.23.32",
Expand All @@ -126,6 +128,7 @@
"@types/passport-local": "^1.0.29",
"@types/request": "0.0.31",
"@types/serve-static": "^1.7.31",
"@types/stream-buffers": "^3.0.2",
"@types/uuid": "^2.0.29",
"@types/weighted": "0.0.5",
"@types/winston": "0.0.28",
Expand Down
4 changes: 2 additions & 2 deletions src/authentication/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ export class ApiAuth {
}

if (this.logger.isDebugEnabled) {
this.logger.debug(`Authentication Strategy [${authentication.strategy.name}] configured for path [${path}]`);
this.logger.debug(`Authentication Strategy [${this.middlewareLoader.getId(authentication.strategy)}] configured for path [${path}]`);
}
}
} catch (e) {
this.logger.error(`Error configuring Authentication Strategy [${authentication.strategy.name}] for path [${path}]`, e);
this.logger.error(`Error configuring Authentication Strategy [${this.middlewareLoader.getId(authentication.strategy)}] for path [${path}]`, e);
}
}

Expand Down
8 changes: 5 additions & 3 deletions src/config/config-package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ export interface ConfigPackage {
}

export interface MiddlewareConfig {
id?: string;
middleware: string;
name: string;
name?: string;
content: string;
}

Expand All @@ -34,9 +35,10 @@ export let configPackageValidatorSchema = Joi.object().keys({
gateway: gatewayConfigValidatorSchema,
middlewares: Joi.array().items(Joi.object().keys({
content: Joi.string().required(),
id: Joi.string(),
middleware: Joi.string().required(),
name: Joi.string().required()
}))
name: Joi.string()
}).xor('id', 'name'))
});

export function validateConfigPackage(configPackage: ConfigPackage) {
Expand Down
11 changes: 8 additions & 3 deletions src/config/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,25 @@ export interface GatewayConfig {
}

export interface MonitorConfig {
/**
* Alternative do MonitorConfig.id
*/
id?: string;
/**
* The name of the monitor
*/
name: string;
name?: string;
/**
* Configure how statistical data will be collected
*/
statsConfig: StatsConfig;
}

const monitorConfigSchema = Joi.object().keys({
name: Joi.string().valid('cpu', 'mem').required(),
id: Joi.string().valid('cpu', 'mem'),
name: Joi.string().valid('cpu', 'mem'),
statsConfig: statsConfigValidatorSchema.required()
});
}).xor('id', 'name');

export const gatewayConfigValidatorSchema = Joi.object().keys({
accessLogger: accessLoggerConfigSchema,
Expand Down
9 changes: 7 additions & 2 deletions src/config/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ export interface MiddlewareConfig {
/**
* The name of the middleware
*/
id: string;
/**
* An alias for the middleware ID. It cause the same effect then configure id property
*/
name: string;
/**
* Options to be passed to middleware initialization
Expand All @@ -17,6 +21,7 @@ export interface MiddlewareConfig {
}

export let middlewareConfigValidatorSchema = Joi.object().keys({
name: Joi.string().required(),
id: Joi.string(),
name: Joi.string(),
options: Joi.object().unknown(true)
});
}).xor('id', 'name');
2 changes: 1 addition & 1 deletion src/config/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export interface Proxy {
*/
interceptor?: Interceptors;
/**
* If true, the gateway will copy the host HTTP header to the proxied express server.
* If true, the gateway will copy the host HTTP header to the proxied server.
*/
preserveHostHdr?: boolean;
/**
Expand Down
8 changes: 5 additions & 3 deletions src/monitor/monitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export abstract class Monitor {

constructor(config: MonitorConfig) {
this.config = config;
this.stats = this.createStats(this.config.name);
this.stats = this.createStats(this.config.id || this.config.name);
this.machineId = Monitor.getMachineId();
}

Expand All @@ -29,7 +29,8 @@ export abstract class Monitor {
const self = this;
this.interval = setInterval(() => {
this.run(this.period).then(value => self.registerStats(value)).catch(err => {
this.logger.error(`Error on monitor [${this.config.name}]: ${err}`);
const monitorName = this.config.id || this.config.name;
this.logger.error(`Error on monitor [${monitorName}]: ${err}`);
this.stop();
});
}, this.period);
Expand All @@ -38,7 +39,8 @@ export abstract class Monitor {
stop() {
if (this.interval) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(`Stopping monitor [${this.config.name}]`);
const monitorName = this.config.id || this.config.name;
this.logger.debug(`Stopping monitor [${monitorName}]`);
}
clearInterval(this.interval);
this.interval = null;
Expand Down
5 changes: 3 additions & 2 deletions src/monitor/monitors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ export class Monitors {
}
this.config.gateway.monitor.forEach(monitorConfig => {
let monitor = null;
if (monitorConfig.name === 'cpu') {
const monitorName = monitorConfig.id || monitorConfig.name;
if (monitorName === 'cpu') {
if (this.logger.isDebugEnabled()) {
this.logger.debug(`Starting a CPU monitor.`);
}
monitor = new CpuMonitor(monitorConfig);
} else if (monitorConfig.name === 'mem') {
} else if (monitorName === 'mem') {
if (this.logger.isDebugEnabled()) {
this.logger.debug(`Starting a Memory monitor.`);
}
Expand Down
5 changes: 3 additions & 2 deletions src/proxy/interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ export class ProxyInterceptor {
body.push(`var continueChain = function(body, headers, request){ return {body: body}; };`);
proxy.interceptor.response.forEach((interceptor, index) => {
const interceptorMiddleware = this.middlewareLoader.loadMiddleware('interceptor/response', interceptor.middleware);
interceptors[interceptor.middleware.name] = interceptorMiddleware;
const middlewareId = this.middlewareLoader.getId(interceptor.middleware);
interceptors[middlewareId] = interceptorMiddleware;
if (interceptor.group) {
result.validators.push(Groups.buildGroupNotAllowFilter(api.group, interceptor.group));
} else {
Expand All @@ -111,7 +112,7 @@ export class ProxyInterceptor {
body.push(`var f${index};`);
body.push(`if (ignore[${index}])`);
body.push(`f${index} = continueChain;`);
body.push(`else f${index} = interceptors['${interceptor.middleware.name}'];`);
body.push(`else f${index} = interceptors['${middlewareId}'];`);
body.push(`Promise.resolve(f${index}(body, proxyRes.headers, request)).catch((error) => { \
callback(error); \
return; \
Expand Down
9 changes: 4 additions & 5 deletions src/proxy/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ import { MiddlewareLoader } from '../utils/middleware-loader';
import { ServiceDiscovery } from '../servicediscovery/service-discovery';
import * as bodyParser from 'body-parser';
import * as cookieParser from 'cookie-parser';

import { WritableStreamBuffer } from 'stream-buffers';
const agentKeepAlive = require('agentkeepalive');
const httpProxy = require('../../lib/http-proxy');
const memoryStream = require('memory-streams').WritableStream;

/**
* The API Proxy system. It uses [[http-proxy]](https://github.com/nodejitsu/node-http-proxy)
Expand Down Expand Up @@ -171,7 +170,7 @@ export class ApiProxy {
return (req: express.Request, res: express.Response, next: express.NextFunction) => {
if (validateInterceptors(req, res) || (<any>req).parseRespBody) {
const options: any = (<any>req).proxyOptions || {};
(<any>res).__data = new memoryStream();
(<any>res).__data = new WritableStreamBuffer();
options.destPipe = { stream: (<any>res).__data };
proxy.web(req, res, options);
} else if ((<any>req).proxyOptions) {
Expand All @@ -186,7 +185,7 @@ export class ApiProxy {
proxy.on('end', (req: any, res: any, proxyRes: any, ) => {
if (res.__data) {
if (responseInterceptor) {
responseInterceptor.middelware(res.__data.toBuffer(), proxyRes, req, res, res.__ignore,
responseInterceptor.middelware(res.__data.getContents(), proxyRes, req, res, res.__ignore,
(newHeaders: any, removeHeaders: string[]) => {
if (newHeaders) {
Object.keys(newHeaders).forEach(name => {
Expand Down Expand Up @@ -215,7 +214,7 @@ export class ApiProxy {
}
});
} else {
const body = res.__data.toBuffer();
const body = res.__data.getContents();
delete res['__data'];
if (!res.finished) {
res.send(body);
Expand Down
4 changes: 2 additions & 2 deletions src/service/config-package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class ConfigPackageServiceImpl implements ConfigPackageService {
return new Promise<void>((resolve, reject) => {
if (config.middlewares) {
Promise.all(config.middlewares.map(mid =>
this.middlewareService.save(mid.middleware, mid.name, new Buffer(mid.content))))
this.middlewareService.save(mid.middleware, mid.id || mid.name, new Buffer(mid.content))))
.then(() => this.setApisAndGateway(config))
.then(resolve)
.catch(reject);
Expand Down Expand Up @@ -114,7 +114,7 @@ export class ConfigPackageServiceImpl implements ConfigPackageService {
if (names && names.length) {
const promises = names.map(name => new Promise<MiddlewareConfig>((res, rej) => {
this.middlewareService.read(middleware, name)
.then(content => res({ middleware: middleware, name: name, content: content.toString() }))
.then(content => res({ middleware: middleware, id: name, content: content.toString() }))
.catch(rej);
}));
Promise.all(promises).then(resolve).catch(reject);
Expand Down
6 changes: 3 additions & 3 deletions src/service/redis/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

import * as uuid from 'uuid';
import { ObjectID } from 'bson';
import { ApiService } from '../api';
import { NotFoundError, ValidationError } from '../../error/errors';
import { ApiConfig } from '../../config/api';
Expand Down Expand Up @@ -63,7 +63,7 @@ export class RedisApiService implements ApiService {
create(api: ApiConfig): Promise<string> {
return new Promise<string>((resolve, reject) => {
if (!api.id) {
api.id = uuid();
api.id = new ObjectID().toString();
}
this.ensureAPICreateConstraints(api)
.then(() =>
Expand All @@ -87,7 +87,7 @@ export class RedisApiService implements ApiService {
update(api: ApiConfig, upsert?: boolean): Promise<void> {
return new Promise<void>((resolve, reject) => {
if (upsert && !api.id) {
api.id = uuid();
api.id = new ObjectID().toString();
}
this.ensureAPIUpdateConstraints(api, upsert)
.then(() =>
Expand Down
27 changes: 16 additions & 11 deletions src/servicediscovery/service-discovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,21 @@ export class ServiceDiscovery {
}
const promises = gatewayConfig.serviceDiscovery.provider.map(provider => {
return new Promise<void>((resolve, reject) => {
const middleware = this.middlewareLoader.loadMiddleware('servicediscovery/provider', provider);
Promise.resolve(middleware())
.then((serviceDiscovery: any) => {
this.loadedClients.set(provider.name, serviceDiscovery);
this.logger.info(`Service Discovery provider ${provider.name} initialized.`);
resolve();
})
.catch(error => {
reject(new Error(`Error loading service discovery provider ${provider.name}. Error: ${error.message}`));
});
const middlewareId = this.middlewareLoader.getId(provider);
try {
const middleware = this.middlewareLoader.loadMiddleware('servicediscovery/provider', provider);
Promise.resolve(middleware())
.then((serviceDiscovery: any) => {
this.loadedClients.set(middlewareId, serviceDiscovery);
this.logger.info(`Service Discovery provider ${middlewareId} initialized.`);
resolve();
})
.catch(error => {
reject(new Error(`Error loading service discovery provider ${middlewareId}. Error: ${error.message}`));
});
} catch (error) {
reject(new Error(`Error loading service discovery provider ${middlewareId}. Error: ${error.message}`));
}
});
});
return new Promise<void>((resolve, reject) => {
Expand All @@ -37,7 +42,7 @@ export class ServiceDiscovery {
}

loadServiceDiscovery(middlewareConfig: MiddlewareConfig, ssl?: boolean) {
const provider = middlewareConfig.name;
const provider = this.middlewareLoader.getId(middlewareConfig);
const serviceDiscovery = this.loadedClients.get(provider);
if (serviceDiscovery) {
if (this.logger.isDebugEnabled()) {
Expand Down
11 changes: 8 additions & 3 deletions src/utils/middleware-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@ export class MiddlewareLoader {

loadMiddleware(type: string, middlewareConfig: MiddlewareConfig) {
let p: string;
const middlewareId = this.getId(middlewareConfig);
if ((_.has(MiddlewareLoader.providedMiddlewares, type)) &&
(_.has(MiddlewareLoader.providedMiddlewares[type], middlewareConfig.name))) {
p = MiddlewareLoader.providedMiddlewares[type][middlewareConfig.name];
(_.has(MiddlewareLoader.providedMiddlewares[type], middlewareId))) {
p = MiddlewareLoader.providedMiddlewares[type][middlewareId];
} else {
p = path.join(this.config.middlewarePath, type, middlewareConfig.name);
p = path.join(this.config.middlewarePath, type, middlewareId);
}

let middleware = require(p);
Expand All @@ -64,4 +65,8 @@ export class MiddlewareLoader {
}
return middleware;
}

getId(middlewareConfig: MiddlewareConfig) {
return middlewareConfig.id || middlewareConfig.name;
}
}
2 changes: 1 addition & 1 deletion test/data/apis/basicAuthenticationByGroup.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"authentication": {
"strategy": {
"name": "basic",
"id": "basic",
"options": {
"verify": {
"name": "verifyBasicUser"
Expand Down
2 changes: 1 addition & 1 deletion test/data/apis/customAuthentication.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"authentication": {
"strategy": {
"name": "myJwtStrategy",
"id": "myJwtStrategy",
"options": {
"secret": "secret"
}
Expand Down
4 changes: 2 additions & 2 deletions test/data/apis/intercepted.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"request": [
{
"middleware": {
"name":"myRequestInterceptor"
"id":"myRequestInterceptor"
},
"group": ["Group1"]
},
Expand All @@ -36,7 +36,7 @@
],
"response": [
{
"middleware": {"name":"myResponseInterceptor"}
"middleware": {"id":"myResponseInterceptor"}
},
{
"middleware": {
Expand Down

0 comments on commit 4d8160d

Please sign in to comment.