@mdf.js/service-registry
Version:
MMS - API - Service Registry
186 lines • 7.32 kB
JavaScript
"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