UNPKG

13.9 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 fs = require("fs-extra-promise");
13const _ = require("lodash");
14const path = require("path");
15const YAML = require("yamljs");
16const uuid = require("uuid");
17const events_1 = require("events");
18const gateway_1 = require("./config/gateway");
19const typescript_ioc_1 = require("typescript-ioc");
20const env_1 = require("./utils/env");
21const users_1 = require("./service/users");
22const middleware_1 = require("./service/middleware");
23const api_1 = require("./service/api");
24const config_1 = require("./service/config");
25const gateway_2 = require("./service/gateway");
26const plugin_data_1 = require("./service/plugin-data");
27const config_2 = require("./utils/config");
28const inquirer = require("inquirer");
29const chalk_1 = require("chalk");
30_.mixin(require('lodash-deep'));
31let Configuration = Configuration_1 = class Configuration extends events_1.EventEmitter {
32 constructor() {
33 super();
34 this.isLoaded = false;
35 this.load();
36 }
37 async load() {
38 if (!this.isLoaded) {
39 try {
40 await this.loadGatewayConfig(Configuration_1.gatewayConfigFile || path.join(process.cwd(), 'tree-gateway.json'));
41 this.isLoaded = true;
42 this.emit('load', this);
43 }
44 catch (err) {
45 this.isLoaded = false;
46 this.emit('error', err);
47 }
48 }
49 }
50 async reload() {
51 this.config = null;
52 await this.loadGatewayConfig(Configuration_1.gatewayConfigFile || path.join(process.cwd(), 'tree-gateway.json'));
53 this.emit('gateway-update', this.gateway);
54 return;
55 }
56 get gateway() {
57 this.ensureLoaded();
58 return this.config.gateway;
59 }
60 get rootPath() {
61 return this.config.rootPath;
62 }
63 get middlewarePath() {
64 return this.config.middlewarePath;
65 }
66 get database() {
67 return this.config.database;
68 }
69 get loaded() {
70 return this.isLoaded;
71 }
72 async loadGatewayConfig(serverConfigFile) {
73 let configFileName = serverConfigFile;
74 configFileName = this.removeExtension(_.trim(configFileName));
75 if (_.startsWith(configFileName, '.')) {
76 configFileName = path.join(process.cwd(), configFileName);
77 }
78 const config = await this.loadServerConfig(configFileName);
79 let serverConfig = await gateway_1.validateServerConfig(config);
80 serverConfig = _.defaults(serverConfig, {
81 rootPath: path.dirname(configFileName),
82 });
83 if (_.startsWith(serverConfig.rootPath, '.')) {
84 serverConfig.rootPath = path.join(path.dirname(configFileName), serverConfig.rootPath);
85 }
86 serverConfig = _.defaults(serverConfig, {
87 middlewarePath: path.join(serverConfig.rootPath, 'middleware')
88 });
89 if (_.startsWith(serverConfig.middlewarePath, '.')) {
90 serverConfig.middlewarePath = path.join(serverConfig.rootPath, serverConfig.middlewarePath);
91 }
92 serverConfig = this.config = _.deepMapValues(serverConfig, (value) => {
93 return env_1.checkEnvVariable(value);
94 });
95 this.config = serverConfig;
96 this.castArrays(this.config);
97 this.loadContainerConfigurations();
98 await this.loadDatabaseConfig();
99 if (this.config.gateway && this.config.gateway.protocol) {
100 if (this.config.gateway.protocol.https) {
101 if (_.startsWith(this.config.gateway.protocol.https.privateKey, '.')) {
102 this.config.gateway.protocol.https.privateKey =
103 path.join(this.config.rootPath, this.config.gateway.protocol.https.privateKey);
104 }
105 if (_.startsWith(this.config.gateway.protocol.https.certificate, '.')) {
106 this.config.gateway.protocol.https.certificate =
107 path.join(this.config.rootPath, this.config.gateway.protocol.https.certificate);
108 }
109 }
110 }
111 return;
112 }
113 ensureLoaded() {
114 if (!this.isLoaded) {
115 throw new Error('Configuration not loaded. Only access configurations after the Configuration \'load\' event is fired.');
116 }
117 }
118 loadContainerConfigurations() {
119 const RedisApiService = require('./service/redis/api').RedisApiService;
120 const RedisConfigService = require('./service/redis/config').RedisConfigService;
121 const RedisUserService = require('./service/redis/users').RedisUserService;
122 const RedisMiddlewareService = require('./service/redis/middleware').RedisMiddlewareService;
123 const RedisGatewayService = require('./service/redis/gateway').RedisGatewayService;
124 const RedisPluginsDataService = require('./service/redis/plugin-data').RedisPluginsDataService;
125 typescript_ioc_1.Container.bind(gateway_2.GatewayService).to(RedisGatewayService);
126 typescript_ioc_1.Container.bind(middleware_1.MiddlewareService).to(RedisMiddlewareService);
127 typescript_ioc_1.Container.bind(api_1.ApiService).to(RedisApiService);
128 typescript_ioc_1.Container.bind(config_1.ConfigService).to(RedisConfigService);
129 typescript_ioc_1.Container.bind(users_1.UserService).to(RedisUserService);
130 typescript_ioc_1.Container.bind(plugin_data_1.PluginsDataService).to(RedisPluginsDataService);
131 }
132 loadDatabaseConfig() {
133 return new Promise((resolve, reject) => {
134 setTimeout(() => {
135 if (Configuration_1.resetBeforeStart) {
136 console.info('reseting database');
137 const Database = require('./database').Database;
138 const database = typescript_ioc_1.Container.get(Database);
139 database.redisClient.flushdb()
140 .then(() => this.getConfigFromDB())
141 .then(resolve)
142 .catch(reject);
143 }
144 else {
145 this.getConfigFromDB()
146 .then(resolve)
147 .catch(reject);
148 }
149 }, 1);
150 });
151 }
152 async getConfigFromDB() {
153 const gatewayService = typescript_ioc_1.Container.get(gateway_2.GatewayService);
154 const gatewayConfig = await gatewayService.get();
155 if (gatewayConfig) {
156 this.config.gateway = _.defaultsDeep(gatewayConfig, this.config.gateway);
157 await gateway_1.validateGatewayConfig(this.config.gateway);
158 if (!this.config.gateway.protocol) {
159 throw new Error('GatewayConfig protocol is required.');
160 }
161 }
162 else if (!this.config.gateway) {
163 this.config.gateway = this.loadDefaultGatewayConfig();
164 await gatewayService.save(this.config.gateway);
165 await gatewayService.registerGatewayVersion();
166 }
167 return;
168 }
169 loadConfigObject(fileName) {
170 if (fs.existsSync(`${fileName}.yml`)) {
171 return YAML.load(`${fileName}.yml`);
172 }
173 else if (fs.existsSync(`${fileName}.yaml`)) {
174 return YAML.load(`${fileName}.yaml`);
175 }
176 else if (fs.existsSync(`${fileName}.json`)) {
177 return fs.readJSONSync(`${fileName}.json`);
178 }
179 else {
180 return null;
181 }
182 }
183 removeExtension(fileName) {
184 const lowerFileName = fileName.toLowerCase();
185 if (lowerFileName.endsWith('.yaml') || lowerFileName.endsWith('.yml') || lowerFileName.endsWith('.json')) {
186 return fileName.substring(0, fileName.lastIndexOf('.'));
187 }
188 return fileName;
189 }
190 async loadServerConfig(configFileName) {
191 let config = this.loadConfigObject(configFileName);
192 if (process.env.NODE_ENV) {
193 const envConfigFileName = (`${configFileName}-${process.env.NODE_ENV}`);
194 const envConfig = this.loadConfigObject(envConfigFileName);
195 if (envConfig) {
196 config = _.defaultsDeep(envConfig, config);
197 }
198 }
199 if (!config) {
200 config = await this.loadDefaultServerConfig();
201 }
202 return config;
203 }
204 async loadDefaultServerConfig() {
205 const filePath = path.join(process.cwd(), 'tree-gateway.yaml');
206 console.info(chalk_1.default.yellowBright(`No server configuration file was found. Creating a configuration file and saving it on '${filePath}'`));
207 const config = YAML.load(require.resolve('./tree-gateway-server-default.yaml'));
208 const answers = await this.askRedisOptions();
209 this.createRedisConfiguration(config, answers);
210 await fs.writeFile(filePath, YAML.stringify(config, 15));
211 return config;
212 }
213 askRedisOptions() {
214 return inquirer.prompt([
215 {
216 choices: ['Cluster', 'Standalone'],
217 default: 'Standalone',
218 filter: function (val) {
219 return val.toLowerCase();
220 },
221 message: 'Choose the redis topology:',
222 name: 'connectionType',
223 type: 'list'
224 },
225 {
226 default: 'localhost',
227 message: 'Redis host:',
228 name: 'host',
229 type: 'input'
230 },
231 {
232 default: '6379',
233 message: 'Redis port:',
234 name: 'port',
235 type: 'input',
236 validate: function (val) {
237 const valid = val === '' || val.match(/^[0-9]+$/) !== null;
238 return valid || 'Please enter a number';
239 }
240 },
241 {
242 message: 'Redis DB number (Optional):',
243 name: 'db',
244 type: 'input',
245 validate: function (val) {
246 const valid = val === '' || val.match(/^[0-9]+$/) !== null;
247 return valid || 'Please enter a number';
248 }
249 },
250 {
251 message: 'Redis Password (Optional):',
252 name: 'password',
253 type: 'password'
254 }
255 ]);
256 }
257 createRedisConfiguration(config, answers) {
258 if (answers['connectionType'] === 'standalone') {
259 config.database.redis = {
260 standalone: {
261 host: answers['host'],
262 port: parseInt(answers['port'], 10)
263 }
264 };
265 }
266 else {
267 config.database.redis = {
268 cluster: [{
269 host: answers['host'],
270 port: parseInt(answers['port'], 10)
271 }]
272 };
273 }
274 if (answers['db'] || answers['password']) {
275 config.database.redis.options = {};
276 if (answers['db']) {
277 config.database.redis.options.db = parseInt(answers['db'], 10);
278 }
279 if (answers['password']) {
280 config.database.redis.options.password = answers['password'];
281 }
282 }
283 }
284 loadDefaultGatewayConfig() {
285 const gateway = YAML.load(require.resolve('./tree-gateway-default.yaml'));
286 console.info(`No configuration for gateway was found. Using default configuration and saving it on database.`);
287 gateway.admin.userService.jwtSecret = uuid();
288 return gateway;
289 }
290 /**
291 * This function cast all array properties inside server configuration to array.
292 * It is used to allow user to configure array properties as a single item too.
293 * @param server Server configuration
294 */
295 castArrays(server) {
296 config_2.castArray(server, 'database.redis.cluster');
297 config_2.castArray(server, 'database.redis.sentinel.nodes');
298 config_2.castArray(server, 'gateway.filter');
299 config_2.castArray(server, 'gateway.admin.filter');
300 config_2.castArray(server, 'gateway.serviceDiscovery.provider');
301 config_2.castArray(server, 'gateway.logger.console.stderrLevels');
302 config_2.castArray(server, 'gateway.accessLogger.console.stderrLevels');
303 if (_.has(server, 'gateway.config.cache')) {
304 _.keys(server.gateway.config.cache).forEach(cacheKey => {
305 config_2.castArray(server.gateway.config.cache[cacheKey], 'server.preserveHeaders');
306 });
307 }
308 if (_.has(server, 'gateway.config.cors')) {
309 _.keys(server.gateway.config.cors).forEach(corsKey => {
310 config_2.castArray(server.gateway.config.cors[corsKey], 'allowedHeaders');
311 config_2.castArray(server.gateway.config.cors[corsKey], 'exposedHeaders');
312 config_2.castArray(server.gateway.config.cors[corsKey], 'method');
313 });
314 }
315 }
316};
317Configuration = Configuration_1 = __decorate([
318 typescript_ioc_1.Singleton,
319 typescript_ioc_1.AutoWired,
320 __metadata("design:paramtypes", [])
321], Configuration);
322exports.Configuration = Configuration;
323var Configuration_1;
324//# sourceMappingURL=configuration.js.map
\No newline at end of file