@azure/event-hubs
Version:
Azure Event Hubs SDK for JS.
351 lines (350 loc) • 15.3 kB
JavaScript
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