@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.
202 lines • 8.93 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NonSubscriptionRequestImpl = void 0;
const tslib_1 = require("tslib");
const promise_wrapper_1 = require("../promise-wrapper");
const request_status_1 = require("../request-status");
const helpers_1 = require("./helpers");
const event_types_1 = require("./event-types");
const utils_1 = require("./../utils");
const base_request_1 = require("./base-request");
const message_handlers_1 = require("./message-handlers");
const DATA_EVENT = "data-event";
const ERROR_EVENT = "error-event";
const STATUS_EVENT = "status-event";
/**
* Represents the lifecycle of a non-subscription request.
*/
class NonSubscriptionRequestImpl extends base_request_1.BaseRequest {
constructor(sessionManager, config, operationArgs, handlers) {
super(sessionManager, config, operationArgs);
this.sessionManager = sessionManager;
this.config = config;
this.operationArgs = operationArgs;
this.handlers = handlers;
this.aggregatedResponseData = [];
/**
* Controlled by "OpenRequestOptions".
* See https://docs.glue42.com/connectors/bloomberg-connector/market-data/javascript/index.html#handling_requests-opening_a_request.
*/
this.shouldAggregateResponse = true;
super.onRequestStatusChanged(this.handleRequestStatusChanged.bind(this));
if (typeof this.handlers.partialResponseData != "function" ||
typeof this.handlers.responseData != "function" ||
typeof this.handlers.responseError != "function") {
throw new Error("All handlers must be functions.");
}
}
/**
* Public api.
*/
get api() {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const that = this;
return {
/**
* Dynamically set when the request is (re)opened.
*/
get id() {
return that.requestId;
},
get settings() {
return {
operation: that.config.operation,
service: that.config.service,
aggregateResponse: that.shouldAggregateResponse,
operationArgs: that.operationArgs,
};
},
get status() {
return that._status;
},
open: this.open.bind(that),
close: that.closeRequest.bind(that),
onData: (callback) => {
return that.registry.add(DATA_EVENT, callback);
},
onError: (callback) => {
return that.registry.add(ERROR_EVENT, callback);
},
onEvent: that.onEvent.bind(that),
onStatus: (callback) => {
utils_1.callSafe(callback, that._status);
return that.registry.add(STATUS_EVENT, callback);
},
};
}
open(options) {
const _super = Object.create(null, {
openRequest: { get: () => super.openRequest }
});
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (helpers_1.isPending(this._status)) {
return Promise.reject(new Error("Request can be opened/reopened if its status is Created, Failed, Closed or Completed. Either close the request or wait it to complete."));
}
this.reset();
const _a = options !== null && options !== void 0 ? options : {}, { aggregateResponse } = _a, otherOptions = tslib_1.__rest(_a, ["aggregateResponse"]);
this.shouldAggregateResponse = aggregateResponse === false ? false : true;
this.aggregatedResponsePW = new promise_wrapper_1.PromiseWrapper();
_super.openRequest.call(this, Object.assign(Object.assign({}, otherOptions), { messageProcessor: this.messageProcessor.bind(this) })).catch(() => {
// We handle the error via the status event.
});
return this.aggregatedResponsePW.promise;
});
}
handleRequestStatusChanged(event) {
var _a, _b, _c;
this.registry.execute(STATUS_EVENT, event.status);
if (event.status === request_status_1.RequestStatus.Active) {
if (this.shouldAggregateResponse === false) {
(_a = this.aggregatedResponsePW) === null || _a === void 0 ? void 0 : _a.resolve(undefined);
}
return;
}
if (event.status === request_status_1.RequestStatus.Closed || event.status === request_status_1.RequestStatus.Completed) {
return (_b = this.aggregatedResponsePW) === null || _b === void 0 ? void 0 : _b.resolve(this.aggregatedResponseData);
}
if (event.status === request_status_1.RequestStatus.Failed) {
this.registry.execute(ERROR_EVENT, event.error);
return (_c = this.aggregatedResponsePW) === null || _c === void 0 ? void 0 : _c.reject(event.error);
}
}
messageProcessor(eventMessage) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
// Check if the event is a known error type and handle it accordingly.
const error = [
message_handlers_1.sessionStartUpFailureHandler(eventMessage),
message_handlers_1.sessionTerminatedHandler(eventMessage),
message_handlers_1.serviceOpenedFailureHandler(eventMessage),
message_handlers_1.requestFailureHandler(eventMessage),
].find(({ match }) => match);
if (error) {
return { action: "fail", error: error.data };
}
if (helpers_1.isEventOfType(eventMessage, event_types_1.EventTypes.Response)) {
return this.processResponseBBGEvent(eventMessage);
}
if (helpers_1.isEventOfType(eventMessage, event_types_1.EventTypes.PartialResponse)) {
this.processPartialResponseBBGEvent(eventMessage);
}
return Promise.resolve({ action: 'continue' });
});
}
processPartialResponseBBGEvent(eventMessage) {
var _a;
try {
const { data, match } = this.handlers.partialResponseData(eventMessage);
if (!match) {
return;
}
if (this.shouldAggregateResponse) {
(_a = this.aggregatedResponseData) === null || _a === void 0 ? void 0 : _a.push(data);
}
this.raiseResponseData({
data: data,
isLast: false,
});
}
catch (_b) {
this.raiseResponseData({
data: undefined,
isLast: false,
});
}
}
processResponseBBGEvent(eventMessage) {
var _a;
try {
// Check if "RESPONSE" contains data.
const responseDataResult = this.handlers.responseData(eventMessage);
if (responseDataResult.match) {
if (this.shouldAggregateResponse) {
(_a = this.aggregatedResponseData) === null || _a === void 0 ? void 0 : _a.push(responseDataResult.data);
}
this.raiseResponseData({
data: responseDataResult.data,
isLast: true,
});
return { action: 'complete' };
}
// Check if "RESPONSE" contains error.
const responseErrorResult = this.handlers.responseError(eventMessage);
if (responseErrorResult.match) {
return {
action: 'fail',
error: responseErrorResult.data
};
}
return {
action: 'fail',
error: new Error(`Received a ${event_types_1.EventTypes.Response} event but neither data nor error messages can be matched. Check handlers.`)
};
}
catch (error) {
const errorMsg = utils_1.extractErrorMessage(error);
return {
action: 'fail',
error: new Error(`Processing ${event_types_1.EventTypes.Response} event message errored with "${errorMsg}"`)
};
}
}
raiseResponseData(responseData) {
this.registry.execute(DATA_EVENT, responseData);
}
reset() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
this.shouldAggregateResponse = true;
this.aggregatedResponseData = [];
});
}
}
exports.NonSubscriptionRequestImpl = NonSubscriptionRequestImpl;
//# sourceMappingURL=non-subscription-request.js.map