UNPKG

@azure/event-hubs

Version:
351 lines (350 loc) • 15.3 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var connectionContext_exports = {}; __export(connectionContext_exports, { ConnectionContext: () => ConnectionContext, createConnectionContext: () => createConnectionContext }); module.exports = __toCommonJS(connectionContext_exports); var import_rhea_promise = require("rhea-promise"); var import_core_amqp = require("@azure/core-amqp"); var import_connectionStringUtils = require("./util/connectionStringUtils.js"); var import_managementClient = require("./managementClient.js"); var import_core_auth = require("@azure/core-auth"); var import_logger = require("./logger.js"); var import_eventhubConnectionConfig = require("./eventhubConnectionConfig.js"); var import_runtimeInfo = require("./util/runtimeInfo.js"); var import_typeGuards = require("./util/typeGuards.js"); var import_constants = require("./util/constants.js"); var import_core_util = require("@azure/core-util"); var ConnectionContext; ((ConnectionContext2) => { const userAgent = `azsdk-js-azureeventhubs/${import_constants.packageJsonInfo.version} (${(0, import_runtimeInfo.getRuntimeInfo)()})`; function getUserAgent(options) { const finalUserAgent = options.userAgent ? `${userAgent},${options.userAgent}` : userAgent; if (finalUserAgent.length > import_core_amqp.Constants.maxUserAgentLength) { throw new Error( `The user-agent string cannot be more than ${import_core_amqp.Constants.maxUserAgentLength} characters in length.The given user-agent string is: ${finalUserAgent} with length: ${finalUserAgent.length}` ); } return finalUserAgent; } ConnectionContext2.getUserAgent = getUserAgent; function create(config, tokenCredential, options) { if (!options) options = {}; config.webSocket = options.webSocketOptions && options.webSocketOptions.webSocket; config.webSocketEndpointPath = "$servicebus/websocket"; config.webSocketConstructorOptions = options.webSocketOptions && options.webSocketOptions.webSocketConstructorOptions; const parameters = { config, // re-enabling this will be a post-GA discussion. // dataTransformer: options.dataTransformer, isEntityPathRequired: true, connectionProperties: { product: "MSJSClient", userAgent: getUserAgent(options), version: import_constants.packageJsonInfo.version } }; const connectionContext = import_core_amqp.ConnectionContextBase.create(parameters); connectionContext.tokenCredential = tokenCredential; connectionContext.wasConnectionCloseCalled = false; connectionContext.senders = {}; connectionContext.receivers = {}; const mOptions = { address: options.managementSessionAddress, audience: options.managementSessionAudience }; connectionContext.managementSession = new import_managementClient.ManagementClient(connectionContext, mOptions); let waitForConnectionRefreshResolve; let waitForConnectionRefreshPromise; Object.assign(connectionContext, { isConnectionClosing() { return Boolean(!this.connection.isOpen() && this.connection.isRemoteOpen()); }, async readyToOpenLink(optionsArg) { if (this.isConnectionClosing()) { await this.waitForDisconnectedEvent(optionsArg); } await this.waitForConnectionReset(); }, waitForDisconnectedEvent(optionsArg) { return (0, import_core_util.createAbortablePromise)((resolve) => { import_logger.logger.verbose( `[${this.connectionId}] Attempting to reinitialize connection but the connection is in the process of closing. Waiting for the disconnect event before continuing.` ); this.connection.once(import_rhea_promise.ConnectionEvents.disconnected, resolve); }, optionsArg); }, waitForConnectionReset() { if (waitForConnectionRefreshPromise) { return waitForConnectionRefreshPromise; } return Promise.resolve(); }, async close() { try { if (this.connection.isOpen()) { await Promise.all( Object.keys(connectionContext.senders).map( (name) => connectionContext.senders[name]?.close().catch(() => { }) ) ); await Promise.all( Object.keys(connectionContext.receivers).map( (name) => connectionContext.receivers[name]?.close().catch(() => { }) ) ); await this.cbsSession.close(); await this.managementSession?.close(); await this.connection.close(); this.wasConnectionCloseCalled = true; import_logger.logger.info("Closed the amqp connection '%s' on the client.", this.connectionId); } } catch (err) { const errorDescription = err instanceof Error ? `${err.name}: ${err.message}` : JSON.stringify(err); import_logger.logger.warning( `An error occurred while closing the connection "${this.connectionId}": ${errorDescription}` ); (0, import_logger.logErrorStackTrace)(err); throw err; } } }); const onConnectionOpen = () => { connectionContext.wasConnectionCloseCalled = false; import_logger.logger.verbose( "[%s] setting 'wasConnectionCloseCalled' property of connection context to %s.", connectionContext.connection.id, connectionContext.wasConnectionCloseCalled ); }; async function handleDisconnection(context) { if (waitForConnectionRefreshPromise) { return; } waitForConnectionRefreshPromise = new Promise((resolve) => { waitForConnectionRefreshResolve = resolve; }); try { import_logger.logger.verbose( "[%s] 'disconnected' event occurred on the amqp connection.", connectionContext.connection.id ); if (context.connection && context.connection.error) { import_logger.logger.verbose( "[%s] Accompanying error on the context.connection: %O", connectionContext.connection.id, context.connection.error ); } if (context.error) { import_logger.logger.verbose( "[%s] Accompanying error on the context: %O", connectionContext.connection.id, context.error ); } const state = { wasConnectionCloseCalled: connectionContext.wasConnectionCloseCalled, numSenders: Object.keys(connectionContext.senders).length, numReceivers: Object.keys(connectionContext.receivers).length }; import_logger.logger.verbose( "[%s] Closing all open senders and receivers in the state: %O", connectionContext.connection.id, state ); connectionContext.connection.removeAllSessions(); await connectionContext.cbsSession?.close().catch(() => { }); await connectionContext.managementSession?.close().catch(() => { }); if (state.numSenders || state.numReceivers) { await Promise.all( Object.keys(connectionContext.senders).map( (name) => connectionContext.senders[name]?.close().catch(() => { }) ) ); await Promise.all( Object.keys(connectionContext.receivers).map( (name) => connectionContext.receivers[name]?.close().catch(() => { }) ) ); } } catch (err) { import_logger.logger.verbose( `[${connectionContext.connectionId}] An error occurred while closing the connection in 'disconnected'. %O`, err ); } try { await refreshConnection(connectionContext); } catch (err) { import_logger.logger.verbose( `[${connectionContext.connectionId}] An error occurred while refreshing the connection in 'disconnected'. %O`, err ); } finally { waitForConnectionRefreshResolve(); waitForConnectionRefreshPromise = void 0; } } const onDisconnected = (context) => { handleDisconnection(context).catch((err) => { import_logger.logger.verbose( `[${connectionContext.connectionId}] Unhandled error in 'disconnected' event handler. %O`, err ); }); }; const protocolError = (context) => { import_logger.logger.verbose( "[%s] 'protocol_error' event occurred on the amqp connection.", connectionContext.connection.id ); if (context.connection && context.connection.error) { import_logger.logger.verbose( "[%s] Accompanying error on the context.connection: %O", connectionContext.connection.id, context.connection && context.connection.error ); } if (context.error) { import_logger.logger.verbose( "[%s] Accompanying error on the context: %O", connectionContext.connection.id, context.error ); } }; const error = (context) => { import_logger.logger.verbose( "[%s] 'error' event occurred on the amqp connection.", connectionContext.connection.id ); if (context.connection && context.connection.error) { import_logger.logger.verbose( "[%s] Accompanying error on the context.connection: %O", connectionContext.connection.id, context.connection && context.connection.error ); } if (context.error) { import_logger.logger.verbose( "[%s] Accompanying error on the context: %O", connectionContext.connection.id, context.error ); } }; function addConnectionListeners(connection) { connection.on(import_rhea_promise.ConnectionEvents.connectionOpen, onConnectionOpen); connection.on(import_rhea_promise.ConnectionEvents.disconnected, onDisconnected); connection.on(import_rhea_promise.ConnectionEvents.protocolError, protocolError); connection.on(import_rhea_promise.ConnectionEvents.error, error); } function cleanConnectionContext(context) { context.connection.removeListener(import_rhea_promise.ConnectionEvents.connectionOpen, onConnectionOpen); context.connection.removeListener(import_rhea_promise.ConnectionEvents.disconnected, onDisconnected); context.connection.removeListener(import_rhea_promise.ConnectionEvents.protocolError, protocolError); context.connection.removeListener(import_rhea_promise.ConnectionEvents.error, error); return context.connection.close(); } async function refreshConnection(context) { const originalConnectionId = context.connectionId; try { await cleanConnectionContext(context); } catch (err) { import_logger.logger.verbose( `[${context.connectionId}] There was an error closing the connection before reconnecting: %O`, err ); } context.refreshConnection(); addConnectionListeners(context.connection); import_logger.logger.verbose( `The connection "${originalConnectionId}" has been updated to "${context.connectionId}".` ); } addConnectionListeners(connectionContext.connection); import_logger.logger.verbose("[%s] Created connection context successfully.", connectionContext.connectionId); return connectionContext; } ConnectionContext2.create = create; })(ConnectionContext || (ConnectionContext = {})); function createConnectionContext(hostOrConnectionString, eventHubNameOrOptions, credentialOrOptions, options) { let connectionString; let config; let credential; hostOrConnectionString = String(hostOrConnectionString); if (!(0, import_typeGuards.isCredential)(credentialOrOptions)) { const parsedCS = (0, import_connectionStringUtils.parseEventHubConnectionString)(hostOrConnectionString); if (!(parsedCS.eventHubName || typeof eventHubNameOrOptions === "string" && eventHubNameOrOptions)) { throw new TypeError( `Either provide "eventHubName" or the "connectionString": "${hostOrConnectionString}", must contain "EntityPath=<your-event-hub-name>".` ); } if (parsedCS.eventHubName && typeof eventHubNameOrOptions === "string" && eventHubNameOrOptions && parsedCS.eventHubName !== eventHubNameOrOptions) { throw new TypeError( `The entity path "${parsedCS.eventHubName}" in connectionString: "${hostOrConnectionString}" doesn't match with eventHubName: "${eventHubNameOrOptions}".` ); } connectionString = hostOrConnectionString; if (typeof eventHubNameOrOptions !== "string") { config = import_eventhubConnectionConfig.EventHubConnectionConfig.create(connectionString); options = eventHubNameOrOptions; } else { const eventHubName = eventHubNameOrOptions; config = import_eventhubConnectionConfig.EventHubConnectionConfig.create(connectionString, eventHubName); options = credentialOrOptions; } const parsed = (0, import_connectionStringUtils.parseEventHubConnectionString)(connectionString); credential = (0, import_core_amqp.createSasTokenProvider)(parsed); } else { const eventHubName = eventHubNameOrOptions; let host = hostOrConnectionString; if ((0, import_core_auth.isNamedKeyCredential)(credentialOrOptions) || (0, import_core_auth.isSASCredential)(credentialOrOptions)) { credential = (0, import_core_amqp.createSasTokenProvider)(credentialOrOptions); } else { credential = credentialOrOptions; } if (!eventHubName) { throw new TypeError(`"eventHubName" is missing`); } if (!host.endsWith("/")) host += "/"; connectionString = `Endpoint=sb://${host};SharedAccessKeyName=defaultKeyName;SharedAccessKey=defaultKeyValue;EntityPath=${eventHubName}`; config = import_eventhubConnectionConfig.EventHubConnectionConfig.create(connectionString); } if (options?.customEndpointAddress) { import_eventhubConnectionConfig.EventHubConnectionConfig.setCustomEndpointAddress(config, options.customEndpointAddress); } import_core_amqp.ConnectionConfig.validate(config); return ConnectionContext.create(config, credential, options); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { ConnectionContext, createConnectionContext }); //# sourceMappingURL=connectionContext.js.map