UNPKG

barracuda-client-api

Version:

API Client to connect to Barracuda Enterprise Service Bus

1,084 lines 73.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BarracudaPublisherCommandType = exports.BarracudaClient = exports.DefaultQueryTopValue = exports.BarracudaBridgeAggregateCommands = exports.BarracudaBridgeReadQueryCommands = exports.BarracudaCommand = void 0; const IBarracudaClient_1 = require("./IBarracudaClient"); const index_1 = require("./logging/index"); const connectionProps_1 = require("./helpers/connectionProps"); const BarracudaBrowserWebSocket_1 = require("./BarracudaBrowserWebSocket"); const index_2 = require("./error/index"); const cross_fetch_1 = require("cross-fetch"); const BarracudaClientBuildDetail_1 = __importDefault(require("./BarracudaClientBuildDetail")); // tslint:disable-next-line:no-require-imports const ws_1 = __importDefault(require("ws")); const uuid_1 = require("./react-native/uuid"); var BarracudaCommand; (function (BarracudaCommand) { BarracudaCommand["close"] = "close"; })(BarracudaCommand = exports.BarracudaCommand || (exports.BarracudaCommand = {})); var BarracudaBridgeReadQueryCommands; (function (BarracudaBridgeReadQueryCommands) { BarracudaBridgeReadQueryCommands["aggregate"] = "aggregate"; BarracudaBridgeReadQueryCommands["diffSubscribe"] = "diffSubscribe"; BarracudaBridgeReadQueryCommands["snapshot"] = "snapshot"; BarracudaBridgeReadQueryCommands["snapshotAndDiffSubscribe"] = "snapshotAndDiffSubscribe"; BarracudaBridgeReadQueryCommands["snapshotAndSubscribe"] = "snapshotAndSubscribe"; BarracudaBridgeReadQueryCommands["subscribe"] = "subscribe"; })(BarracudaBridgeReadQueryCommands = exports.BarracudaBridgeReadQueryCommands || (exports.BarracudaBridgeReadQueryCommands = {})); var BarracudaBridgeQueryCommands; (function (BarracudaBridgeQueryCommands) { BarracudaBridgeQueryCommands["unsubscribe"] = "unsubscribe"; })(BarracudaBridgeQueryCommands || (BarracudaBridgeQueryCommands = {})); var BarracudaBridgeAggregateCommands; (function (BarracudaBridgeAggregateCommands) { BarracudaBridgeAggregateCommands["unsubscribe"] = "unsubscribe"; })(BarracudaBridgeAggregateCommands = exports.BarracudaBridgeAggregateCommands || (exports.BarracudaBridgeAggregateCommands = {})); function createWebSocket(ep) { if (typeof window === "undefined" || typeof ws_1.default === "undefined") { return new ws_1.default(ep); } else { return new BarracudaBrowserWebSocket_1.BarracudaBrowserWebSocket(ep); } } exports.DefaultQueryTopValue = 50000; function toBoolean(v) { switch (typeof v) { case "boolean": return v; case "string": switch (v.toLocaleLowerCase()) { case "true": case "1": case "on": case "yes": return true; default: return false; } default: return !!v; } } class BarracudaClient { constructor(defaultProps) { this.skipReconnecting = false; this._requests = {}; this._staleNotice = {}; this._defaultRestPublishEndPoint = `https://barracuda-rest-dev.citadelgroup.com`; this._connectedAckAtLeastOnce = false; this._reconnectCounter = 0; this._subscriptionHistory = []; this._lastConnectionProps = this; this._connectionCounter = 0; this._reconnect = false; this._loglevel = index_1.loglevels.info; this.connectionState = IBarracudaClient_1.BarracudaConnectionStatus.unknown; this._subscriptions = {}; this._uid = uuid_1.uuid4(); this.setProps(defaultProps); } static get Build() { return BarracudaClientBuildDetail_1.default; } get appName() { return this._appName; } get appVersion() { return this._appVersion; } get lastPong() { return this._lastPong; } get serverClientId() { var _a; return (_a = this.connectionAckMessage) === null || _a === void 0 ? void 0 : _a.clientId; } get serverDebug() { return !!this._serverDebug; } get restPublishEndPoint() { return this._defaultRestPublishEndPoint; } get gaToken() { return this._gaToken; } get serviceHost() { var _a; return (_a = this.connectionAckMessage) === null || _a === void 0 ? void 0 : _a.host; } get reconnect() { return this._reconnect; } set reconnect(value) { this._reconnect = value; } get onConnectionError() { return this._onConnectionError; } set onConnectionError(value) { this._onConnectionError = value; } get onError() { return this._onError; } set onError(value) { this._onError = value; } get onConnectionStateChange() { return this._onConnectionStateChange; } set onConnectionStateChange(value) { this._onConnectionStateChange = value; } get onSubscriptionUpdate() { return this._onSubscriptionUpdate; } set onSubscriptionUpdate(value) { this._onSubscriptionUpdate = value; } get loglevel() { return this._loglevel; } set loglevel(value) { this._loglevel = value; } get uid() { return this._uid; } get logUid() { var _a; return ((_a = this._logUid) !== null && _a !== void 0 ? _a : (this._logUid = this.uid.substr(this.uid.length - 5))); } get connectionAckMessage() { return this._connectionAckMessage; } get lastConnectionProps() { return this._lastConnectionProps; } get defaultConnectionProps() { return { ...BarracudaClient.getConnectionProps(this) }; } async connect(overrideProps) { const connectionProps = BarracudaClient.getConnectionProps(this, overrideProps); if (index_1.isDebug(this.ll)) { index_1.logDebug(`${this.bcLog(this.lastConnectionProps)}`, { defaultConnectionProps: this.defaultConnectionProps, overrideProps, connectionProps, }); } if (!connectionProps.endpoint) { throw new index_2.BarracudaError(`${this.bcLog(connectionProps)} Can't connect to an empty endpoint.`, { connectionProps, }); } switch (this.connectionState) { case IBarracudaClient_1.BarracudaConnectionStatus.connected: case IBarracudaClient_1.BarracudaConnectionStatus.connectedAck: if (index_1.isWarn(this.ll)) { index_1.logWarn("Already connected. Cannot reconnect again without closing the connection first.", { activeSubscription: Object.values(this._subscriptions).length, activeRequests: Object.values(this._requests).filter((r) => !r.responseProcessed).length, }); } return Promise.resolve(this); case IBarracudaClient_1.BarracudaConnectionStatus.connecting: index_1.logWarn("Actively connecting. Cannot connect again without closing the connection first.", { activeSubscription: Object.values(this._subscriptions).length, activeRequests: Object.values(this._requests).filter((r) => !r.responseProcessed).length, }); return Promise.resolve(this); case IBarracudaClient_1.BarracudaConnectionStatus.reconnecting: case IBarracudaClient_1.BarracudaConnectionStatus.disconnected: case IBarracudaClient_1.BarracudaConnectionStatus.connectionError: case IBarracudaClient_1.BarracudaConnectionStatus.unknown: this.triggerOnConnectionStateChange(IBarracudaClient_1.BarracudaConnectionStatus.connecting, connectionProps); break; case IBarracudaClient_1.BarracudaConnectionStatus.closing: index_1.logWarn("Closing, wait until closed.", { activeSubscription: !this._subscriptions ? 0 : Object.values(this._subscriptions).length, activeRequests: !this._requests ? 0 : Object.values(this._requests).filter((r) => !(r === null || r === void 0 ? void 0 : r.responseProcessed)) .length, }); return Promise.resolve(this); } return new Promise(async (connectionPendingResolve, rejectPendingConnection) => { try { this._lastConnectionProps = connectionProps; this.clearConnectionState(); const endPointUrlString = connectionProps_1.makeConnectionQuery(connectionProps, this.serverDebug); if (index_1.isDebug(this.ll)) { index_1.logDebug(`${this.bcLog(connectionProps)} connecting Barracuda Client`, { connectionProps, endPointUrl: endPointUrlString, }); } else { if (index_1.isInfo(this.ll)) { index_1.logInfo(`${this.bcLog(connectionProps)} connecting Barracuda Client`); } } this.ws = createWebSocket(endPointUrlString); this.ws.once("message", (ack) => { if (index_1.isDebug(this.ll)) { index_1.logDebug(`${this.bcLog(connectionProps)} WS first MSG ACK`, { ack, connectionProps, }); } try { const ackMsg = JSON.parse(ack); this._connectionAckMessage = ackMsg; if (ackMsg.status === "Connected") { this._connectedAckAtLeastOnce = true; this._connectionCounter++; this.triggerOnConnectionStateChange(IBarracudaClient_1.BarracudaConnectionStatus.connectedAck, connectionProps); this.startSubscriptionListener(connectionProps); try { connectionPendingResolve(this); } catch (e) { if (index_1.isWarn(this.ll)) { index_1.logWarn(`${this.bcLog(connectionProps)} Unhandled exception in BCjs consumer. BCjs consumer should implement .catch and ensure it doesn't throw exceptions`, e); } } } else { if (index_1.shouldLogErrors(this.ll)) { index_1.logError(`${this.bcLog(connectionProps)} ackMessage contained status other than 'Connected' ${ackMsg.status}`, ackMsg); } } } catch (error) { const err = new index_2.BarracudaError("Error while parsing ACK message", { connectionProps, originalError: error, }); if (connectionProps === null || connectionProps === void 0 ? void 0 : connectionProps.onConnectionError) { this.callHandlerSafely(connectionProps, () => { var _a; return (_a = connectionProps === null || connectionProps === void 0 ? void 0 : connectionProps.onConnectionError) === null || _a === void 0 ? void 0 : _a.call(this, err, this); }, { error: err }, "onConnectionError"); } } }); this.ws.once("open", () => { if (index_1.isDebug(this.ll)) { index_1.logDebug(`${this.bcLog(connectionProps)} WS connected`, connectionProps); } this._reconnectCounter = 0; this.triggerOnConnectionStateChange(IBarracudaClient_1.BarracudaConnectionStatus.connected, connectionProps); }); this.ws.once("close", (code, reason) => { this.triggerOnConnectionStateChange(IBarracudaClient_1.BarracudaConnectionStatus.disconnected, connectionProps); const closeData = { code, reason }; if (index_1.isInfo(this.ll)) { index_1.logInfo(`${this.bcLog(connectionProps)} closed ==>`, closeData); } if (this._connectedAckAtLeastOnce && toBoolean(connectionProps === null || connectionProps === void 0 ? void 0 : connectionProps.reconnect)) { const delay = 1000 * ++this._reconnectCounter + Math.random() * 1000; this.scheduleReconnect(connectionProps, delay); } else { if (rejectPendingConnection) { try { rejectPendingConnection(new index_2.BarracudaError("[closed]", { ...closeData, connectionProps, msg: this.connectionAckMessage, connectedAtLeastOnce: this._connectedAckAtLeastOnce, })); } catch (e) { // prevent bubbling up unhandled exceptions in reject clause. Consumer should implement .catch on promise if (index_1.isWarn(this.ll)) { index_1.logWarn(`Unhandled exception in BCjs consumer. BCjs consumer should implement .catch and ensure it doesn't throw/bubble exceptions`, e); } } } } }); this.ws.on("error", (error) => { if (this.connectionState === IBarracudaClient_1.BarracudaConnectionStatus.closing) { if (index_1.isWarn(this.ll)) { index_1.logWarn(`${this.bcLog(connectionProps)} ignoring processing errors while closing ==>`, { error }); } return; } this.triggerOnConnectionStateChange(IBarracudaClient_1.BarracudaConnectionStatus.connectionError, connectionProps); if (index_1.shouldLogErrors(this.ll)) { index_1.logError(`${this.bcLog(connectionProps)} error ==>`, { connectionState: this.connectionState, error, }); } if (connectionProps === null || connectionProps === void 0 ? void 0 : connectionProps.onConnectionError) { this.callHandlerSafely(connectionProps, () => { var _a; return (_a = connectionProps === null || connectionProps === void 0 ? void 0 : connectionProps.onConnectionError) === null || _a === void 0 ? void 0 : _a.call(this, error, this); }, { error, msg: this.connectionAckMessage, }, "onConnectionError"); } }); } catch (error) { this.triggerOnConnectionStateChange(IBarracudaClient_1.BarracudaConnectionStatus.connectionError, connectionProps); try { if (rejectPendingConnection) { rejectPendingConnection(error); } } catch (e) { if (index_1.isWarn(this.ll)) { index_1.logWarn(`Unhandled exception in BCjs consumer. BCjs consumer should implement .catch and ensure it doesn't throw exceptions`, e); } } } }); } _emulateServerDisconnect() { var _a; const message = `${this.bcLog(this.lastConnectionProps)} Emulating server disconnect`; const serverCloseMessage = { messageType: "IBarracudaBridgeRequest", requestId: uuid_1.uuid4(), command: BarracudaCommand.close, messsage: message, }; if (index_1.isInfo(this.ll)) { index_1.logInfo(message, serverCloseMessage); } (_a = this.ws) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(serverCloseMessage)); } close() { var _a; const props = this.lastConnectionProps; const reason = `[${this.logUid}] [sUid:${this.serverClientId}] connection gracefully closed by API consumer`; const code = 1000; switch (this.connectionState) { case IBarracudaClient_1.BarracudaConnectionStatus.connected: case IBarracudaClient_1.BarracudaConnectionStatus.connectedAck: case IBarracudaClient_1.BarracudaConnectionStatus.connecting: case IBarracudaClient_1.BarracudaConnectionStatus.connectionError: case IBarracudaClient_1.BarracudaConnectionStatus.reconnecting: if (index_1.isInfo(this.ll)) { index_1.logInfo(`${this.bcLog(props)} closing connection`, { connectionState: this.connectionState, code, reason, }); } break; case IBarracudaClient_1.BarracudaConnectionStatus.unknown: case IBarracudaClient_1.BarracudaConnectionStatus.disconnected: case IBarracudaClient_1.BarracudaConnectionStatus.closing: if (index_1.isWarn(this.ll)) { index_1.logWarn(`${this.bcLog(props)} Can not close this client, it is already [${this.connectionState}]`); } return; default: break; } this.triggerOnConnectionStateChange(IBarracudaClient_1.BarracudaConnectionStatus.closing, props); this.skipReconnecting = true; if (this._staleTriggerTimer) { clearTimeout(this._staleTriggerTimer); this._staleTimeOutMs = 0; } (_a = this.ws) === null || _a === void 0 ? void 0 : _a.close(code, reason); } get connectionCounter() { return this._connectionCounter; } bcLog(props) { if (this.serverClientId) { return `[${props.endpoint}] [${this.logUid}] [sUid:${this.serverClientId}]`; } else { return `[${props.endpoint}] [${this.logUid}]`; } } disconnect() { return new Promise((resolve, reject) => { var _a; (_a = this.ws) === null || _a === void 0 ? void 0 : _a.once("close", (code, reason) => { const closeConfirmation = { code, reason }; resolve(closeConfirmation); }); this.close(); }); } get subscriptions() { return Object.values(this._subscriptions).map((s) => BarracudaClient.shareSubscriptionDetails(s)); } get previousSessionSubscriptions() { if (this._subscriptionHistory.length === 0) { return []; } const lastSubscriptions = this._subscriptionHistory[this._subscriptionHistory.length - 1]; return Object.values(lastSubscriptions).map((s) => BarracudaClient.shareSubscriptionDetails(s)); } snapshot(instance, topic, message, filter, top = exports.DefaultQueryTopValue, project, sort, heartbeatPeriod = 0) { return this.subscribeQuery(BarracudaBridgeReadQueryCommands.snapshot, { instance, topic, filter, top, onMessage: (batch, subscriptionId) => { if (message) { message({ subscriptionId, messages: batch, }); } }, project, sort, heartbeatPeriod, }).then((sub) => { return sub.subscriptionId; }); } snapshotAndSubscribe(instance, topic, message, filter, top = exports.DefaultQueryTopValue, project, sort, heartbeatPeriod = 0) { return this.subscribeQuery(BarracudaBridgeReadQueryCommands.snapshotAndSubscribe, { instance, topic, filter, top, onMessage: (batch, subscriptionId) => { if (message) { message({ subscriptionId, messages: batch, }); } }, project, sort, heartbeatPeriod, }).then((sub) => { return sub.subscriptionId; }); } snapshotAndDiffSubscribe(instance, topic, message, filter, top = exports.DefaultQueryTopValue, project, sort, heartbeatPeriod = 0) { return this.subscribeQuery(BarracudaBridgeReadQueryCommands.snapshotAndDiffSubscribe, { instance, topic, filter, top, onMessage: (batch, subscriptionId) => { if (message) { message({ subscriptionId, messages: batch, }); } }, project, sort, heartbeatPeriod, }).then((sub) => { return sub.subscriptionId; }); } subscribeDiff(instance, topic, message, filter, top = exports.DefaultQueryTopValue, project, sort, heartbeatPeriod = 0) { return this.subscribeQuery(BarracudaBridgeReadQueryCommands.diffSubscribe, { instance, topic, filter, top, onMessage: (batch, subscriptionId) => { if (message) { message({ subscriptionId, messages: batch, }); } }, project, sort, heartbeatPeriod, }).then((sub) => { return sub.subscriptionId; }); } subscribe(instance, topic, message, filter, top = exports.DefaultQueryTopValue, project, sort, heartbeatPeriod = 0) { return this.subscribeQuery(BarracudaBridgeReadQueryCommands.subscribe, { instance, topic, filter, top, onMessage: (batch, subscriptionId) => { if (message) { message({ subscriptionId, messages: batch, }); } }, project, sort, heartbeatPeriod, }).then((sub) => { return sub.subscriptionId; }); } async unsubscribe(subscriptionId) { const props = this.lastConnectionProps; const subDetails = this._subscriptions[subscriptionId]; if (!subDetails) { throw new Error(`Unable to find internal details for [subId: ${subscriptionId}]. Please confirm subscriptionId veracity`); } if ((subDetails === null || subDetails === void 0 ? void 0 : subDetails.unsubscribed) || (subDetails === null || subDetails === void 0 ? void 0 : subDetails.lastServerStatus) === IBarracudaClient_1.BarracudaBridgeSubscriptionStatus.unsubscribed) { index_1.logWarn(`Subscription ${subscriptionId} is already unsubscribed`, BarracudaClient.shareSubscriptionDetails(subDetails)); return; } if (index_1.isInfo(this.ll)) { index_1.logInfo(`Unsubscribing ${subscriptionId}`); } subDetails.onMessage = undefined; this._subscriptions[subscriptionId].pendingUnsubscribe = true; const unsubscribeMsg = { requestId: uuid_1.uuid4(), messageType: "IBarracudaBridgeSubscriptionRequest", command: BarracudaBridgeQueryCommands.unsubscribe, heartbeatPeriod: 0, subscriptionId, }; const response = await this.sendRequest(unsubscribeMsg); if (props === null || props === void 0 ? void 0 : props.onSubscriptionUpdate) { subDetails.lastServerStatus = IBarracudaClient_1.BarracudaBridgeSubscriptionStatus.unsubscribeRequestAcknowledged; subDetails.lastServerStatusDt = new Date(); this.safeTriggerOnSubscriptionChanged(BarracudaClient.shareSubscriptionDetails(subDetails), props); } if (response.success) { subDetails.unsubscribed = true; } } async aggregate(topic, pipeline, instance, maxTimeMS = 5 * 1000, batchSize = 100) { return new Promise(async (resolve, reject) => { let results = []; let subId; const onSubscriptionResponse = (subResponse) => { subResponse.messages.forEach((m) => { switch (m.command) { case IBarracudaClient_1.BarracudaBridgeResponseCommandTypes.sow: results.push(m.data); break; case IBarracudaClient_1.BarracudaBridgeResponseCommandTypes.publish: results.push(m.data); break; case IBarracudaClient_1.BarracudaBridgeResponseCommandTypes.groupEnd: resolve(results); break; } }); }; if (index_1.isDebug(this.ll)) { index_1.logDebug(`${this.bcLog(this.lastConnectionProps)} aggregate`, { topic, instance, pipeline, maxTimeMS, batchSize, }); } const query = { instance, topic, batchSize, pipeline, batchPeriod: maxTimeMS, onMessage: onSubscriptionResponse, }; try { await this.requestQueryCommand(BarracudaBridgeReadQueryCommands.aggregate, query, undefined); } catch (e) { reject(e); } }); } async subscribeQuery(commandType, queryDetails) { var _a; let subId; const onSubscriptionResponse = (subResponse) => { var _a; (_a = queryDetails.onMessage) === null || _a === void 0 ? void 0 : _a.call(this, subResponse.messages, subId); }; if (index_1.isDebug(this.ll)) { index_1.logDebug(`${this.bcLog(this.lastConnectionProps)} subscribeQuery`, queryDetails); } const query = { ...queryDetails, project: queryDetails.project, orderBy: queryDetails.sort, top: (_a = queryDetails === null || queryDetails === void 0 ? void 0 : queryDetails.top) !== null && _a !== void 0 ? _a : exports.DefaultQueryTopValue, onMessage: onSubscriptionResponse, }; subId = await this.requestQueryCommand(commandType, query, queryDetails); return { subscriptionId: subId, unsubscribe: () => this.unsubscribe(subId), }; } getTopicInfo(topic, infoType, instance) { if (index_1.isVerbose(this.ll)) { index_1.logVerbose("getTopicInfo", { topic, infoType, instance }, this.instance); } const database = instance !== null && instance !== void 0 ? instance : this.instance; if (!database) { throw new Error("Instance is required. please provide either a default instance in the constructor, or pass an override instance in the parameter"); } const requestBase = BarracudaClient.createRequest("IBarracudaBridgeCommandRequest"); let command; let getResult; switch (infoType) { case IBarracudaClient_1.BarracudaTopicInfoType.barracuda_keys: command = { listIndexes: topic, }; getResult = (response) => { var _a, _b; const indices = (_a = response === null || response === void 0 ? void 0 : response.cursor) === null || _a === void 0 ? void 0 : _a.firstBatch; return { result: (_b = indices === null || indices === void 0 ? void 0 : indices.find((i) => "_" + IBarracudaClient_1.BarracudaTopicInfoType.barracuda_keys === (i === null || i === void 0 ? void 0 : i.name))) === null || _b === void 0 ? void 0 : _b.key, }; }; break; case IBarracudaClient_1.BarracudaTopicInfoType.documentsCount: command = { count: topic, }; getResult = (response) => ({ result: response === null || response === void 0 ? void 0 : response.n }); break; case IBarracudaClient_1.BarracudaTopicInfoType.size: command = { dataSize: `${instance}.${topic}`, }; getResult = (response) => ({ result: response === null || response === void 0 ? void 0 : response.size }); break; default: throw new index_2.BarracudaError(`Unidentified infoType: ${infoType}`, { topic, instance, }); } const req = { ...requestBase, database, command: { ...command, }, }; if (index_1.isInfo(this.ll)) { index_1.logInfo(`Requesting TopicInfo ${topic}`, index_1.isDebug(this.ll) ? req : undefined); } return this.sendRequest(req).then((r) => { if (this.throwIfMissingField(r, "response")) { return; } return getResult(r.response); }); } setOnStaleSubscriptionAlert(onStale, seconds = 60) { this._staleTimeOutMs = seconds * 1000; this._onStale = onStale; if (this._staleTimeOutMs && this._onStale) { if (!this._staleTriggerTimer) { clearTimeout(this._staleTriggerTimer); } setTimeout(() => this.detectStaleSubscriptions(), this.staleTimeOutMs); } } get endpoint() { return this._endpoint; } set endpoint(value) { this._endpoint = value; } get instance() { return this._defaultInstance; } set instance(value) { this._defaultInstance = value; } get staleTimeOutMs() { var _a; return (_a = this._staleTimeOutMs) !== null && _a !== void 0 ? _a : 0; } get ll() { return this._loglevel; } static getConnectionProps(defaultProps, overrideProps) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o; return { endpoint: (_a = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.endpoint) !== null && _a !== void 0 ? _a : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.endpoint, onConnectionError: (_b = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.onConnectionError) !== null && _b !== void 0 ? _b : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.onConnectionError, onConnectionStateChange: (_c = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.onConnectionStateChange) !== null && _c !== void 0 ? _c : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.onConnectionStateChange, onError: (_d = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.onError) !== null && _d !== void 0 ? _d : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.onError, reconnect: (_e = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.reconnect) !== null && _e !== void 0 ? _e : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.reconnect, gaToken: (_f = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.gaToken) !== null && _f !== void 0 ? _f : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.gaToken, instance: (_g = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.instance) !== null && _g !== void 0 ? _g : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.instance, onSubscriptionUpdate: (_h = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.onSubscriptionUpdate) !== null && _h !== void 0 ? _h : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.onSubscriptionUpdate, loglevel: (_j = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.loglevel) !== null && _j !== void 0 ? _j : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.loglevel, publishRestEndPoint: (_k = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.publishRestEndPoint) !== null && _k !== void 0 ? _k : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.publishRestEndPoint, serverDebug: (_l = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.serverDebug) !== null && _l !== void 0 ? _l : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.serverDebug, appName: (_m = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.appName) !== null && _m !== void 0 ? _m : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.appName, appVersion: (_o = overrideProps === null || overrideProps === void 0 ? void 0 : overrideProps.appVersion) !== null && _o !== void 0 ? _o : defaultProps === null || defaultProps === void 0 ? void 0 : defaultProps.appVersion, }; } static createRequest(messageType) { return this.createBBMsgType(messageType, { requestId: uuid_1.uuid4(), }); } static createBBMsgType(messageType, bMsg) { return { messageType, ...bMsg, }; } static createRequestSubscription(commandType, instance, topic, queryDetails) { var _a; let filter; if (typeof queryDetails.filter === "object") { filter = JSON.stringify(queryDetails.filter); } else { filter = queryDetails.filter; } // let pipeline: string | undefined; // if (Array.isArray(queryDetails.pipeline)) { // pipeline = JSON.stringify(queryDetails.pipeline); // } else { // pipeline = queryDetails.pipeline; // } return { ...BarracudaClient.createRequest("IBarracudaBridgeSubscriptionRequest"), command: commandType, database: instance, collection: topic, filter, pipeline: queryDetails.pipeline, projection: queryDetails.project, orderBy: queryDetails.orderBy, batchSize: queryDetails.batchSize, batchPeriod: queryDetails.batchPeriod, heartbeatPeriod: (_a = queryDetails.heartbeatPeriod) !== null && _a !== void 0 ? _a : 0, top: queryDetails.top, }; } static shareSubscriptionDetails(subDetails) { const copy = { ...subDetails }; // @ts-ignore delete copy.inboundQueue; delete copy.onMessage; return copy; } static hasError(msg) { var _a; return ((msg === null || msg === void 0 ? void 0 : msg.success) === false || (!!(msg === null || msg === void 0 ? void 0 : msg.error) && ((_a = msg === null || msg === void 0 ? void 0 : msg.error) === null || _a === void 0 ? void 0 : _a.trim()) !== "")); } async send(topic, msg, type, props) { return this.sendMessage(topic, msg, type, props); } sendWithKey(topic, key, msg) { throw new Error("Not implemented yet. Contact Francesco Laurita to enable sending messages with custom keys"); } safeTriggerOnSubscriptionChanged(subscriptionStatus, props) { if (props.onSubscriptionUpdate) { this.callHandlerSafely(props, () => { var _a; return (_a = props.onSubscriptionUpdate) === null || _a === void 0 ? void 0 : _a.call(this, subscriptionStatus, this); }, { subscriptionStatus }, "onSubscriptionUpdate"); } } safeTriggerOnStale(subscriptionStatus) { this.callHandlerSafely(this.lastConnectionProps, () => { var _a; return (_a = this._onStale) === null || _a === void 0 ? void 0 : _a.call(this, subscriptionStatus, this); }, { subscriptionStatus }, "onStale"); this._staleNotice[subscriptionStatus.subscriptionId] = subscriptionStatus.lastServerStatusDt; } async sendMessage(topic, msg, type, props) { var _a, _b, _c; let bMsg; const sendProps = { onError: (_a = props === null || props === void 0 ? void 0 : props.onError) !== null && _a !== void 0 ? _a : this.onError, publishRestEndPoint: (_b = props === null || props === void 0 ? void 0 : props.publishRestEndPoint) !== null && _b !== void 0 ? _b : this.restPublishEndPoint, gaToken: (_c = props === null || props === void 0 ? void 0 : props.gaToken) !== null && _c !== void 0 ? _c : this === null || this === void 0 ? void 0 : this.gaToken, }; if (!topic) { const err = "Can not send a message without a topic"; const errObj = new index_2.BarracudaError(err, { msg }); this.handleSendError(errObj, sendProps); return undefined; } if (!msg) { const err = "Can not send an empty message"; const errObj = new index_2.BarracudaError(err, { msg }); this.handleSendError(errObj, sendProps); return undefined; } if (typeof msg === "string") { try { bMsg = JSON.parse(msg); } catch (e) { const errObj = new index_2.BarracudaError("Can not send an un-parsable JSON message. JSON messages needs to be well formed.", { originalError: e, msg, }); this.handleSendError(errObj, sendProps); return undefined; } } else { bMsg = msg; } if (bMsg["_barracuda_meta"]) { bMsg["_barracuda_meta"] = { ...bMsg["_barracuda_meta"], bPublisherTst: Date.now(), }; } else { bMsg._barracuda_meta = { _payload_ver: 1, _ver: 4, bPublisherTst: Date.now(), bPublisherCommand: type, expiration: 0, sequenceId: 0, topic, bPublisherClient: { lang: BarracudaClientBuildDetail_1.default.name, version: BarracudaClientBuildDetail_1.default.version, }, bPublisherName: this.uid, }; } const requestHeaders = new cross_fetch_1.Headers({ "Content-Type": "application/json", }); requestHeaders.append("gaToken", sendProps.gaToken); const init = { body: JSON.stringify(bMsg, null, "").trim(), method: "POST", headers: requestHeaders, }; const info = `${sendProps === null || sendProps === void 0 ? void 0 : sendProps.publishRestEndPoint}/${type}/${topic}`; if (index_1.isInfo(this.ll)) { index_1.logInfo(`Sending Request to ${info}`, init); } let r; try { r = await cross_fetch_1.fetch(info, init); } catch (error) { const errObj = new index_2.BarracudaError(`Error while sending msg through REST to ${info}`, { httpRequest: { info, init }, originalError: error, }); this.handleSendError(errObj, sendProps); return undefined; } const responseHeader = r.headers; const xRay = JSON.stringify(responseHeader === null || responseHeader === void 0 ? void 0 : responseHeader.get("x-ray")); let responseBody; try { responseBody = await r.json(); } catch (error) { let body = ""; try { body = await r.text(); } catch (e) { index_1.logError(`Couldn't get text body from server response`, { httpRequest: { info, init, }, }); } const errObj = new index_2.BarracudaError("Error while json parsing server response.", { httpRequest: { info, init, }, httpResponse: { "x-ray": xRay, body, headers: responseHeader, }, originalError: error, }); this.handleSendError(errObj, sendProps); throw errObj; } if (responseBody.reply && responseBody.reply.indexOf("enqueued to ") >= 0) { const piranhaResponse = { ...responseBody, "x-ray": xRay, url: sendProps === null || sendProps === void 0 ? void 0 : sendProps.publishRestEndPoint, }; if (index_1.isInfo(this.ll)) { index_1.logInfo("REST Publish Success ==>", piranhaResponse); } if (index_1.isDebug(this.ll)) { index_1.logDebug("REST Publish Success ==>", { ...piranhaResponse, headers: responseHeader, }); } return piranhaResponse; } else { const errObj = new index_2.BarracudaError(`Received failure response from server ==> ${responseBody}`, { httpRequest: { info, init, }, httpResponse: { "x-ray": xRay, body: responseBody, header: responseHeader, }, url: sendProps === null || sendProps === void 0 ? void 0 : sendProps.publishRestEndPoint, }); this.handleSendError(errObj, sendProps); throw errObj; } } handleSendError(err, sendProps, logContext = { error: err }) { if (index_1.shouldLogErrors(this.ll)) { index_1.logError(err); } if (sendProps === null || sendProps === void 0 ? void 0 : sendProps.onError) { this.callHandlerSafely(this.lastConnectionProps, () => { var _a; return (_a = sendProps === null || sendProps === void 0 ? void 0 : sendProps.onError) === null || _a === void 0 ? void 0 : _a.call(this, err, this); }, logContext, "onError"); } else { throw err; } } setProps(props) { if (props === null || props === void 0 ? void 0 : props.loglevel) { this.loglevel = props.loglevel; } if (index_1.isDebug(this.ll)) { index_1.logDebug("BarracudaClient setting props", props); } if (props === null || props === void 0 ? void 0 : props.endpoint) { this._endpoint = props.endpoint; } if (props === null || props === void 0 ? void 0 : props.publishRestEndPoint) { this._defaultRestPublishEndPoint = props.publishRestEndPoint; } if (props === null || props === void 0 ? void 0 : props.serverDebug) { this._serverDebug = props.serverDebug; } if ((props === null || props === void 0 ? void 0 : props.reconnect) !== undefined) { this.reconnect = props.reconnect; } if (props === null || props === void 0 ? void 0 : props.onError) { this.onError = props.onError; } if (props === null || props === void 0 ? void 0 : props.onConnectionError) { this.onConnectionError = props.onConnectionError; } if (props === null || props === void 0 ? void 0 : props.onConnectionStateChange) { this.onConnectionStateChange = props.onConnectionStateChange; } if (props === null || props === void 0 ? void 0 : props.onSubscriptionUpdate) { this.onSubscriptionUpdate = props.onSubscriptionUpdate; } if (props === null || props === void 0 ? void 0 : props.instance) { this.instance = props === null || props === void 0 ? void 0 : props.instance; } if (props === null || props === void 0 ? void 0 : props.gaToken) { this._gaToken = props === null || props === void 0 ? void 0 : props.gaToken; } if (props === null || props === void 0 ? void 0 : props.appName) { this._appName = props.appName; } if (props === null || props === void 0 ? void 0 : props.appVersion) { this._appVersion = props.appVersion; } } triggerOnConnectionStateChange(conState, connectionProps) { this.connectionState = conState; const connectionStatusHandler = connectionProps === null || connectionProps === void 0 ? void 0 : connectionProps.onConnectionStateChange; switch (conState) { case IBarracudaClient_1.BarracudaConnectionStatus.connecting: case IBarracudaClient_1.BarracudaConnectionStatus.connected: case IBarracudaClient_1.BarracudaConnectionStatus.reconnecting: case IBarracudaClient_1.BarracudaConnectionStatus.closing: if (index_1.isDebug(this.ll)) { index_1.logDebug(`${this.bcLog(connectionProps)} connection state: ${conState}`); } break; case IBarracudaClient_1.BarracudaConnectionStatus.disconnected: case IBarracudaClient_1.BarracudaConnectionStatus.connectedAck: if (index_1.isInfo(this.ll)) { index_1.logInfo(`${this.bcLog(connectionProps)} connection state: ${conState}`); } break; case IBarracudaClient_1.BarracudaConnectionStatus.connectionError: if (index_1.shouldLogErrors(this.ll)) { index_1.logError(`${this.bcLog(connectionProps)} connection state: ${conState}`); } break; } if (connectionStatusHandler) { this.callHandlerSafely(connectionProps, () => connectionStatusHandler === null || connectionStatusHandler === void 0 ? void 0 : connectionStatusHandler.call(this, conState, this), { connectionState: conState }, "onConnectionStateChange"); } } scheduleReconnect(props, delay = 1000) { if (!this.skipReconnecting) { this.triggerOnConnectionStateChange(IBarracudaClient_1.BarracudaConnectionStatus.reconnecting, this.lastConnectionProps); if (index_1.isInfo(this.ll)) { const logArgs = index_1.isDebug(this.ll) ? { lastConnectionProps: this.lastConnectionProps, newConnectionProps: props, delay, } : undefined; index_1.logInfo(`Scheduling reconnection in ${delay === null || delay === void 0 ? void 0 : delay.toFixed(2)}ms`, logArgs); } setTimeout(() => this.connect(props), delay); } } callHandlerSafely(logCProps, handler, logContext, handlerName) { if (index_1.isDebug(this.ll)) { index_1.logDebug(`${this.bcLog(logCProps)} calling ${handlerName}`, { ...logContext, connectionProps: logCProps, }); } try { handler(); } catch (error) { const err = new index_2.BarracudaError(`Error while executing handler [${handlerName}]`, { originalError: error, handlerName: handlerName, handlerContext: logContext, connectionProps: logCProps, }); if (index_1.shouldLogErrors(this.ll)) { index_1.logError(err, { connectionProps: logCProps }); } } } startSubscriptionListener(props) { var _a; if (this.connectionState !== IBarracudaClient_1.BarracudaConnectionStatus.connectedAck) { return; } (_a = this.ws) === null || _a === void 0 ? void 0 : _a.on("message", (msg) => { if (this.connectionState !== IB