1 | 'use strict';
|
2 | var __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 | };
|
8 | var __metadata = (this && this.__metadata) || function (k, v) {
|
9 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
10 | };
|
11 | Object.defineProperty(exports, "__esModule", { value: true });
|
12 | const fs = require("fs-extra-promise");
|
13 | const _ = require("lodash");
|
14 | const path = require("path");
|
15 | const YAML = require("yamljs");
|
16 | const uuid = require("uuid");
|
17 | const events_1 = require("events");
|
18 | const gateway_1 = require("./config/gateway");
|
19 | const typescript_ioc_1 = require("typescript-ioc");
|
20 | const env_1 = require("./utils/env");
|
21 | const users_1 = require("./service/users");
|
22 | const middleware_1 = require("./service/middleware");
|
23 | const api_1 = require("./service/api");
|
24 | const config_1 = require("./service/config");
|
25 | const gateway_2 = require("./service/gateway");
|
26 | const plugin_data_1 = require("./service/plugin-data");
|
27 | const config_2 = require("./utils/config");
|
28 | const inquirer = require("inquirer");
|
29 | const chalk_1 = require("chalk");
|
30 | _.mixin(require('lodash-deep'));
|
31 | let 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 |
|
292 |
|
293 |
|
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 | };
|
317 | Configuration = Configuration_1 = __decorate([
|
318 | typescript_ioc_1.Singleton,
|
319 | typescript_ioc_1.AutoWired,
|
320 | __metadata("design:paramtypes", [])
|
321 | ], Configuration);
|
322 | exports.Configuration = Configuration;
|
323 | var Configuration_1;
|
324 |
|
\ | No newline at end of file |