UNPKG

@mdf.js/openc2-core

Version:

MMS - API Core - OpenC2

141 lines 5.84 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.AdapterWrapper = void 0; const tslib_1 = require("tslib"); const core_1 = require("@mdf.js/core"); const crash_1 = require("@mdf.js/crash"); const utils_1 = require("@mdf.js/utils"); const events_1 = tslib_1.__importDefault(require("events")); const lodash_1 = require("lodash"); class AdapterWrapper extends events_1.default { /** * Create a new instance of AdapterWrapper * @param adapter - adapter instance * @param retryOptions - options for job retry operations */ constructor(adapter, retryOptions) { super(); this.adapter = adapter; /** Register an error in the adapter operation */ this.onOperationError = (rawError) => { this.lastOperationError = crash_1.Crash.from(rawError, this.adapter.componentId); this.lastOperationDate = new Date(); this.emitStatus(); }; /** Register an error in the adapter operation */ this.onOperationSuccess = () => { this.lastOperationError = undefined; this.lastOperationDate = new Date(); }; /** Subscribe the incoming message handler to the underlayer transport system */ this.subscribe = async (handler) => { return this.wrappedOperation(this.subscribeOriginal, [handler], this.retryOptions); }; /** Unsubscribe the incoming message handler from the underlayer transport system*/ this.unsubscribe = async (handler) => { return this.wrappedOperation(this.unsubscribeOriginal, [handler], this.retryOptions); }; this.retryOptions = (0, lodash_1.merge)({ logger: this.onOperationError }, retryOptions); if (!this.adapter) { throw new crash_1.Crash('AdapterWrapper requires an adapter instance'); } this.checkMandatoryMethods(); this.subscribeOriginal = this.adapter.subscribe; this.unsubscribeOriginal = this.adapter.unsubscribe; this.adapter.subscribe = this.subscribe; this.adapter.unsubscribe = this.unsubscribe; this.adapter.on('error', this.onOperationError); } /** Component name */ get name() { return this.adapter.name; } /** Component identifier */ get componentId() { return this.adapter.componentId; } /** Connect the OpenC2 Adapter to the underlayer transport system */ start() { return this.adapter.start(); } /** Disconnect the OpenC2 Adapter to the underlayer transport system */ stop() { return this.adapter.stop(); } /** Close the OpenC2 Adapter to the underlayer transport system */ close() { return this.adapter.close(); } /** * Check if the adapter implements the mandatory methods * @throws Crash if the adapter does not implement the mandatory methods */ checkMandatoryMethods() { if (!this.adapter.subscribe || typeof this.adapter.subscribe !== 'function') { throw new crash_1.Crash(`Adapter ${this.adapter.name} does not implement the subscribe method`); } else if (!this.adapter.unsubscribe || typeof this.adapter.unsubscribe !== 'function') { throw new crash_1.Crash(`Adapter ${this.adapter.name} does not implement the unsubscribe method`); } } /** * Perform the retry functionality for a promise * @param task - promise to execute * @param funcArgs - promise arguments * @param options - control execution options * @returns */ async wrappedOperation(task, funcArgs, options) { try { const result = await (0, utils_1.retryBind)(task, this.adapter, funcArgs, options); this.onOperationSuccess(); return result; } catch (rawError) { const error = new crash_1.Crash(`Error performing [${task.name}] operation on ${this.adapter.name} plug`, this.adapter.componentId, { cause: crash_1.Crash.from(rawError, this.adapter.componentId) }); this.onOperationError(error); throw rawError; } } /** Overall component status */ get status() { return core_1.Health.overallStatus(this.checks); } /** Emit the status if it's different from the last emitted status */ emitStatus() { if (this.lastStatusEmitted !== this.status) { this.lastStatusEmitted = this.status; this.emit('status', this.status); } } /** * Return the status of the adapter in a standard format * @returns _check object_ as defined in the draft standard * https://datatracker.ietf.org/doc/html/draft-inadarei-api-health-check-05 */ get checks() { var _a; return { ...this.adapter.checks, [`${this.adapter.name}:lastOperation`]: [ { status: this.lastOperationError ? 'fail' : 'pass', componentId: this.adapter.componentId, componentType: 'adapter', observedValue: this.lastOperationError ? 'error' : 'ok', observedUnit: 'result of last operation', time: this.lastOperationDate ? this.lastOperationDate.toISOString() : undefined, output: this.lastOperationError ? (_a = this.lastOperationError) === null || _a === void 0 ? void 0 : _a.trace() : undefined, }, ], }; } } exports.AdapterWrapper = AdapterWrapper; //# sourceMappingURL=AdapterWrapper.js.map