@glue42/bbg-market-data
Version:
A high-level API that wraps existing Glue42 Bloomberg Bridge Market Data interop methods. The API is based on the jBloomberg open source wrapper.
226 lines • 12.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MdfBridge = void 0;
const tslib_1 = require("tslib");
const callback_registry_1 = tslib_1.__importDefault(require("callback-registry"));
const promise_wrapper_1 = require("../promise-wrapper");
const utils_1 = require("./../utils");
const ON_EVENT = "bbg-event";
/**
* MDF API facade.
*/
class MdfBridge {
constructor(interop, apiId, apiVersion, protocolMethods, logger) {
this.interop = interop;
this.apiId = apiId;
this.apiVersion = apiVersion;
this.protocolMethods = protocolMethods;
this.logger = logger;
this.registry = callback_registry_1.default();
this.registerEventsCallbackPW = new promise_wrapper_1.PromiseWrapper();
/**
* Enable multiple library instances.
*/
this.eventsCallbackMethodName = `OnBBGRequestData_${this.apiVersion}_${this.apiId}`;
this.registerEventsCallbackMethod();
}
get eventsCallbackMethod() {
return this.eventsCallbackMethodName;
}
/**
* Returns a promise which either resolves when the callback method was registered successfully or rejects when registration failed.
*/
ready() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
yield this.registerEventsCallbackPW.promise;
});
}
/**
* Subscribe to receive events for a particular request.
*/
onEvent(requestId, handler) {
if (typeof requestId != "string") {
throw new Error("requestId must be a string.");
}
if (typeof handler != "function") {
throw new Error("handler must be function.");
}
const _handler = ({ requestCorrelationId, msg }) => {
if (requestCorrelationId === requestId) {
handler(msg);
}
};
return this.registry.add(ON_EVENT, _handler);
}
/**
* Invokes the MDF API to create a non-subscription request.
*/
createRequest(args) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
yield this.invokeCreateRequest(this.protocolMethods.CreateRequest, args, `MDF API failed to create the non-subscription request with id "${args.requestCorrelationId}".`);
});
}
/**
* Invokes the MDF API to create a subscription request.
*/
createSubscriptionRequest(args) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
yield this.invokeCreateRequest(this.protocolMethods.CreateSubscriptionRequest, args, `MDF API failed to create the subscription request with id "${args.requestCorrelationId}".`);
});
}
/**
* Invokes the MDF API to cancel a request.
*/
closeRequest(requestId, reason) {
var _a, _b, _c, _d;
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const invocationArgs = {
requestCorrelationIds: [requestId],
reason,
};
const methodDef = this.protocolMethods.CancelRequests;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Attempting to invoke interop method "${methodDef.name}" with args ${JSON.stringify(invocationArgs)}`);
const defaultErrorMessage = `MDF API failed to close request with id "${requestId}".`;
try {
const { returned } = yield this.interop.invoke(methodDef, invocationArgs);
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.info(`Successfully invoked interop method "${methodDef.name}" - ${JSON.stringify(returned)}`);
const terminalResults = (_c = returned.Result) !== null && _c !== void 0 ? _c : returned.result;
const thisRequestResult = (Array.isArray(terminalResults) ? terminalResults : []).find(({ correlationId }) => correlationId === requestId);
if (thisRequestResult == null || thisRequestResult.success !== true) {
const errorMessage = typeof (thisRequestResult === null || thisRequestResult === void 0 ? void 0 : thisRequestResult.message) === "string" ? thisRequestResult.message : defaultErrorMessage;
return Promise.reject(new Error(errorMessage));
}
}
catch (error) {
const errorMessage = utils_1.extractErrorMessage(error, defaultErrorMessage);
(_d = this.logger) === null || _d === void 0 ? void 0 : _d.warn(`Failed to invoke interop method "${methodDef.name}" - ${errorMessage}`);
return Promise.reject(new Error(errorMessage));
}
});
}
/**
* Invokes the MDF API to close a session.
*/
closeSession(sessionName) {
var _a, _b, _c, _d;
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const invocationArgs = {
sessionName,
};
const methodDef = this.protocolMethods.CloseSession;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Attempting to invoke interop method "${methodDef.name}" with args ${JSON.stringify(invocationArgs)}`);
try {
const { returned } = yield this.interop.invoke(methodDef, invocationArgs);
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.info(`Successfully invoked interop method ${methodDef.name} - ${JSON.stringify(returned)}`);
const terminalResult = (_c = returned.Result) !== null && _c !== void 0 ? _c : returned.result;
if (terminalResult == null || terminalResult.success === false) {
const errorMessage = typeof (terminalResult === null || terminalResult === void 0 ? void 0 : terminalResult.message) === "string"
? terminalResult.message
: `MDF API failed to close session "${sessionName}".`;
return Promise.reject(new Error(errorMessage));
}
}
catch (error) {
const errorMessage = utils_1.extractErrorMessage(error);
(_d = this.logger) === null || _d === void 0 ? void 0 : _d.warn(`Failed to invoke interop method "${methodDef.name}" - ${errorMessage}`);
return Promise.reject(new Error(errorMessage));
}
});
}
/**
* Subscribes to MDF API Interop stream that streams Bloomberg Heartbeat.
*/
subscribeForConnectionStatus(retryPeriodMsecs, subscriber) {
var _a, _b, _c;
return tslib_1.__awaiter(this, void 0, void 0, function* () {
// TODO: Implement resubscription logic.
const methodDef = this.protocolMethods.SubscribeStatus;
try {
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Attempting to subscribe to "${methodDef.name}".`);
const subscription = yield this.interop.subscribe(methodDef, {
arguments: { settings: { retryPeriodMsecs } },
});
const handleData = ({ SubscriptionStatus }) => subscriber.onData(SubscriptionStatus);
const handleError = () => subscriber.onError();
const handleClose = () => subscriber.onClose();
subscription.onData(({ data }) => {
var _a;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.trace(`Stream "${methodDef.name}" subscription data - ${JSON.stringify(data)}`);
handleData(data);
});
subscription.onFailed((error) => {
var _a;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.warn(`Stream "${methodDef.name}" subscription failed - ${JSON.stringify(error)}`);
handleError();
});
subscription.onClosed((info) => {
var _a;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Stream "${methodDef.name}" subscription closed - ${JSON.stringify(info)}`);
handleClose();
});
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.info(`Successfully subscribed to "${methodDef.name}".`);
}
catch (error) {
const errorMsg = utils_1.extractErrorMessage(error);
(_c = this.logger) === null || _c === void 0 ? void 0 : _c.error(`Failed to subscribe to "${methodDef.name}" - ${errorMsg}`);
subscriber.onError();
}
});
}
registerEventsCallbackMethod() {
var _a, _b, _c;
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const invocationHandler = (data) => {
this.registry.execute(ON_EVENT, data);
};
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Attempting to register events callback "${this.eventsCallbackMethodName}".`);
try {
yield this.interop.register(this.eventsCallbackMethodName, invocationHandler);
this.registerEventsCallbackPW.resolve();
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.info(`Successfully registered events callback "${this.eventsCallbackMethodName}".`);
}
catch (error) {
const errorMessage = utils_1.extractErrorMessage(error);
const kindMessage = `Failed to register events callback "${this.eventsCallbackMethodName}" - ${errorMessage}`;
(_c = this.logger) === null || _c === void 0 ? void 0 : _c.error(kindMessage);
this.registerEventsCallbackPW.reject(new Error(kindMessage));
}
});
}
invokeCreateRequest(methodDef, args, defaultErrorMessage) {
var _a, _b, _c, _d;
return tslib_1.__awaiter(this, void 0, void 0, function* () {
yield this.ready();
const invocationArgs = Object.assign(Object.assign({}, args), { callbackMethod: this.eventsCallbackMethodName });
const invokeOptions = {
methodResponseTimeoutMs: 180 * 1000,
};
const argsToLog = {
settings: args.settings,
requestCorrelationId: args.requestCorrelationId,
operation: args.operation,
operationArgs: args.operationArgs,
subscriptions: args.subscriptions,
};
delete argsToLog.settings.sessionIdentityOptions;
delete argsToLog.settings.sessionOptions;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Attempting to invoke interop method "${methodDef.name}" with args ${JSON.stringify(argsToLog)}`);
try {
const { returned } = yield this.interop.invoke(methodDef, invocationArgs, "best", invokeOptions);
(_b = this.logger) === null || _b === void 0 ? void 0 : _b.info(`Successfully invoked interop method "${methodDef.name}" - ${JSON.stringify(returned)}`);
const terminalResult = (_c = returned.Result) !== null && _c !== void 0 ? _c : returned.result;
if (terminalResult == null || terminalResult.success === false) {
const errorMessage = typeof (terminalResult === null || terminalResult === void 0 ? void 0 : terminalResult.message) === "string" ? terminalResult.message : defaultErrorMessage;
return Promise.reject(new Error(errorMessage));
}
}
catch (error) {
const errorMessage = utils_1.extractErrorMessage(error, defaultErrorMessage);
(_d = this.logger) === null || _d === void 0 ? void 0 : _d.warn(`Failed to invoke interop method "${methodDef.name}" - ${errorMessage}`);
return Promise.reject(new Error(errorMessage));
}
});
}
}
exports.MdfBridge = MdfBridge;
//# sourceMappingURL=mdf-bridge.js.map