UNPKG

aws-crt

Version:

NodeJS/browser bindings to the aws-c-* libraries

998 lines 56.6 kB
"use strict"; /* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RequestResponseClient = exports.StreamingOperationBase = void 0; /** * * @packageDocumentation * @module mqtt_request_response * @mergeTarget * */ var protocol_client_adapter = __importStar(require("./mqtt_request_response/protocol_adapter")); var subscription_manager = __importStar(require("./mqtt_request_response/subscription_manager")); var mqtt_request_response = __importStar(require("../common/mqtt_request_response")); var mqtt_request_response_internal = __importStar(require("../common/mqtt_request_response_internal")); var event_1 = require("../common/event"); var error_1 = require("./error"); var promise_1 = require("../common/promise"); var io = __importStar(require("../common/io")); var mqtt_shared = __importStar(require("../common/mqtt_shared")); __exportStar(require("../common/mqtt_request_response"), exports); var OperationState; (function (OperationState) { /* creation -> in event loop enqueue */ OperationState[OperationState["None"] = 0] = "None"; /* in event loop queue -> non blocked response from subscription manager */ OperationState[OperationState["Queued"] = 1] = "Queued"; /* subscribing response from sub manager -> subscription success/failure event */ OperationState[OperationState["PendingSubscription"] = 2] = "PendingSubscription"; /* (request only) subscription success -> (publish failure OR correlated response received) */ OperationState[OperationState["PendingResponse"] = 3] = "PendingResponse"; /* (streaming only) subscription success -> (operation finished OR subscription ended event) */ OperationState[OperationState["Subscribed"] = 4] = "Subscribed"; /* (streaming only) (subscription failure OR subscription ended) -> operation close/terminate */ OperationState[OperationState["Terminal"] = 5] = "Terminal"; })(OperationState || (OperationState = {})); function operationStateToString(state) { switch (state) { case OperationState.None: return "None"; case OperationState.Queued: return "Queued"; case OperationState.PendingSubscription: return "PendingSubscription"; case OperationState.PendingResponse: return "PendingResponse"; case OperationState.Subscribed: return "Subscribed"; case OperationState.Terminal: return "Terminal"; default: return "Unknown"; } } var OperationType; (function (OperationType) { OperationType[OperationType["RequestResponse"] = 0] = "RequestResponse"; OperationType[OperationType["Streaming"] = 1] = "Streaming"; })(OperationType || (OperationType = {})); function areClientOptionsValid(options) { if (!options) { return false; } if (!options.maxRequestResponseSubscriptions) { return false; } if (!Number.isInteger(options.maxRequestResponseSubscriptions)) { return false; } if (options.maxRequestResponseSubscriptions < 2) { return false; } if (!options.maxStreamingSubscriptions) { return false; } if (!Number.isInteger(options.maxStreamingSubscriptions)) { return false; } if (options.operationTimeoutInSeconds) { if (!Number.isInteger(options.operationTimeoutInSeconds)) { return false; } if (options.operationTimeoutInSeconds <= 0) { return false; } } return true; } /** * An AWS MQTT service streaming operation. A streaming operation listens to messages on * a particular topic, deserializes them using a service model, and emits the modeled data as Javascript events. */ var StreamingOperationBase = /** @class */ (function (_super) { __extends(StreamingOperationBase, _super); function StreamingOperationBase(options) { var _this = _super.call(this) || this; _this.state = mqtt_request_response_internal.StreamingOperationState.None; _this.internalOptions = options; return _this; } /** * Triggers the streaming operation to start listening to the configured stream of events. Has no effect on an * already-open operation. It is an error to attempt to re-open a closed streaming operation. */ StreamingOperationBase.prototype.open = function () { if (this.state == mqtt_request_response_internal.StreamingOperationState.None) { this.internalOptions.open(); this.state = mqtt_request_response_internal.StreamingOperationState.Open; } else if (this.state == mqtt_request_response_internal.StreamingOperationState.Closed) { throw new error_1.CrtError("MQTT streaming operation already closed"); } }; /** * Stops a streaming operation from listening to the configured stream of events */ StreamingOperationBase.prototype.close = function () { if (this.state != mqtt_request_response_internal.StreamingOperationState.Closed) { this.state = mqtt_request_response_internal.StreamingOperationState.Closed; this.internalOptions.close(); } }; StreamingOperationBase.prototype.on = function (event, listener) { _super.prototype.on.call(this, event, listener); return this; }; /** * Event emitted when the stream's subscription status changes. * * Listener type: {@link SubscriptionStatusListener} * * @event */ StreamingOperationBase.SUBSCRIPTION_STATUS = 'subscriptionStatus'; /** * Event emitted when a stream message is received * * Listener type: {@link IncomingPublishListener} * * @event */ StreamingOperationBase.INCOMING_PUBLISH = 'incomingPublish'; return StreamingOperationBase; }(event_1.BufferedEventEmitter)); exports.StreamingOperationBase = StreamingOperationBase; var StreamingOperationInternal = /** @class */ (function (_super) { __extends(StreamingOperationInternal, _super); function StreamingOperationInternal(options) { return _super.call(this, options) || this; } StreamingOperationInternal.newInternal = function (options) { var operation = new StreamingOperationInternal(options); return operation; }; StreamingOperationInternal.prototype.triggerIncomingPublishEvent = function (publishEvent) { var _this = this; process.nextTick(function () { _this.emit(StreamingOperationBase.INCOMING_PUBLISH, publishEvent); }); }; StreamingOperationInternal.prototype.triggerSubscriptionStatusUpdateEvent = function (statusEvent) { var _this = this; process.nextTick(function () { _this.emit(StreamingOperationBase.SUBSCRIPTION_STATUS, statusEvent); }); }; return StreamingOperationInternal; }(StreamingOperationBase)); /** * Native implementation of an MQTT-based request-response client tuned for AWS MQTT services. * * Supports streaming operations (listen to a stream of modeled events from an MQTT topic) and request-response * operations (performs the subscribes, publish, and incoming publish correlation and error checking needed to * perform simple request-response operations over MQTT). */ var RequestResponseClient = /** @class */ (function (_super) { __extends(RequestResponseClient, _super); function RequestResponseClient(protocolClientAdapter, options) { var _this = this; var _a; if (!areClientOptionsValid(options)) { throw new error_1.CrtError("Invalid client options passed to RequestResponseClient constructor"); } _this = _super.call(this) || this; _this.nextOperationId = 1; _this.state = mqtt_request_response_internal.RequestResponseClientState.Ready; _this.operations = new Map(); _this.streamingOperationsByTopicFilter = new Map(); // topic filter -> set of operation ids _this.correlationTokenPathsByResponsePaths = new Map(); // response topic -> response path entry _this.operationsByCorrelationToken = new Map(); // correlation token -> operation id _this.operationQueue = new Array; _this.operationTimeoutInSeconds = (_a = options.operationTimeoutInSeconds) !== null && _a !== void 0 ? _a : 60; _this.protocolClientAdapter = protocolClientAdapter; _this.protocolClientAdapter.addListener(protocol_client_adapter.ProtocolClientAdapter.PUBLISH_COMPLETION, _this.handlePublishCompletionEvent.bind(_this)); _this.protocolClientAdapter.addListener(protocol_client_adapter.ProtocolClientAdapter.CONNECTION_STATUS, _this.handleConnectionStatusEvent.bind(_this)); _this.protocolClientAdapter.addListener(protocol_client_adapter.ProtocolClientAdapter.INCOMING_PUBLISH, _this.handleIncomingPublishEvent.bind(_this)); var config = { maxRequestResponseSubscriptions: options.maxRequestResponseSubscriptions, maxStreamingSubscriptions: options.maxStreamingSubscriptions, operationTimeoutInSeconds: _this.operationTimeoutInSeconds, }; _this.subscriptionManager = new subscription_manager.SubscriptionManager(protocolClientAdapter, config); _this.subscriptionManager.addListener(subscription_manager.SubscriptionManager.SUBSCRIBE_SUCCESS, _this.handleSubscribeSuccessEvent.bind(_this)); _this.subscriptionManager.addListener(subscription_manager.SubscriptionManager.SUBSCRIBE_FAILURE, _this.handleSubscribeFailureEvent.bind(_this)); _this.subscriptionManager.addListener(subscription_manager.SubscriptionManager.SUBSCRIPTION_ENDED, _this.handleSubscriptionEndedEvent.bind(_this)); _this.subscriptionManager.addListener(subscription_manager.SubscriptionManager.STREAMING_SUBSCRIPTION_ESTABLISHED, _this.handleStreamingSubscriptionEstablishedEvent.bind(_this)); _this.subscriptionManager.addListener(subscription_manager.SubscriptionManager.STREAMING_SUBSCRIPTION_LOST, _this.handleStreamingSubscriptionLostEvent.bind(_this)); _this.subscriptionManager.addListener(subscription_manager.SubscriptionManager.STREAMING_SUBSCRIPTION_HALTED, _this.handleStreamingSubscriptionHaltedEvent.bind(_this)); _this.subscriptionManager.addListener(subscription_manager.SubscriptionManager.SUBSCRIPTION_ORPHANED, _this.handleSubscriptionOrphanedEvent.bind(_this)); _this.subscriptionManager.addListener(subscription_manager.SubscriptionManager.UNSUBSCRIBE_COMPLETE, _this.handleUnsubscribeCompleteEvent.bind(_this)); return _this; } /** * Creates a new MQTT service request-response client that uses an MQTT5 client as the protocol implementation. * * @param protocolClient protocol client to use for all operations * @param options configuration options for the desired request-response client */ RequestResponseClient.newFromMqtt5 = function (protocolClient, options) { if (!protocolClient) { throw new error_1.CrtError("protocol client is null"); } var adapter = protocol_client_adapter.ProtocolClientAdapter.newFrom5(protocolClient); var client = new RequestResponseClient(adapter, options); return client; }; /** * Creates a new MQTT service request-response client that uses an MQTT311 client as the protocol implementation. * * @param protocolClient protocol client to use for all operations * @param options configuration options for the desired request-response client */ RequestResponseClient.newFromMqtt311 = function (protocolClient, options) { if (!protocolClient) { throw new error_1.CrtError("protocol client is null"); } var adapter = protocol_client_adapter.ProtocolClientAdapter.newFrom311(protocolClient); var client = new RequestResponseClient(adapter, options); return client; }; /** * Triggers cleanup of native resources associated with the request-response client. Closing a client will fail * all incomplete requests and close all outstanding streaming operations. * * This must be called when finished with a client; otherwise, native resources will leak. */ RequestResponseClient.prototype.close = function () { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Closed) { io.logInfo(RequestResponseClient.logSubject, "closing MQTT RequestResponseClient"); this.state = mqtt_request_response_internal.RequestResponseClientState.Closed; this.closeAllOperations(); this.protocolClientAdapter.close(); this.subscriptionManager.close(); } }; /** * Submits a request to the request-response client. * * @param requestOptions description of the request to perform * * Returns a promise that resolves to a response to the request or an error describing how the request attempt * failed. * * A "successful" request-response execution flow is defined as "the service sent a response payload that * correlates with the request payload." Upon deserialization (which is the responsibility of the service model * client, one layer up), such a payload may actually indicate a failure. */ RequestResponseClient.prototype.submitRequest = function (requestOptions) { return __awaiter(this, void 0, void 0, function () { var resultPromise, id, operation; var _this = this; return __generator(this, function (_a) { resultPromise = (0, promise_1.newLiftedPromise)(); if (this.state == mqtt_request_response_internal.RequestResponseClientState.Closed) { resultPromise.reject(new error_1.CrtError("MQTT request-response client has already been closed")); return [2 /*return*/, resultPromise.promise]; } try { validateRequestOptions(requestOptions); } catch (err) { resultPromise.reject(err); return [2 /*return*/, resultPromise.promise]; } id = this.nextOperationId; this.nextOperationId++; operation = { id: id, type: OperationType.RequestResponse, state: OperationState.Queued, pendingSubscriptionCount: requestOptions.subscriptionTopicFilters.length, inClientTables: false, options: requestOptions, resultPromise: resultPromise, }; this.operations.set(id, operation); this.operationQueue.push(id); setTimeout(function () { try { _this.completeRequestResponseOperationWithError(id, new error_1.CrtError("Operation timeout")); } catch (err) { ; } }, this.operationTimeoutInSeconds * 1000); this.wakeServiceTask(); io.logInfo(RequestResponseClient.logSubject, "request-response operation with id \"".concat(id, "\" submitted to operation queue")); return [2 /*return*/, resultPromise.promise]; }); }); }; /** * Creates a new streaming operation from a set of configuration options. A streaming operation provides a * mechanism for listening to a specific event stream from an AWS MQTT-based service. * * @param streamOptions configuration options for the streaming operation * * browser/node implementers are covariant by returning an implementation of IStreamingOperation. This split * is necessary because event listening (which streaming operations need) cannot be modeled on an interface. */ RequestResponseClient.prototype.createStream = function (streamOptions) { var _this = this; if (this.state == mqtt_request_response_internal.RequestResponseClientState.Closed) { throw new error_1.CrtError("MQTT request-response client has already been closed"); } validateStreamingOptions(streamOptions); var id = this.nextOperationId; this.nextOperationId++; var internalOptions = { open: function () { _this.openStreamingOperation(id); }, close: function () { _this.closeStreamingOperation(id); }, }; var internalOperation = StreamingOperationInternal.newInternal(internalOptions); var operation = { id: id, type: OperationType.Streaming, state: OperationState.None, pendingSubscriptionCount: 1, inClientTables: false, options: streamOptions, operation: internalOperation }; this.operations.set(id, operation); return internalOperation; }; RequestResponseClient.prototype.canOperationDequeue = function (operation) { var _a; if (operation.type != OperationType.RequestResponse) { return true; } var rrOperation = operation; var correlationToken = (_a = rrOperation.options.correlationToken) !== null && _a !== void 0 ? _a : ""; return !this.operationsByCorrelationToken.has(correlationToken); }; RequestResponseClient.buildSuscriptionListFromOperation = function (operation) { if (operation.type == OperationType.RequestResponse) { var rrOperation = operation; return rrOperation.options.subscriptionTopicFilters; } else { var streamingOperation = operation; return new Array(streamingOperation.options.subscriptionTopicFilter); } }; RequestResponseClient.prototype.addOperationToInProgressTables = function (operation) { var e_1, _a; var _b; if (operation.type == OperationType.Streaming) { var streamingOperation = operation; var filter = streamingOperation.options.subscriptionTopicFilter; var existingSet = this.streamingOperationsByTopicFilter.get(filter); if (!existingSet) { existingSet = new Set(); this.streamingOperationsByTopicFilter.set(filter, existingSet); io.logDebug(RequestResponseClient.logSubject, "adding topic filter \"".concat(filter, "\" to streaming subscriptions table")); } existingSet.add(operation.id); io.logDebug(RequestResponseClient.logSubject, "adding operation ".concat(operation.id, " to streaming subscriptions table under topic filter \"").concat(filter, "\"")); } else { var rrOperation = operation; var correlationToken = (_b = rrOperation.options.correlationToken) !== null && _b !== void 0 ? _b : ""; this.operationsByCorrelationToken.set(correlationToken, operation.id); io.logDebug(RequestResponseClient.logSubject, "operation ".concat(operation.id, " registered with correlation token \"").concat(correlationToken, "\"")); try { for (var _c = __values(rrOperation.options.responsePaths), _d = _c.next(); !_d.done; _d = _c.next()) { var path = _d.value; var existingEntry = this.correlationTokenPathsByResponsePaths.get(path.topic); if (!existingEntry) { existingEntry = { refCount: 0 }; if (path.correlationTokenJsonPath) { existingEntry.correlationTokenPath = path.correlationTokenJsonPath.split('.'); } this.correlationTokenPathsByResponsePaths.set(path.topic, existingEntry); io.logDebug(RequestResponseClient.logSubject, "adding response path \"".concat(path.topic, "\" to response path table")); } existingEntry.refCount++; io.logDebug(RequestResponseClient.logSubject, "operation ".concat(operation.id, " adding reference to response path \"").concat(path.topic, "\"")); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_1) throw e_1.error; } } } operation.inClientTables = true; }; RequestResponseClient.prototype.handleAcquireSubscriptionResult = function (operation, result) { if (result == subscription_manager.AcquireSubscriptionResult.Failure || result == subscription_manager.AcquireSubscriptionResult.NoCapacity) { this.completeOperationWithError(operation.id, new error_1.CrtError("Acquire subscription error: ".concat(subscription_manager.acquireSubscriptionResultToString(result)))); return; } this.addOperationToInProgressTables(operation); if (result == subscription_manager.AcquireSubscriptionResult.Subscribing) { this.changeOperationState(operation, OperationState.PendingSubscription); return; } if (operation.type == OperationType.Streaming) { this.changeOperationState(operation, OperationState.Subscribed); var streamingOperation = operation; streamingOperation.operation.triggerSubscriptionStatusUpdateEvent({ type: mqtt_request_response.SubscriptionStatusEventType.SubscriptionEstablished }); } else { this.applyRequestResponsePublish(operation); } }; RequestResponseClient.prototype.service = function () { this.serviceTask = undefined; if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } this.subscriptionManager.purge(); io.logDebug(RequestResponseClient.logSubject, "servicing operation queue with ".concat(this.operationQueue.length, " entries")); while (this.operationQueue.length > 0) { var headId = this.operationQueue[0]; var operation = this.operations.get(headId); if (!operation) { this.operationQueue.shift(); continue; } if (!this.canOperationDequeue(operation)) { io.logDebug(RequestResponseClient.logSubject, "operation ".concat(headId, " cannot be dequeued")); break; } var acquireOptions = { topicFilters: RequestResponseClient.buildSuscriptionListFromOperation(operation), operationId: headId, type: (operation.type == OperationType.RequestResponse) ? subscription_manager.SubscriptionType.RequestResponse : subscription_manager.SubscriptionType.EventStream, }; var acquireResult = this.subscriptionManager.acquireSubscription(acquireOptions); io.logDebug(RequestResponseClient.logSubject, "servicing queued operation ".concat(operation.id, " yielded acquire subscription result of \"").concat(subscription_manager.acquireSubscriptionResultToString(acquireResult), "\"")); if (acquireResult == subscription_manager.AcquireSubscriptionResult.Blocked) { break; } this.operationQueue.shift(); this.handleAcquireSubscriptionResult(operation, acquireResult); } }; RequestResponseClient.prototype.clearServiceTask = function () { if (this.serviceTask) { clearTimeout(this.serviceTask.serviceTask); this.serviceTask = undefined; } }; RequestResponseClient.prototype.tryScheduleServiceTask = function (serviceTime) { var _this = this; if (this.serviceTask) { if (serviceTime >= this.serviceTask.nextServiceTime) { return; } this.clearServiceTask(); } var futureMs = Math.max(0, Date.now() - serviceTime); this.serviceTask = { serviceTask: setTimeout(function () { _this.service(); }, futureMs), nextServiceTime: serviceTime, }; io.logDebug(RequestResponseClient.logSubject, "service task scheduled for execution in ".concat(futureMs, " MS")); }; RequestResponseClient.prototype.wakeServiceTask = function () { this.tryScheduleServiceTask(Date.now()); }; RequestResponseClient.prototype.closeAllOperations = function () { var e_2, _a; var operations = Array.from(this.operations).map(function (_a) { var _b = __read(_a, 2), key = _b[0], value = _b[1]; return key; }); try { for (var operations_1 = __values(operations), operations_1_1 = operations_1.next(); !operations_1_1.done; operations_1_1 = operations_1.next()) { var id = operations_1_1.value; this.completeOperationWithError(id, new error_1.CrtError("Request-response client closed")); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (operations_1_1 && !operations_1_1.done && (_a = operations_1.return)) _a.call(operations_1); } finally { if (e_2) throw e_2.error; } } }; RequestResponseClient.prototype.removeStreamingOperationFromTopicFilterSet = function (topicFilter, id) { var operationSet = this.streamingOperationsByTopicFilter.get(topicFilter); if (!operationSet) { return; } operationSet.delete(id); io.logDebug(RequestResponseClient.logSubject, "removed operation ".concat(id, " from streaming topic filter table entry for \"").concat(topicFilter, "\"")); if (operationSet.size > 0) { return; } this.streamingOperationsByTopicFilter.delete(topicFilter); io.logDebug(RequestResponseClient.logSubject, "removed streaming topic filter table entry for \"".concat(topicFilter, "\"")); }; RequestResponseClient.prototype.decRefResponsePaths = function (topic) { var pathEntry = this.correlationTokenPathsByResponsePaths.get(topic); if (!pathEntry) { return; } pathEntry.refCount--; io.logDebug(RequestResponseClient.logSubject, "dec-refing response path entry for \"".concat(topic, "\", ").concat(pathEntry.refCount, " references left")); if (pathEntry.refCount < 1) { io.logDebug(RequestResponseClient.logSubject, "removing response path entry for \"".concat(topic, "\"")); this.correlationTokenPathsByResponsePaths.delete(topic); } }; RequestResponseClient.prototype.removeRequestResponseOperation = function (operation) { var e_3, _a; var _b; io.logDebug(RequestResponseClient.logSubject, "removing request-response operation ".concat(operation.id, " from client state")); this.operations.delete(operation.id); if (operation.inClientTables) { try { for (var _c = __values(operation.options.responsePaths), _d = _c.next(); !_d.done; _d = _c.next()) { var responsePath = _d.value; this.decRefResponsePaths(responsePath.topic); } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_3) throw e_3.error; } } var correlationToken = (_b = operation.options.correlationToken) !== null && _b !== void 0 ? _b : ""; this.operationsByCorrelationToken.delete(correlationToken); } var releaseOptions = { topicFilters: operation.options.subscriptionTopicFilters, operationId: operation.id, }; this.subscriptionManager.releaseSubscription(releaseOptions); }; RequestResponseClient.prototype.removeStreamingOperation = function (operation) { io.logDebug(RequestResponseClient.logSubject, "removing streaming operation ".concat(operation.id, " from client state")); this.operations.delete(operation.id); if (operation.inClientTables) { this.removeStreamingOperationFromTopicFilterSet(operation.options.subscriptionTopicFilter, operation.id); } var releaseOptions = { topicFilters: new Array(operation.options.subscriptionTopicFilter), operationId: operation.id, }; this.subscriptionManager.releaseSubscription(releaseOptions); }; RequestResponseClient.prototype.removeOperation = function (id) { var operation = this.operations.get(id); if (!operation) { return; } if (operation.type == OperationType.RequestResponse) { this.removeRequestResponseOperation(operation); } else { this.removeStreamingOperation(operation); } }; RequestResponseClient.prototype.completeRequestResponseOperationWithError = function (id, err) { var operation = this.operations.get(id); if (!operation) { return; } io.logInfo(RequestResponseClient.logSubject, "request-response operation ".concat(id, " completed with error: \"").concat(JSON.stringify(err), "\"")); this.removeOperation(id); if (operation.type != OperationType.RequestResponse) { return; } var rrOperation = operation; var promise = rrOperation.resultPromise; promise.reject(err); }; RequestResponseClient.prototype.haltStreamingOperationWithError = function (id, err) { var operation = this.operations.get(id); if (!operation) { return; } io.logInfo(RequestResponseClient.logSubject, "streaming operation ".concat(id, " halted with error: \"").concat(JSON.stringify(err), "\"")); this.removeOperation(id); if (operation.type != OperationType.Streaming) { return; } var streamingOperation = operation; if (operation.state != OperationState.Terminal && operation.state != OperationState.None) { streamingOperation.operation.triggerSubscriptionStatusUpdateEvent({ type: mqtt_request_response.SubscriptionStatusEventType.SubscriptionHalted, error: err }); } this.changeOperationState(operation, OperationState.Terminal); // this is mostly a no-op except it's the only way we can guarantee that the streaming operation state also gets // flipped to closed streamingOperation.operation.close(); }; RequestResponseClient.prototype.completeOperationWithError = function (id, err) { var operation = this.operations.get(id); if (!operation) { return; } if (operation.type == OperationType.RequestResponse) { this.completeRequestResponseOperationWithError(id, err); } else { this.haltStreamingOperationWithError(id, err); } }; RequestResponseClient.prototype.completeRequestResponseOperationWithResponse = function (id, responseTopic, payload) { var operation = this.operations.get(id); if (!operation) { return; } io.logInfo(RequestResponseClient.logSubject, "request-response operation ".concat(id, " successfully completed with response\"")); this.removeOperation(id); if (operation.type != OperationType.RequestResponse) { return; } var rrOperation = operation; var promise = rrOperation.resultPromise; promise.resolve({ topic: responseTopic, payload: payload }); }; RequestResponseClient.prototype.handlePublishCompletionEvent = function (event) { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } var id = event.completionData; if (event.err) { this.completeRequestResponseOperationWithError(id, event.err); } else { io.logDebug(RequestResponseClient.logSubject, "request-response operation ".concat(id, " successfully published request payload\"")); } }; RequestResponseClient.prototype.handleConnectionStatusEvent = function (event) { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } if (event.status == protocol_client_adapter.ConnectionState.Connected && this.operationQueue.length > 0) { this.wakeServiceTask(); } }; RequestResponseClient.prototype.handleIncomingPublishEventStreaming = function (event, operations) { var e_4, _a; if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } try { for (var operations_2 = __values(operations), operations_2_1 = operations_2.next(); !operations_2_1.done; operations_2_1 = operations_2.next()) { var id = operations_2_1.value; var operation = this.operations.get(id); if (!operation) { continue; } if (operation.type != OperationType.Streaming) { continue; } var streamingOperation = operation; streamingOperation.operation.triggerIncomingPublishEvent({ topic: event.topic, payload: event.payload }); } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (operations_2_1 && !operations_2_1.done && (_a = operations_2.return)) _a.call(operations_2); } finally { if (e_4) throw e_4.error; } } }; RequestResponseClient.prototype.handleIncomingPublishEventRequestResponse = function (event, responsePathEntry) { var e_5, _a; io.logDebug(RequestResponseClient.logSubject, "processing incoming publish event on response path topic \"".concat(event.topic, "\"")); if (!event.payload) { io.logError(RequestResponseClient.logSubject, "incoming publish on response path topic \"".concat(event.topic, "\" has no payload")); return; } try { var correlationToken = undefined; if (!responsePathEntry.correlationTokenPath) { correlationToken = ""; } else { var payloadAsString = new TextDecoder().decode(new Uint8Array(event.payload)); var payloadAsJson = JSON.parse(payloadAsString); var segmentValue = payloadAsJson; try { for (var _b = __values(responsePathEntry.correlationTokenPath), _c = _b.next(); !_c.done; _c = _b.next()) { var segment = _c.value; var segmentPropertyValue = segmentValue[segment]; if (!segmentPropertyValue) { io.logError(RequestResponseClient.logSubject, "incoming publish on response path topic \"".concat(event.topic, "\" does not have a correlation token at the expected JSON path")); break; } segmentValue = segmentValue[segment]; } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_5) throw e_5.error; } } if (segmentValue && typeof (segmentValue) === "string") { correlationToken = segmentValue; } } if (correlationToken === undefined) { io.logError(RequestResponseClient.logSubject, "A valid correlation token could not be inferred for incoming publish on response path topic \"".concat(event.topic, "\"")); return; } var id = this.operationsByCorrelationToken.get(correlationToken); if (!id) { io.logDebug(RequestResponseClient.logSubject, "incoming publish on response path topic \"".concat(event.topic, "\" with correlation token \"").concat(correlationToken, "\" does not have an originating request entry")); return; } this.completeRequestResponseOperationWithResponse(id, event.topic, event.payload); } catch (err) { io.logError(RequestResponseClient.logSubject, "incoming publish on response path topic \"".concat(event.topic, "\" triggered exception: ").concat(JSON.stringify(err))); } }; RequestResponseClient.prototype.handleIncomingPublishEvent = function (event) { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } var responsePathEntry = this.correlationTokenPathsByResponsePaths.get(event.topic); if (responsePathEntry) { this.handleIncomingPublishEventRequestResponse(event, responsePathEntry); } var streamingOperationSet = this.streamingOperationsByTopicFilter.get(event.topic); if (streamingOperationSet) { this.handleIncomingPublishEventStreaming(event, streamingOperationSet); } }; RequestResponseClient.prototype.handleSubscribeSuccessEvent = function (event) { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } io.logDebug(RequestResponseClient.logSubject, "subscribe success event received for operation ".concat(event.operationId, " using topic filter \"").concat(event.topicFilter, "\"")); var operation = this.operations.get(event.operationId); if (!operation) { return; } var rrOperation = operation; rrOperation.pendingSubscriptionCount--; if (rrOperation.pendingSubscriptionCount === 0) { this.applyRequestResponsePublish(rrOperation); } else { io.logDebug(RequestResponseClient.logSubject, "operation ".concat(event.operationId, " has ").concat(rrOperation.pendingSubscriptionCount, " pending subscriptions left")); } }; RequestResponseClient.prototype.handleSubscribeFailureEvent = function (event) { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } io.logDebug(RequestResponseClient.logSubject, "subscribe failure event received for operation ".concat(event.operationId, " using topic filter \"").concat(event.topicFilter, "\"")); this.completeRequestResponseOperationWithError(event.operationId, new error_1.CrtError("Subscribe failure")); }; RequestResponseClient.prototype.handleSubscriptionEndedEvent = function (event) { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } io.logDebug(RequestResponseClient.logSubject, "subscription ended event received for operation ".concat(event.operationId, " using topic filter \"").concat(event.topicFilter, "\"")); this.completeRequestResponseOperationWithError(event.operationId, new error_1.CrtError("Subscription Ended Early")); }; RequestResponseClient.prototype.handleStreamingSubscriptionEstablishedEvent = function (event) { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } var operation = this.operations.get(event.operationId); if (!operation) { return; } if (operation.state == OperationState.Terminal) { return; } if (operation.type != OperationType.Streaming) { return; } var streamingOperation = operation; streamingOperation.operation.triggerSubscriptionStatusUpdateEvent({ type: mqtt_request_response.SubscriptionStatusEventType.SubscriptionEstablished }); this.changeOperationState(operation, OperationState.Subscribed); }; RequestResponseClient.prototype.handleStreamingSubscriptionLostEvent = function (event) { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } var operation = this.operations.get(event.operationId); if (!operation) { return; } if (operation.state == OperationState.Terminal) { return; } if (operation.type != OperationType.Streaming) { return; } var streamingOperation = operation; streamingOperation.operation.triggerSubscriptionStatusUpdateEvent({ type: mqtt_request_response.SubscriptionStatusEventType.SubscriptionLost, }); }; RequestResponseClient.prototype.handleStreamingSubscriptionHaltedEvent = function (event) { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } var operation = this.operations.get(event.operationId); if (!operation) { return; } if (operation.state == OperationState.Terminal) { return; } if (operation.type != OperationType.Streaming) { return; } var streamingOperation = operation; streamingOperation.operation.triggerSubscriptionStatusUpdateEvent({ type: mqtt_request_response.SubscriptionStatusEventType.SubscriptionHalted, error: new error_1.CrtError("Subscription Failure for topic filter \"".concat(event.topicFilter, "\"")) }); this.changeOperationState(operation, OperationState.Terminal); }; RequestResponseClient.prototype.handleSubscriptionOrphanedEvent = function (event) { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } io.logDebug(RequestResponseClient.logSubject, "subscription orphaned event received for topic filter \"".concat(event.topicFilter, "\"")); this.wakeServiceTask(); }; RequestResponseClient.prototype.handleUnsubscribeCompleteEvent = function (event) { if (this.state != mqtt_request_response_internal.RequestResponseClientState.Ready) { return; } io.logDebug(RequestResponseClient.logSubject, "unsubscribe completion event received for topic filter \"".concat(event.topicFilter, "\"")); this.wakeServiceTask(); }; RequestResponseClient.prototype.changeOperationState = function (operation, state) { if (state == operation.state) { return; } io.logDebug(RequestResponseClient.logSubject, "operation ".concat(operation.id, " changing state from \"").concat(operationStateToString(operation.state), "\" to \"").concat(operationStateToString(state), "\"")); operation.state = state; }; RequestResponseClient.prototype.applyRequestResponsePublish = function (operation) { var publishOptions = { topic: operation.options.publishTopic, payload: operation.options.payload, timeoutInSeconds: this.operationTimeoutInSeconds, completionData: operation.id }; try { io.logDebug(RequestResponseClient.logSubject, "submitting publish for request-response operation ".concat(operation.id)); this.protocolClientAdapter.publish(publishOptions); this.changeOperationState(operation, OperationStat