UNPKG

@restorecommerce/chassis-srv

Version:

Restore Commerce microservice chassis

147 lines 5.06 kB
import { createLogger } from '@restorecommerce/logger'; import { isNullish, isString, keys } from 'remeda'; import { EventEmitter } from 'events'; import { grpcServer } from './transport/provider/grpc/index.js'; const transports = {}; /** * register transport provider * * @param {string} name transport provider identifier * @param {constructor} provider transport provider constructor function */ export const registerTransport = (name, provider) => { transports[name] = provider; }; // register included providers registerTransport('grpc', grpcServer); /** * Initializes all configured transports. * @param {object} config Configuration * @param {object} logger * @return {object} Transport */ const setupTransport = (config, logger) => { const transport = {}; logger.debug('available transport providers', Object.keys(transports).join(',')); for (let i = 0; i < config.length; i += 1) { const transportCfg = config[i]; const providerName = transportCfg.provider; if (isNullish(providerName)) { throw new Error('transport configuration without a provider'); } const transportName = transportCfg.name; if (isNullish(providerName)) { throw new Error('transport configuration without a name'); } const TransportProvider = transports[providerName]; if (isNullish(TransportProvider)) { throw new Error(`transport provider ${providerName} does not exist`); } const provider = new TransportProvider(transportCfg, logger); transport[transportName] = provider; } logger.debug('using transports', Object.keys(transport).join(',')); return transport; }; /** * Server is a microservice server chassis. * It enables business logic to be accessed over transports and listen to events. * Default event providers: 'kafka' * Default transports: 'grpc' * @class */ export class Server extends EventEmitter { config; logger; middleware; transport; /** * @constructor * @param {object} config Server config. * @param {Logger} logger */ constructor(config, logger) { super(); if (isNullish(config)) { throw new Error('mising argument config'); } this.config = config; // logger if (isNullish(logger)) { if (isNullish(this.config.logger)) { this.logger = createLogger(); } else { const loggerCfg = this.config.logger; this.logger = createLogger(loggerCfg); } } else { this.logger = logger; } // services this.logger.debug('setting up service endpoints'); // transports this.logger.debug('setting up transports'); try { this.transport = setupTransport(this.config.transports, this.logger); } catch (error) { this.logger.error('setupTransports', { code: error.code, message: error.message, stack: error.stack }); throw error; } } /** * bind connects the service to configured transports. * * @param {string} name Service name. * @param {BindConfig} bindConfig A business logic service. */ async bind(name, bindConfig) { if (isNullish(name)) { throw new Error('missing argument name'); } if (!isString(name)) { throw new Error('argument name is not of type string'); } if (isNullish(bindConfig)) { throw new Error('missing argument bindConfig'); } this.logger.debug('binding endpoints to transports'); const transportNames = Object.keys(this.transport); const transport = this.transport; for (let i = 0; i < transportNames.length; i += 1) { const transportName = transportNames[i]; const provider = transport[transportName]; await provider.bind(bindConfig); this.emit('bound', name, bindConfig, provider); } } /** * start launches the server by starting transports and listening to events. */ async start() { const transportNames = Object.keys(this.transport); for (let i = 0; i < transportNames.length; i += 1) { const name = transportNames[i]; const provider = this.transport[name]; await provider.start(); this.logger.info(`transport ${name} started`); } this.emit('serving', this.transport); } /** * Shuts down all transport provider servers. */ async stop() { const transportNames = keys(this.transport); for (let i = 0; i < transportNames.length; i += 1) { const name = transportNames[i]; if (this.transport[name].end) { await this.transport[name].end(); } } this.emit('stopped', this.transport); } } //# sourceMappingURL=server.js.map