UNPKG

@mdf.js/service-registry

Version:

MMS - API - Service Registry

186 lines 7.32 kB
"use strict"; /** * Copyright 2024 Mytra Control S.L. All rights reserved. * * Use of this source code is governed by an MIT-style license that can be found in the LICENSE file * or at https://opensource.org/licenses/MIT. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ObservabilityAppManager = void 0; const tslib_1 = require("tslib"); const http_server_provider_1 = require("@mdf.js/http-server-provider"); const middlewares_1 = require("@mdf.js/middlewares"); const cluster_1 = tslib_1.__importDefault(require("cluster")); const express_1 = tslib_1.__importDefault(require("express")); const http_proxy_middleware_1 = require("http-proxy-middleware"); const lodash_1 = require("lodash"); const types_1 = require("./types"); /** * Manages the lifecycle and configuration of an Express application dedicated to observability. * This includes setting up middleware, routing, and server configuration. * It also supports dynamic registration of services and links for enhanced observability. */ class ObservabilityAppManager { /** * Create an instance of observability service * @param options - observability options * @param registry - registry to be used for endpoints metrics */ constructor(options, registry) { this.registry = registry; /** Links offered by application */ this._links = {}; this._router = express_1.default.Router(); this._options = (0, lodash_1.merge)({ service: { primaryPort: types_1.DEFAULT_PRIMARY_PORT, port: types_1.DEFAULT_PORT } }, options); this._options.service.port = this.checkPortInRange(this._options.service.port, types_1.DEFAULT_PORT); this._options.service.primaryPort = this.checkPortInRange(this._options.service.primaryPort, types_1.DEFAULT_PRIMARY_PORT); } /** Indicates whether the server has been initialized. */ get isBuild() { return !!this._server; } /** Starts the server if it has been built. */ async start() { var _a; await ((_a = this._server) === null || _a === void 0 ? void 0 : _a.start()); } /** Stops the server if it is running. */ async stop() { var _a; await ((_a = this._server) === null || _a === void 0 ? void 0 : _a.stop()); } /** Constructs the server with the configured options. */ build() { var _a; if (this.isBuild) { return; } if (this.isWorker) { this._app = this.workerApp(); } else { this._app = this.primaryApp(this._router, this.registry, this.apiVersion, middlewares_1.Middleware.Default.FormatLinks(this.apiVersion, this._links)); } this._server = http_server_provider_1.HTTP.Factory.create({ name: 'observability', config: { app: this._app, port: this.getPort(), host: (_a = this._options.service) === null || _a === void 0 ? void 0 : _a.host, }, }); } /** Resets the server to its initial state. */ unbuilt() { this._server = undefined; this._router = express_1.default.Router(); this._links = {}; this._app = undefined; } /** @returns The links offered by this service */ get links() { return middlewares_1.Middleware.Default.FormatLinks(`${this.baseURL}:${this.getPort()}${this.apiVersion}`, this._links); } /** Registers a new service with the observability app. */ register(service) { const _services = Array.isArray(service) ? service : [service]; for (const service of _services) { if (typeof service.router !== 'undefined') { this.addRouter(service.router); } if (typeof service.links === 'object') { this.addLinks(service.links); } } } /** Get the base url whew the observability is served */ get baseURL() { var _a, _b; const _attachedAddress = (_b = (_a = this._server) === null || _a === void 0 ? void 0 : _a.client) === null || _b === void 0 ? void 0 : _b.address(); let address; if (_attachedAddress) { if (typeof _attachedAddress === 'string') { address = _attachedAddress.split(':')[1]; } else { address = _attachedAddress.address; } } else { address = '127.0.0.1'; } return `http://${address}`; } /** Get the api version */ get apiVersion() { return `/v${this._options.metadata.version}`; } /** Add a new link to the observability */ addLinks(links) { this._links = (0, lodash_1.merge)(this._links, links); } /** Add a new router to the observability */ addRouter(router) { this._router.use(router); } /** * Create an express app that offer all the services routes * @param router - router to be used * @param registry - registry to be used for endpoints metrics * @param apiVersion - api version to be used * @param defaultLinks - default links to be used */ primaryApp(router, registry, apiVersion, defaultLinks) { const app = (0, express_1.default)(); app.use(middlewares_1.Middleware.RequestId.handler()); app.use(middlewares_1.Middleware.BodyParser.JSONParserHandler()); app.use(middlewares_1.Middleware.Metrics.handler(registry)); app.use(apiVersion, router); app.use(middlewares_1.Middleware.Default.handler(defaultLinks)); app.use(middlewares_1.Middleware.ErrorHandler.handler()); return app; } /** Create an express app that redirect all the request to the master */ workerApp() { const app = (0, express_1.default)(); app.use((0, http_proxy_middleware_1.createProxyMiddleware)({ router: () => `${this.baseURL}:${this._options.service.primaryPort}`, changeOrigin: true, })); return app; } /** Get if the current process is a worker */ get isWorker() { return cluster_1.default.isWorker; } /** Get if the current process is working in cluster mode */ get isClusterMode() { var _a, _b; return typeof ((_a = this._options.service) === null || _a === void 0 ? void 0 : _a.isCluster) === 'boolean' ? (_b = this._options.service) === null || _b === void 0 ? void 0 : _b.isCluster : false; } /** * Check if the port is in the range of valid ports * @param port - port to be used * @param defaultPort - default port to be used * @returns The port to be used */ checkPortInRange(port, defaultPort) { return !port || port < 1 || port > 65535 ? defaultPort : port; } /** * Get the port to be used by the service based on the configuration * @returns The port to be used */ getPort() { if (this.isClusterMode && cluster_1.default.isPrimary) { return this._options.service.primaryPort; } else { return this._options.service.port; } } } exports.ObservabilityAppManager = ObservabilityAppManager; //# sourceMappingURL=ObservabilityAppManager.js.map