UNPKG

nats-micro

Version:

NATS micro compatible extra-lightweight microservice library

183 lines 8.99 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import moment from 'moment'; import { isUndefined } from 'util'; import { z } from 'zod'; import { zodToJsonSchema } from 'zod-to-json-schema'; import { localConfig } from '../localConfig.js'; import { MicroserviceRegistrationSubject, } from '../types/index.js'; import { randomId, wrapMethod, attachThreadContext, } from '../utils/index.js'; const emptyMethodProfile = { num_requests: 0, num_errors: 0, last_error: '', processing_time: 0, average_processing_time: 0, }; export class Discovery { constructor(broker, configOrGetter, options = {}) { this.broker = broker; this.configOrGetter = configOrGetter; this.options = options; this.methodStats = {}; this._isStarted = false; this.startedAt = new Date(); this.id = randomId(); const wrap = (handler, name) => wrapMethod(this.broker, attachThreadContext(this.id, handler.bind(this)), { microservice: this.originalConfig.name, method: name }); this.handleSchemaWrap = wrap(this.handleSchema, 'handleSchema'); this.handleInfoWrap = wrap(this.handleInfo, 'handleInfo'); this.handlePingWrap = wrap(this.handlePing, 'handlePing'); this.handleStatsWrap = wrap(this.handleStats, 'handleStats'); } get originalConfig() { if (typeof (this.configOrGetter) === 'function') return this.configOrGetter(); return this.configOrGetter; } get config() { let config = this.originalConfig; if (this.options.transformConfig) config = this.options.transformConfig(config); return config; } get isStarted() { return this._isStarted; } start() { return __awaiter(this, void 0, void 0, function* () { this._isStarted = true; this.broker.on('$SRV.SCHEMA', this.handleSchemaWrap); this.broker.on(`$SRV.SCHEMA.${this.config.name}`, this.handleSchemaWrap); this.broker.on(`$SRV.SCHEMA.${this.config.name}.${this.id}`, this.handleSchemaWrap); this.broker.on('$SRV.INFO', this.handleInfoWrap); this.broker.on(`$SRV.INFO.${this.config.name}`, this.handleInfoWrap); this.broker.on(`$SRV.INFO.${this.config.name}.${this.id}`, this.handleInfoWrap); this.broker.on('$SRV.PING', this.handlePingWrap); this.broker.on(`$SRV.PING.${this.config.name}`, this.handlePingWrap); this.broker.on(`$SRV.PING.${this.config.name}.${this.id}`, this.handlePingWrap); this.broker.on('$SRV.STATS', this.handleStatsWrap); this.broker.on(`$SRV.STATS.${this.config.name}`, this.handleStatsWrap); this.broker.on(`$SRV.STATS.${this.config.name}.${this.id}`, this.handleStatsWrap); yield this.publish(); return this; }); } stop() { return __awaiter(this, void 0, void 0, function* () { this._isStarted = false; yield this.publishRegistration('down'); this.broker.off('$SRV.SCHEMA', this.handleSchemaWrap); this.broker.off(`$SRV.SCHEMA.${this.config.name}`, this.handleSchemaWrap); this.broker.off(`$SRV.SCHEMA.${this.config.name}.${this.id}`, this.handleSchemaWrap); this.broker.off('$SRV.INFO', this.handleInfoWrap); this.broker.off(`$SRV.INFO.${this.config.name}`, this.handleInfoWrap); this.broker.off(`$SRV.INFO.${this.config.name}.${this.id}`, this.handleInfoWrap); this.broker.off('$SRV.PING', this.handlePingWrap); this.broker.off(`$SRV.PING.${this.config.name}`, this.handlePingWrap); this.broker.off(`$SRV.PING.${this.config.name}.${this.id}`, this.handlePingWrap); this.broker.off('$SRV.STATS', this.handleStatsWrap); this.broker.off(`$SRV.STATS.${this.config.name}`, this.handleStatsWrap); this.broker.off(`$SRV.STATS.${this.config.name}.${this.id}`, this.handleStatsWrap); return this; }); } publish() { return __awaiter(this, void 0, void 0, function* () { yield this.publishRegistration('up'); }); } publishRegistration(state) { return __awaiter(this, void 0, void 0, function* () { yield this.broker.send(MicroserviceRegistrationSubject, { info: this.makeInfo(), state, }); }); } profileMethod(name, error, time) { if (!this.methodStats[name]) this.methodStats[name] = Object.assign({}, emptyMethodProfile); const method = this.methodStats[name]; method.num_requests++; if (!isUndefined(error)) { method.num_errors++; method.last_error = error; } method.processing_time += time; method.average_processing_time = Math.round(Number(method.processing_time) / method.num_requests); } makeMicroserviceData() { return { name: this.config.name, id: this.id, version: this.config.version, metadata: Object.assign(Object.assign({ '_nats.client.created.library': localConfig.name, '_nats.client.created.version': localConfig.version, '_nats.client.id': String(this.broker.clientId) }, (!isUndefined(this.broker.name) ? { 'nats.micro.ext.v1.service.node': this.broker.name } : {})), this.config.metadata), }; } makeMethodData(name, method) { return { name: name, subject: this.getMethodSubject(name, method), }; } getMethodSubject(name, method) { if (method.subject) return method.subject; if (method.local) return `${this.config.name}.${this.id}.${name}`; return `${this.config.name}.${name}`; } makeInfo() { return Object.assign(Object.assign({}, this.makeMicroserviceData()), { description: this.config.description, type: 'io.nats.micro.v1.info_response', endpoints: Object.entries(this.config.methods) .map(([n, m]) => { const metadata = Object.assign({}, m.metadata); if (m.unbalanced) metadata['nats.micro.ext.v1.method.unbalanced'] = 'true'; if (m.local) metadata['nats.micro.ext.v1.method.local'] = 'true'; return Object.assign(Object.assign({}, this.makeMethodData(n, m)), { metadata }); }) }); } getMethodSchema(name, kind) { var _a; const method = this.config.methods[name]; return method ? ((_a = method[kind]) !== null && _a !== void 0 ? _a : z.void()) : undefined; } getMethodJsonSchema(name, kind) { const schema = this.getMethodSchema(name, kind); return schema ? zodToJsonSchema(schema) : undefined; } handleSchema(_req, res) { res.send(Object.assign(Object.assign({}, this.makeMicroserviceData()), { type: 'io.nats.micro.v1.schema_response', endpoints: Object.entries(this.config.methods) .map(([n, m]) => (Object.assign(Object.assign({}, this.makeMethodData(n, m)), { schema: { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion request: this.getMethodJsonSchema(n, 'request'), // eslint-disable-next-line @typescript-eslint/no-non-null-assertion response: this.getMethodJsonSchema(n, 'response'), } }))) })); } handleInfo(_req, res) { res.send(this.makeInfo()); } handleStats(_req, res) { res.send(Object.assign(Object.assign({}, this.makeMicroserviceData()), { type: 'io.nats.micro.v1.stats_response', started: moment(this.startedAt).toISOString(), endpoints: Object.entries(this.config.methods) .map(([n, m]) => { var _a; return (Object.assign(Object.assign({}, this.makeMethodData(n, m)), ((_a = this.methodStats[n]) !== null && _a !== void 0 ? _a : emptyMethodProfile))); }) })); } handlePing(_req, res) { res.send(Object.assign(Object.assign({}, this.makeMicroserviceData()), { type: 'io.nats.micro.v1.ping_response' })); } } //# sourceMappingURL=discovery.js.map