UNPKG

@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
"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