UNPKG

floret

Version:

Microservice Library for Node

1,260 lines (1,066 loc) 39.9 kB
const logger = require('koa-logger'); const Router = require('koa-router'); const appRouter = new Router(); const Koa = require('koa'); const ip = require('ip'); const bodyParser = require('koa-bodyparser'); const apiDoc = require('swagger-jsdoc'); const fs = require('fs'); const uuidv4 = require('uuid/v4'); const send = require('koa-send'); // core floret services const Config = require('./config/floret-config.js'); const Service = require('./service/floret-service.js'); const Channel = require('./channel/floret-channel.js'); const Subscriber = require('./subscriber/floret-subscriber.js'); const Subscription = require('./subscription/floret-subscription.js'); const Package = require('./package/floret-package.js'); let FloretClass; { // private const _host = Symbol('host'); const _name = Symbol('name'); const _port = Symbol('port'); const _uri = Symbol('uri'); const _appRouter = Symbol('router'); const _gateway = Symbol('gateway'); const _listen = Symbol('listen'); const _subscribers = Symbol('subscribers'); const _subscriptions = Symbol('subscriptions'); const _channels = Symbol('channels'); const _service = Symbol('service'); const _baseURL = Symbol('baseURL'); const _config = Symbol('config'); const _docPaths = Symbol('docPaths'); const _disconnected = Symbol('disconnected'); const _registeredAPIs = Symbol('registeredAPIs'); const _environmentVars = Symbol('environmentVars'); const _modules = Symbol('modules'); const _logging = Symbol('_logging'); const _root = Symbol('_root'); // replaceable classes const _gatewayClass = Symbol('gatewayClass'); const _subscriberClass = Symbol('subscriberClass'); const _subscriptionClass = Symbol('subscriptionClass'); const _channelClass = Symbol('channelClass'); const _serviceClass = Symbol('serviceClass'); const _packageClass = Symbol('packageClass'); const _configClass = Symbol('configClass'); const _send = Symbol('sender'); const _apiDoc = Symbol('apiDoc'); FloretClass = class Floret extends Koa { constructor(floretConfig, ...[ConfigOverride, ChannelOverride, SubscriberOverride, SubscriptionOverride, ServiceOverride, PackageOverride]) { // koa super(); if (floretConfig) { this[_gatewayClass] = require(floretConfig.gatewayModulePath || floretConfig.gatewayModuleName); this.configure(floretConfig, ...[ConfigOverride, ChannelOverride, SubscriberOverride, SubscriptionOverride, ServiceOverride, PackageOverride]); this.configureServices(); } else { console.log('setting default gateway class: floret-gateway-kong'); this[_gatewayClass] = require('floret-gateway-kong'); } this[_configClass] = Config; this[_channelClass] = Channel; this[_subscriberClass] = Subscriber; this[_subscriptionClass] = Subscription; this[_serviceClass] = Service; this[_packageClass] = Package; this[_appRouter] = appRouter; this[_apiDoc] = apiDoc; this[_modules] = {}; this[_send] = send; } configure(floretConfig, ...[ConfigOverride, ChannelOverride, SubscriberOverride, SubscriptionOverride, ServiceOverride, PackageOverride]) { this[_config] = floretConfig.params; console.log('configuring with ', JSON.stringify(this[_config])); const name = this[_config].gatewayModuleName ? `../../${this[_config].gatewayModuleName}` : ''; if (!floretConfig.disconnected) { let modPath = this[_config].gatewayModulePath || name; this[_gatewayClass] = modPath ? require(modPath) : require('../../floret-gateway-kong'); } this[_host] = this[_config].host; this[_name] = this[_config].name; this[_port] = this[_config].port; this[_root] = this[_config].root; this[_uri] = this[_config].uri || `/${this[_name]}`; this[_docPaths] = this[_config].documentationPaths || []; console.log('this[_host], this[_name], this[_port], this[_root], this[_uri]', this[_host], this[_name], this[_port], this[_root], this[_uri]) this[_listen] = super.listen; this[_disconnected] = this[_config].disconnected; this[_logging] = this[_config].logging; this[_registeredAPIs] = []; if (!this[_disconnected]) { this[_subscribers] = []; this[_subscriptions] = []; this[_channels] = {}; // overridess this[_configClass] = ConfigOverride || Config; this[_channelClass] = ChannelOverride || Channel; this[_subscriberClass] = SubscriberOverride || Subscriber; this[_subscriptionClass] = SubscriptionOverride || Subscription; this[_serviceClass] = ServiceOverride || Service; this[_packageClass] = PackageOverride || Package; this[_gateway] = new this[_gatewayClass]('gw', this[_config].gatewayHost, this[_config].gatewayAdminPort, this[_config].gatewayProxyPort); this[_service] = new this[_serviceClass](this[_name], this[_host], this[_port], this[_uri]); this[_baseURL] = `${this[_gateway].ensureProtocol(this[_host])}:${this[_port]}${this[_uri]}`; } this.configureServices(); this.isInit = false; console.log('Configuration complete.'); } configureServices() { if (this[_config].channels) { this.configureChannels(this[_config].channels); } if (this[_config].subscriptions) { this.configureSubscriptions(this[_config].subscriptions); } if (this[_config].apis) { this.configureAPIs(this[_config].apis); } } /** * * @param portOverride */ async listen(portOverride) { if (!this.isInit) { await this.init().then(() => {}).catch((e) => { throw e; }); console.log('...complete.'); } const srv = await this[_listen](portOverride || this[_port]); console.log(`Listening on port ${JSON.stringify(srv.address().port)}`); return srv; } /** * * @returns {send} */ get serve() { return this[_send]; } /** * * @returns {boolean} */ async init() { try { console.log(`Initializing ${this[_name]}:`); console.log(`...routes prefixed [${this[_uri]}]`); this.router.prefix(this[_uri]); if (!this[_disconnected]) { let routes = []; await this[_gateway].gatewayHealthCheck(); console.log('...gateway verified'); const service = await this.registerService(); this[_service].id = service.id; console.log(`...service ${this[_name]} registered with gateway. id: ${this[_service].id}`); console.log() routes = routes.concat(await this.publishFloretConfig()); console.log(`...floret spec created: (${this[_uri]}/floret.json)`); routes = routes.concat(await this.createHealthCheck()); console.log(`...healthcheck created: (${this[_uri]}/healthcheck)`); await this.createSubscriberAPI(); console.log('...subscriber api created'); routes = routes.concat(await this.initSubscriptions()); await this.registerRoutes(routes); console.log('...subscriptions initialized'); const channelService = await this.createChannelService(this[_name]); routes = await this.initChannels(channelService); console.log('...subscriber api created'); await this.registerRoutes(routes, `${this[_name]}-channel`); console.log(`...channel service ${this[_name]}-channel initialized`); await this.createSubscriberService(this[_name]); console.log('subscriber service created'); routes = await this.initSubscribers(this[_channels]); await this.registerRoutes(routes, `${this[_name]}-subscriber`); routes = await this.registerAPIs(); console.log('...api endpoints created'); if (this[_config].publishDocs) { await this.publishAPIDocumentation(this[_docPaths]); console.log('...api documentation published'); } await this.registerRoutes(routes); console.log('...service routes registered with gateway'); } this.use(bodyParser()); if (this[_logging]) { this.use(logger()); } this.use(async (ctx, next) => { ctx.body = ctx.request.body; await next(); }); this.use(this.router.routes()); this.use(this[_appRouter].allowedMethods()); this.isInit = true; return true; } catch (e) { console.log('Error occurred during floret init routine.'); console.log(e); throw e; } } /** * * @returns {*} */ get name() { return this[_name]; } /** * * @returns {*} */ get host() { return this[_host]; } /** * * @returns {*} */ get port() { return this[_port]; } /** * * @returns {string} */ get url() { return `${this[_host]}:${this[_port]}`; } /** * * @returns {*} */ get service() { return this[_service]; } get Service() { return this[_serviceClass]; } /** * * @returns {*} */ get router() { return this[_appRouter]; } /** * * @returns {*} */ get gateway() { return this[_gateway]; } get Gateway() { return this[_gatewayClass]; } /** * * @returns {*} * @constructor */ get Package() { return this[_packageClass]; } /** * * @param pkg * @constructor */ set Package(pkg) { this[_packageClass] = pkg; } get config() { return this[_config]; } /** * * @returns {*} * @constructor */ get Config() { return this[_configClass]; } /** * * @param cfg * @constructor */ set Config(cfg) { this[_configClass] = cfg; } /** * * @returns {*} */ get apiDoc() { return this[_apiDoc]; } /** * * @returns {*} */ get uri() { return this[_uri]; } /** * * @param u */ set uri(u) { this[_uri] = u; } /** * * @returns {*} */ get baseURL() { return this[_baseURL]; } /** * * @returns {*} */ get baseURI() { return this[_uri]; } /** * */ async createHealthCheck() { this[_appRouter].get('/healthcheck/ping', (ctx) => { ctx.set('Content-Type', 'text/plain'); ctx.body = 'OK'; }); this[_appRouter].get('/healthcheck/', async (ctx) => { const gwHealth = await this[_gateway].gatewayHealthCheck(); ctx.body = { ping: { healthy: true, }, 'api-gateway': { healthy: gwHealth.status === 'active', message: `api gateway at ${this[_gateway].url}`, }, }; }); const routes = []; routes.push( { path: `${this[_uri]}/healthcheck`, methods: ['GET', 'OPTIONS'], }, { path: `${this[_uri]}/healthcheck/ping`, methods: ['GET', 'OPTIONS'], }, ); return routes; } publishFloretConfig() { this[_appRouter].get('/floret.json', (ctx) => { ctx.body = this[_config]; }); return [{ path: `${this[_uri]}/floret.json`, methods: ['GET', 'OPTIONS'], }]; } /** API ************************************************************************************ */ /** * * @param name * @returns {*} */ async getAPI(name) { try { return await this.gateway.getAPI(name); } catch (e) { // throw e; return {}; } } get registeredAPIs() { return this[_registeredAPIs]; } set registeredAPIs(arr) { this[_registeredAPIs] = arr; } registerAPIs() { console.log('...registering apis'); const routes = []; this[_registeredAPIs].map((api) => { routes.push({ path: api.uri, methods: api.methods, }); return api; }); return routes; } async registerService() { console.log('calling register service: ') console.log('name' + this[_name], 'host' + this[_host], 'port' + this[_port], '/'); return this[_gateway].addService({ name: this[_name], host: this[_host], port: this[_port], path: '/' }); } async registerRoutes(routes = [], serviceName = this[_name], methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) { let paths = []; let allMethods = []; for (let i = 0; i < routes.length; i++) { paths = paths.concat(routes[i].path); allMethods = methods.concat(routes[i].methods); } await this[_gateway].addRoute({ serviceName, allMethods, paths, }); } /** * * @param name * @param uri * @param methods */ async registerAPI(name, uri, methods) { await this[_gateway].addRoute({ serviceName: this[_name], methods, path: uri, }).catch((e) => { console.log(e.stack); }); } /** * * @param name * @param uri * @param methods */ async registerExternalAPI(name, uri, url, methods) { await this[_gateway].addAPI(name, this[_uri] + uri, `${url}`, methods).then(() => { }).catch((e) => { if (e.statusCode !== 409) { console.log(`api could not be registered. ${e.message}`); throw e; } }); } prependUri(uri) { if (uri.indexOf(this[_uri]) < 0) { return this[_uri] + uri; } return uri; } prependName(name) { if (name.indexOf(this[_name]) < 0) { return `${this[_name]}-${name}`; } return name; } configureAPIs(apis) { const newApis = apis.map((api) => { if (api.path) { require(`${this[_root]}${api.path}`)(this); } api.uri = this.prependUri(api.uri); return api; }); this[_registeredAPIs] = this[_registeredAPIs] || []; this[_registeredAPIs] = this[_registeredAPIs].concat(newApis); } /** * * @param name * @returns {*} */ async deleteAPI(name) { return this.gateway.deleteAPI(name); } /** * @param uri * @param method * @param payload * @param gateway * @returns {*|any|XMLHttpRequest} */ async apiRequest(uri, method, payload, trackingId, gatewayOverride) { const gw = gatewayOverride || this[_gateway]; trackingId = trackingId || uuidv4(); const options = { method, uri: gw.proxyURL + uri, header: { 'Content-Type': 'application/json', }, }; options.body = payload || {}; if (method.indexOf('post')) { options.header['Content-Type'] = 'application/json'; } options.body.trackingId = options.body.trackingId || trackingId; const res = await gw.send(options); res.trackingId = trackingId; return res; } /** API Docs ******************************************************************************* */ /** * * @param newPaths * @returns {Promise<void>} */ async publishAPIDocumentation(newPaths = []) { console.log('...creating OpenAPI Spec'); this.buildAPISpec(newPaths); const channel = await this.createAPISpecChannel(); // subscribe channel.broadcast(this.name, { url: this.apiSpecURL }); // send a message to the document service const options = { uri: `${this.gateway.proxyURL}/api-doc/specs`, method: 'GET', }; console.log('about to pusblish') // notify api-doc service to refresh spec list await this.gateway.publishAPISpec(options).then(() => { console.log('done publish') }).catch((e) => { console.log(`Default document service not found (${this.gateway.proxyURL}/api-doc/specs)`); console.log(e.message); }); const routes = [{ path: '/api-spec.json', methods: ['GET', 'POST', 'DELETE'], }]; console.log('done') return routes; } /** * * @returns {Promise<*>} */ async createAPISpecChannel() { const channelConfig = { name: 'api-spec', description: 'api spec', uri: '/api-spec', endpoint: `${this.url}${this.uri}/api-spec`, }; const channel = new this[_channelClass](channelConfig); await this.addChannel(channel); return this.channels[channelConfig.name]; } /** * * @returns {string} */ get apiSpecURL() { return `${this.url}${this.uri}}/api-spec.json`; } /** * * @param newPaths */ buildAPISpec(documentedCodePaths = []) { const swaggerDefinition = { info: { title: `${this.name}`, version: '1.0.0', description: 'A sample API', }, host: this.gateway.proxyURL.split('http://')[1], basePath: '/', }; // Options for the swagger docs const options = { swaggerDefinition, apis: documentedCodePaths, }; const swaggerSpec = this[_apiDoc](options); swaggerSpec.paths[`${this.uri}/subscribe`] = { post: { summary: 'subscribe to channel', operationId: 'subscribe', tags: ['floret'], responses: [ { 200: { name: 'floret subscription id', }, 201: { description: 'Null response', }, }], }, delete: { summary: 'unsubscribe to channel', operationId: 'subscribe', tags: ['floret'], responses: [ { 200: { name: 'floret subscription id', }, 201: { description: 'Null response', }, }], }, }; swaggerSpec.paths[`${this.uri}/healthcheck`] = { get: { summary: 'returns an active health status when running', operationId: 'healthcheck', tags: ['floret'], responses: [ { 200: { status: 'active', }, }], }, }; swaggerSpec.paths[`${this.uri}/floret.json`] = { get: { summary: 'returns an floret configuration', operationId: 'floret', tags: ['floret'], responses: [ { 200: { }, }], }, }; this.router.get('/api-spec.json', (ctx) => { ctx.set('Content-Type', 'application/json'); ctx.body = swaggerSpec; }); return swaggerSpec; } /** * * @returns {Promise<*>} */ async discoverAPISpecs() { const apis = await this[_gateway].discoverAPISpecs(); return apis; } /** Channels ******************************************************************************* */ /** * */ // list of channel routes ( path + methods ) async createChannelService(serviceName) { // get the service const service = await this[_gateway].getServiceByName(serviceName); console.log('calling addService from createChannelService (floret)', 'name:'+ `${serviceName}-subscriber`, 'host:' + this[_host], 'port:' + this[_port], 'path:' + `/link/${serviceName}/${service.id}`) return this[_gateway].addService({ name: `${serviceName}-channel`, host: this[_host], port: this[_port], path: `/link/${serviceName}/${service.id}`, }); } async createSubscriberService(serviceName) { // get the service const service = await this[_gateway].getServiceByName(serviceName); console.log('calling addService from createSubscriberService (floret)', 'name:'+ `${serviceName}-subscriber`, 'host:' + this[_host], 'port:' + this[_port], 'path:' + `/link/${serviceName}/${service.id}`) return this[_gateway].addService({ name: `${serviceName}-subscriber`, host: this[_host], port: this[_port], path: `/link/${serviceName}/${service.id}` }); } // async initSubscribers(channels) { // } async getChannelsFromGateway(serviceName) { return this.discoverChannels(serviceName); } async initChannels() { const gatewayChannels = await this.getChannelsFromGateway(this[_name]); let keys = Object.keys(gatewayChannels); for (let i = 0; i < keys.length; i++) { if (this[_channels][keys[i]]) { delete gatewayChannels[keys[i]]; } else { this[_channels][keys[i]] = gatewayChannels[keys[i]]; } } this[_channels] = Object.assign(this[_channels], gatewayChannels); const routes = []; keys = Object.keys(this[_channels]); for (let i = 0; i < keys.length; i++) { routes.push({ path: `${this[_uri]}/channels/${this[_channels][keys[i]].name}`, methods: ['GET', 'POST'], }); } return routes; } addChannels(channelArray) { channelArray.map((chan) => { this[_channels][chan.name] = chan; }); } configureChannels(chanConfigArr) { // configuration-based channels chanConfigArr.map((ch) => { ch.endpoint = this.baseURL; ch.serviceName = this[_name]; const channel = this.addChannel(new this.Channel(ch)); }); } /** * * @param channel */ async initChannel(channelName) { await this.discoverSubscribers(this[_name], channelName); console.log(`......initialized channel ${channelName}`); } async initSubscribers(channels) { for (const channelName in channels) { const subscribers = await this.discoverSubscribers(channelName); } } /** * * @returns {*} * @constructor */ get Channel() { return this[_channelClass]; } /** * * @param channel * @constructor */ set Channel(channel) { this[_channelClass] = channel; } addChannel(channel) { this[_channels][channel.name] = channel; } /** * * @returns {*} */ get channels() { return this[_channels]; } /** * * @returns {*|Observable.<R>|any} */ async discoverChannels(serviceName) { const registeredChannels = await this[_gateway].discoverChannels(serviceName || this[_name]) || []; // return channels in object format const channelMap = registeredChannels.reduce((accObj, chan) => { for (let i = 0; i < chan.paths.length; i++) { const path = chan.paths[i]; if (path.indexOf('/channels/') > -1) { const chanName = path.split(`/${this[_name]}/channels/`)[1]; const chanConfig = { endpoint: `${this[_uri]}/channels/${chanName}`, name: chanName, description: chanName, serviceName: this[_name], uri: `${this[_uri]}/channels/${chanName}`, }; accObj[chanName] = new this.Channel(chanConfig); } } return accObj; }, {}); return channelMap; } /** * * @param channel */ updateChannel(channel) { const name = channel.name; for (let i = 0; i < this[_channels].length; i++) { if (this[_channels][i].config().name === name) { this[_channels][i] = channel; } } } /** * * @param channel */ async deleteChannel(channel) { const channelInfo = channel.config(); delete this[_channels][channel.name]; this[_gateway].deleteChannelAPI(channelInfo.apiName).then(() => { for (let i = 0; i < this[_channels].length; i++) { if (this[_channels][i].name === channel.name) { this[_channels].splice(i, 1); i++; } } }); } /** Subscribers **************************************************************************** */ /** * * @returns {*} * @constructor */ get Subscriber() { return this[_subscriberClass]; } /** * * @param subscriber * @constructor */ set Subscriber(subscriber) { this[_subscriberClass] = subscriber; } /** * * @returns {*} */ async discoverSubscribers(channel) { const subscribers = await this[_gateway].discoverSubscribers(this[_name], channel); subscribers.map((sub) => { if (sub.length > 0) { for (let i = 0; i < sub.length; i++) { const subscription = sub[i]; const channelName = subscription.channelName; const url = `${this[_gateway].proxyURL}/${subscription.service}/subscriptions/${subscription.name}`; const subObj = new this.Subscriber(subscription.name, subscription.service, `${this[_gateway].proxyURL}/${subscription.service}/subscriptions/${subscription.name}`); if (!this.channels[channelName].subscribers[subscription.name]) { this.attachSubscriber(this.channels[channelName], subObj); } } } return sub; }); return subscribers; } attachSubscriber(channel, subscriber) { if (channel && subscriber) { if (!channel.subscribers[subscriber.name]) { channel.subscribe(subscriber); } } } /** * */ async createSubscriberAPI() { // gateway endpoint for new subscriptions console.log('adding route for subscriber for: ' + this[_name]); await this[_gateway].addRoute({ serviceName: this[_name], methods: ['GET', 'POST', 'OPTIONS', 'DELETE'], paths: [`${this[_uri]}/subscribe`] }); // subscribe api this[_appRouter].post('/subscribe/', async (ctx, next) => { const subRequest = ctx.request.body; const subscriberName = subRequest.name; const channelName = subRequest.channel; const serviceName = subRequest.service; const serviceURL = subRequest.url; ctx.body = { name: subRequest.name, }; const newSubscriber = new this.Subscriber(subRequest.name, subRequest.service, subRequest.url); const subURI = `/${this[_name]}/channels/${subRequest.channel}/subscriber/${subRequest.service}/subscriptions/${subRequest.name}`; this.attachSubscriber(this.channels[subRequest.channel], newSubscriber); // create the subscriber gateway endpoint await this[_gateway].addRoute({ serviceName: `${this[_name]}-subscriber`, methods: ['GET', 'POST', 'OPTIONS', 'DELETE'], paths: [subURI], }); }).delete('/subscribe/:channelName/:id', async (ctx) => { console.log('delete inbound'); const channelName = ctx.params.channelName; const subscriberName = ctx.params.id; const subscriberId = ctx.params.id; if (this[_channels][channelName]) { this[_channels][channelName].unsubscribe(subscriberId); } // remove subscriber route path await this[_gateway].deleteRoutePath(this[_name], channelName, subscriberName); // should be empty ctx.body = { result: this[_channels][channelName].subscribers[subscriberName], }; }).get('/subscribers/', (ctx, next) => { ctx.body = this[_subscribers]; }).patch('/subscribers/:name', (ctx, next) => { const event = ctx.body; }) .put('/subscribers/:name', (ctx, next) => { const event = ctx.body; }); } async subscribe({ serviceName, channelName, subscription }) { const res = await this.gateway.subscribeTo({ targetService: serviceName, targetChannel: channelName, subscriberService: this[_name], subscriberName: subscription.name, subscriptionEndpoint: subscription.endpoint, }); return res.name; } async unsubscribe(serviceName, channelName, subscriberName) { await this.gateway.unsubscribe(serviceName, channelName, subscriberName); await this.gateway.deleteAPI(subscriberName); } /** * * @param channelName * @returns {Array|Array.<T>|*|Observable|any} */ subscribersByChannel(channelName) { return this[_subscribers].filter(sub => sub.channel === channelName); } /** * * @param channelName */ removeChannelSubscribers(channelName) { this[_subscribers] = this[_subscribers].filter(sub => sub.channel === channelName); } /** Subscriptions ************************************************************************** */ /** * */ async initSubscriptions() { const routes = []; this[_subscriptions].map((sub) => { sub.init(); console.log(`......initialized subscription ${sub.name}`); routes.push({ path: `/${this[_name]}/subscriptions/${sub.name}`, methods: ['GET', 'POST', 'OPTIONS'], }); }); return routes; } addCustomAPI(api) { this[_registeredAPIs].push(api); } addSubscription(subscription) { if (this[_subscriptions].filter(sub => sub.name === subscription.name).length < 1) { this[_subscriptions].push(subscription); } } getSubscriptionByName(name) { const sub = this[_subscriptions].filter(sub => sub.name === name); return sub[0]; } configureSubscriptions(subs) { subs.map((sub) => { const newSub = new this.Subscription(sub.name, this.service, this.router, this.gateway.proxyURL); const path = sub.path; const handler = require(`${this[_root]}${path}`)(this); newSub.observable.subscribe(handler.onEvent); this.addSubscription(newSub); this.subscribe({ serviceName: sub.service, channelName: sub.channel, subscription: newSub, }).catch((e) => { console.log(`Unabled to subscribe to ${sub.service}-${sub.channel} (${e.message})`); }); }); } get Subscription() { return this[_subscriptionClass]; } /** * * @returns {*} */ get subscriptions() { return this[_subscriptions]; } /** * * @param subArray */ set subscriptions(subArray) { this[_subscriptions] = subArray; } createConfig(cfg, service, host, port, uri, gatewayHost, gatewayAdminPort, gatewayProxyPort, disconnected) { return new this[_configClass](cfg, service, host, port, uri, gatewayHost, gatewayAdminPort, gatewayProxyPort, disconnected); } attachModule(name, fn) { this[_modules][name] = fn; } getModule(name) { return this[_modules][name]; } get environmentVariables() { return this[_environmentVars]; } set environmentVariables(env) { this[_environmentVars] = env; } createEnvConfig(envVars) { let envStr = 'local'; let host; let port; let name; let uri; let gatewayHost; let gatewayAdminPort; let gatewayProxyPort; let disconnected; let root; let config; let envObj; this[_environmentVars] = envVars; if (envVars) { envStr = envVars.FLORET_ENV_KEY || 'local'; host = envVars.FLORET_HOST; port = envVars.FLORET_PORT; name = envVars.FLORET_NAME; uri = envVars.FLORET_URI; gatewayHost = envVars.FLORET_GATEWAY_HOST; gatewayAdminPort = envVars.FLORET_GATEWAY_ADMIN_PORT; gatewayProxyPort = envVars.FLORET_GATEWAY_PROXY_PORT; disconnected = envVars.FLORET_IS_DISCONNECTED; root = envVars.FLORET_ROOT; } root = envStr === 'local' ? process.cwd() : root; config = JSON.parse(fs.readFileSync(`${root}/floret.json`, 'utf8')); config.root = root; if (!config.environments) { config.environments = { local: { gatewayAdminPort: 8001, gatewayProxyPort: 8000, }, }; } if ((envStr === 'local')) { config.environments[envStr].gatewayHost = `${ip.address()}`; config.environments[envStr].host = `${ip.address()}`; config.root = root; } envObj = Object.assign({}, config.environments[envStr]); delete config.environments; return this.createConfig(Object.assign({}, config, envObj), name, host, port, uri, gatewayHost, gatewayAdminPort, gatewayProxyPort, disconnected); } }; } module.exports = FloretClass;