UNPKG

15.2 kBJavaScriptView Raw
1'use strict';
2var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6 return c > 3 && r && Object.defineProperty(target, key, r), r;
7};
8var __metadata = (this && this.__metadata) || function (k, v) {
9 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10};
11Object.defineProperty(exports, "__esModule", { value: true });
12const _ = require("lodash");
13const http = require("http");
14const compression = require("compression");
15const express = require("express");
16const admin_api_1 = require("./admin/api/admin-api");
17const users_1 = require("./admin/api/users");
18const typescript_rest_1 = require("typescript-rest");
19const logger_1 = require("./logger");
20const express_logger_1 = require("./express-logger");
21const config_1 = require("./service/config");
22const configuration_1 = require("./configuration");
23const fs = require("fs-extra-promise");
24const typescript_ioc_1 = require("typescript-ioc");
25const events_1 = require("./config/events");
26const path = require("path");
27const time_intervals_1 = require("./utils/time-intervals");
28const service_discovery_1 = require("./pipeline/servicediscovery/service-discovery");
29const events_2 = require("events");
30const request_1 = require("./pipeline/stats/request");
31const api_1 = require("./pipeline/api");
32let Gateway = class Gateway extends events_2.EventEmitter {
33 constructor() {
34 super();
35 this.serverRunning = false;
36 this.setMaxListeners(150);
37 }
38 get server() {
39 return this.app;
40 }
41 get apis() {
42 return this.apiPipeline.apis;
43 }
44 get running() {
45 return this.serverRunning;
46 }
47 getApiConfig(apiId) {
48 return this.apiPipeline.getApiConfig(apiId);
49 }
50 start() {
51 return new Promise((resolve, reject) => {
52 this.initialize()
53 .then(() => {
54 this.apiServer = new Map();
55 let started = 0;
56 let expected = 0;
57 if (this.config.gateway.protocol.http) {
58 expected++;
59 const httpServer = http.createServer(this.app);
60 this.apiServer.set('http', httpServer.listen(_.toSafeInteger(this.config.gateway.protocol.http.listenPort), () => {
61 this.logger.info(`Gateway listenning HTTP on port ${this.config.gateway.protocol.http.listenPort}`);
62 started++;
63 if (started === expected) {
64 this.serverRunning = true;
65 this.emit('start', this);
66 resolve();
67 }
68 }));
69 }
70 if (this.config.gateway.protocol.https) {
71 expected++;
72 const httpsServer = this.createHttpsServer(this.app);
73 this.apiServer.set('https', httpsServer.listen(_.toSafeInteger(this.config.gateway.protocol.https.listenPort), () => {
74 this.logger.info(`Gateway listenning HTTPS on port ${this.config.gateway.protocol.https.listenPort}`);
75 started++;
76 if (started === expected) {
77 this.serverRunning = true;
78 this.emit('start', this);
79 resolve();
80 }
81 }));
82 }
83 })
84 .catch((err) => {
85 reject(err);
86 });
87 });
88 }
89 startAdmin() {
90 return new Promise((resolve, reject) => {
91 if (!this.config.gateway.admin) {
92 return resolve();
93 }
94 if (this.adminApp) {
95 this.adminServer = new Map();
96 let started = 0;
97 let expected = 0;
98 if (this.config.gateway.admin.protocol.http) {
99 expected++;
100 const httpServer = http.createServer(this.adminApp);
101 httpServer.timeout = time_intervals_1.getMilisecondsInterval(this.config.gateway.timeout, 60000);
102 this.adminServer.set('http', httpServer.listen(_.toSafeInteger(this.config.gateway.admin.protocol.http.listenPort), () => {
103 this.logger.info(`Gateway Admin Server listenning HTTP on port ${this.config.gateway.admin.protocol.http.listenPort}`);
104 started++;
105 if (started === expected) {
106 this.emit('admin-start', this);
107 resolve();
108 }
109 }));
110 }
111 if (this.config.gateway.admin.protocol.https) {
112 expected++;
113 const httpsServer = this.createHttpsServer(this.adminApp);
114 httpsServer.timeout = time_intervals_1.getMilisecondsInterval(this.config.gateway.timeout, 60000);
115 this.adminServer.set('https', httpsServer.listen(_.toSafeInteger(this.config.gateway.admin.protocol.https.listenPort), () => {
116 this.logger.info(`Gateway Admin Server listenning HTTPS on port ${this.config.gateway.admin.protocol.https.listenPort}`);
117 started++;
118 if (started === expected) {
119 this.emit('admin-start', this);
120 resolve();
121 }
122 }));
123 }
124 }
125 else {
126 reject('You must start the Tree-Gateway before.');
127 }
128 });
129 }
130 stop() {
131 return new Promise((resolve, reject) => {
132 if (this.apiServer) {
133 let toClose = this.apiServer.size;
134 if (toClose === 0) {
135 this.serverRunning = false;
136 this.apiPipeline.clearRoutes();
137 this.emit('stop', this);
138 return resolve();
139 }
140 this.apiServer.forEach(server => {
141 server.close(() => {
142 toClose--;
143 if (toClose === 0) {
144 this.logger.info('Gateway server stopped');
145 this.serverRunning = false;
146 this.apiPipeline.clearRoutes();
147 this.emit('stop', this);
148 resolve();
149 }
150 });
151 });
152 this.apiServer = null;
153 }
154 else {
155 this.serverRunning = false;
156 this.apiPipeline.clearRoutes();
157 this.emit('stop', this);
158 resolve();
159 }
160 });
161 }
162 stopAdmin() {
163 return new Promise((resolve, reject) => {
164 if (this.adminServer) {
165 let toClose = this.adminServer.size;
166 if (toClose === 0) {
167 this.emit('admin-stop', this);
168 return resolve();
169 }
170 this.adminServer.forEach(server => {
171 server.close(() => {
172 toClose--;
173 if (toClose === 0) {
174 this.logger.info('Gateway Admin server stopped');
175 this.emit('admin-stop', this);
176 resolve();
177 }
178 });
179 });
180 this.adminServer = null;
181 }
182 else {
183 resolve();
184 }
185 });
186 }
187 async restart() {
188 this.logger.info(`Gateway is restarting...`);
189 await this.stopAdmin();
190 await this.stop();
191 await this.start();
192 await this.startAdmin();
193 }
194 createHttpsServer(app) {
195 const privateKey = fs.readFileSync(this.config.gateway.protocol.https.privateKey, 'utf8');
196 const certificate = fs.readFileSync(this.config.gateway.protocol.https.certificate, 'utf8');
197 const credentials = { key: privateKey, cert: certificate };
198 const https = require('https');
199 return https.createServer(credentials, app);
200 }
201 async loadApis() {
202 const configs = await this.configService.getAllApiConfig();
203 await this.apiPipeline.loadApis(configs, this.server);
204 }
205 async reloadApis() {
206 this.emit('api-reload', this);
207 await this.loadApis();
208 }
209 updateConfig(packageId, needsReload) {
210 if (needsReload) {
211 this.config.reload()
212 .then(() => {
213 this.logger.info(`Configuration reloaded. Restarting server...`);
214 return this.restart();
215 })
216 .then(() => {
217 this.logger.info(`Server restarted.`);
218 this.logger.info(`Configuration package ${packageId} applied successfuly.`);
219 })
220 .catch((error) => {
221 this.logger.error(`Error updating gateway config.`);
222 this.logger.inspectObject(error);
223 });
224 }
225 else {
226 this.configService.installAllMiddlewares()
227 .then(() => this.reloadApis())
228 .then(() => {
229 this.logger.info(`Configuration package ${packageId} applied successfuly.`);
230 })
231 .catch(err => {
232 this.logger.error(`Error applying configuration package ${packageId}.`);
233 this.logger.inspectObject(err);
234 });
235 }
236 }
237 async initialize() {
238 try {
239 this.app = express();
240 await this.configureServer();
241 await this.configService.removeAllListeners()
242 .on(events_1.ConfigEvents.CONFIG_UPDATED, (packageId, needsReload) => this.updateConfig(packageId, needsReload))
243 .on(events_1.ConfigEvents.CIRCUIT_CHANGED, (id, state) => this.apiPipeline.circuitChanged(id, state))
244 .subscribeEvents();
245 await this.configureAdminServer();
246 if (this.requestLogger.isGatewayRequestLogEnabled()) {
247 this.requestLogger.initialize();
248 }
249 }
250 catch (err) {
251 this.logger.error(`Error configuring gateway server. Config File:\n${JSON.stringify(this.config.gateway)}`);
252 this.logger.inspectObject(err);
253 throw err;
254 }
255 }
256 async configureServer() {
257 this.app.disable('x-powered-by');
258 if (!this.config.gateway.disableCompression) {
259 this.app.use(compression());
260 }
261 if (this.config.gateway.underProxy) {
262 this.app.enable('trust proxy');
263 }
264 if (this.config.gateway.accessLogger) {
265 express_logger_1.AccessLogger.configureAccessLoger(this.config.gateway.accessLogger, this.config.rootPath, this.app, './logs');
266 }
267 this.configureHealthcheck();
268 await this.configService.installAllMiddlewares();
269 await this.serviceDiscovery.loadServiceDiscoveryProviders(this.config.gateway);
270 this.apiPipeline.buildGatewayFilters(this.app, this.config.gateway.filter);
271 await this.loadApis();
272 }
273 configureHealthcheck() {
274 if (this.config.gateway.healthcheck) {
275 this.app.get(this.config.gateway.healthcheck, (req, res) => {
276 res.write('OK');
277 res.end();
278 });
279 }
280 }
281 configureAdminServer() {
282 if (this.config.gateway.admin) {
283 this.adminApp = express();
284 this.adminApp.disable('x-powered-by');
285 if (!this.config.gateway.disableCompression) {
286 this.adminApp.use(compression());
287 }
288 if (this.config.gateway.admin.accessLogger) {
289 express_logger_1.AccessLogger.configureAccessLoger(this.config.gateway.admin.accessLogger, this.config.rootPath, this.adminApp, './logs/admin');
290 }
291 this.apiPipeline.buildGatewayFilters(this.adminApp, this.config.gateway.admin.filter);
292 this.configureAdminCors();
293 this.configureApiDocs();
294 users_1.UsersRest.configureAuthMiddleware(this.adminApp);
295 typescript_rest_1.Server.buildServices(this.adminApp, ...admin_api_1.default);
296 this.adminApp.use((err, req, res, next) => {
297 if (err instanceof typescript_rest_1.HttpError) {
298 if (res.headersSent) {
299 return next(err);
300 }
301 res.status(err.statusCode);
302 res.json({ error: err.message, code: err.statusCode });
303 }
304 else {
305 next(err);
306 }
307 });
308 }
309 }
310 configureAdminCors() {
311 if (this.config.gateway.admin.cors) {
312 this.adminApp.use(this.apiPipeline.configureCors(this.config.gateway.admin.cors));
313 }
314 }
315 configureApiDocs() {
316 if (this.config.gateway.admin.apiDocs) {
317 const isTest = process.env.NODE_ENV === 'test';
318 const schemes = (this.config.gateway.admin.protocol.https ? ['https'] : ['http']);
319 const swaggerFile = isTest ?
320 './dist/admin/api/swagger.json' :
321 path.join(__dirname, './admin/api/swagger.json');
322 const apiPath = this.config.gateway.admin.apiDocs.path;
323 const apiHost = this.config.gateway.admin.apiDocs.host;
324 typescript_rest_1.Server.swagger(this.adminApp, swaggerFile, apiPath, apiHost, schemes);
325 }
326 }
327};
328__decorate([
329 typescript_ioc_1.Inject,
330 __metadata("design:type", configuration_1.Configuration)
331], Gateway.prototype, "config", void 0);
332__decorate([
333 typescript_ioc_1.Inject,
334 __metadata("design:type", logger_1.Logger)
335], Gateway.prototype, "logger", void 0);
336__decorate([
337 typescript_ioc_1.Inject,
338 __metadata("design:type", request_1.RequestLogger)
339], Gateway.prototype, "requestLogger", void 0);
340__decorate([
341 typescript_ioc_1.Inject,
342 __metadata("design:type", config_1.ConfigService)
343], Gateway.prototype, "configService", void 0);
344__decorate([
345 typescript_ioc_1.Inject,
346 __metadata("design:type", service_discovery_1.ServiceDiscovery)
347], Gateway.prototype, "serviceDiscovery", void 0);
348__decorate([
349 typescript_ioc_1.Inject,
350 __metadata("design:type", api_1.ApiPileline)
351], Gateway.prototype, "apiPipeline", void 0);
352Gateway = __decorate([
353 typescript_ioc_1.Singleton,
354 typescript_ioc_1.AutoWired,
355 __metadata("design:paramtypes", [])
356], Gateway);
357exports.Gateway = Gateway;
358//# sourceMappingURL=gateway.js.map
\No newline at end of file