@mdf.js/openc2-core
Version:
MMS - API Core - OpenC2
141 lines • 5.52 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.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");
const uuid_1 = require("uuid");
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();
};
/** Perform the publication of the message in the underlayer transport system */
this.publish = async (message) => {
return this.wrappedOperation(this.publishOriginal, [message], 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.publishOriginal = this.adapter.publish;
this.adapter.publish = this.publish;
this.on('newListener', (event, listener) => {
if ((0, uuid_1.validate)(event)) {
this.adapter.on(event, listener);
}
});
this.on('removeListener', (event, listener) => {
if ((0, uuid_1.validate)(event)) {
this.adapter.off(event, listener);
}
});
}
/** 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.publish || typeof this.adapter.publish !== 'function') {
throw new crash_1.Crash(`Adapter ${this.adapter.name} does not implement the publish 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() {
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 ? this.lastOperationError.trace() : undefined,
},
],
};
}
}
exports.AdapterWrapper = AdapterWrapper;
//# sourceMappingURL=AdapterWrapper.js.map