UNPKG

@azure/web-pubsub

Version:
367 lines 17.1 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { RestError } from "@azure/core-rest-pipeline"; import { GeneratedClient } from "./generated/generatedClient.js"; import { WebPubSubGroupImpl } from "./groupClient.js"; import { isTokenCredential } from "@azure/core-auth"; import { webPubSubKeyCredentialPolicy } from "./webPubSubCredentialPolicy.js"; import { tracingClient } from "./tracing.js"; import { logger } from "./logger.js"; import { parseConnectionString } from "./parseConnectionString.js"; import jwt from "jsonwebtoken"; import { getPayloadForMessage } from "./utils.js"; import { webPubSubReverseProxyPolicy } from "./reverseProxyPolicy.js"; /** * Client for connecting to a Web PubSub hub */ export class WebPubSubServiceClient { constructor(endpointOrConnectionString, credsOrHubName, hubNameOrOpts, opts) { var _a, _b, _c, _d, _e, _f; /** * The Web PubSub API version being used by this client */ this.apiVersion = "2024-01-01"; // unpack constructor arguments if (typeof credsOrHubName === "object") { this.endpoint = endpointOrConnectionString; this.hubName = hubNameOrOpts; this.clientOptions = opts; this.credential = credsOrHubName; } else { const parsedCs = parseConnectionString(endpointOrConnectionString); this.endpoint = parsedCs.endpoint; this.credential = parsedCs.credential; this.hubName = credsOrHubName; this.clientOptions = hubNameOrOpts; } const internalPipelineOptions = Object.assign(Object.assign(Object.assign({}, this.clientOptions), { apiVersion: this.apiVersion, loggingOptions: { additionalAllowedHeaderNames: (_b = (_a = this.clientOptions) === null || _a === void 0 ? void 0 : _a.loggingOptions) === null || _b === void 0 ? void 0 : _b.additionalAllowedHeaderNames, additionalAllowedQueryParameters: (_d = (_c = this.clientOptions) === null || _c === void 0 ? void 0 : _c.loggingOptions) === null || _d === void 0 ? void 0 : _d.additionalAllowedQueryParameters, logger: logger.info, }, }), (isTokenCredential(this.credential) ? { credential: this.credential, credentialScopes: ["https://webpubsub.azure.com/.default"], } : {})); this.client = new GeneratedClient(this.endpoint, internalPipelineOptions); if (!isTokenCredential(this.credential)) { this.client.pipeline.addPolicy(webPubSubKeyCredentialPolicy(this.credential)); } if ((_e = this.clientOptions) === null || _e === void 0 ? void 0 : _e.reverseProxyEndpoint) { this.client.pipeline.addPolicy(webPubSubReverseProxyPolicy((_f = this.clientOptions) === null || _f === void 0 ? void 0 : _f.reverseProxyEndpoint)); } } /** * Get a client for a group * @param groupName - The name of the group to connect to. */ group(groupName) { return new WebPubSubGroupImpl(this.client, this.hubName, groupName); } async sendToAll(message, options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.sendToAll", options, (updatedOptions) => { const { contentType, payload } = getPayloadForMessage(message, updatedOptions); return this.client.webPubSub.sendToAll(this.hubName, contentType, payload, updatedOptions); }); } async sendToUser(username, message, options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.sendToUser", options, (updatedOptions) => { const { contentType, payload } = getPayloadForMessage(message, updatedOptions); return this.client.webPubSub.sendToUser(this.hubName, username, contentType, payload, updatedOptions); }); } async sendToConnection(connectionId, message, options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.sendToConnection", options, (updatedOptions) => { const { contentType, payload } = getPayloadForMessage(message, updatedOptions); return this.client.webPubSub.sendToConnection(this.hubName, connectionId, contentType, payload, updatedOptions); }); } /** * Check if a specific connection is connected to this hub * * @param connectionId - Connection id to check * @param options - Additional options */ async connectionExists(connectionId, options = {}) { let response; function onResponse(rawResponse, flatResponse) { response = rawResponse; if (options.onResponse) { options.onResponse(rawResponse, flatResponse); } } return tracingClient.withSpan("WebPubSubServiceClient.connectionExists", options, async (updatedOptions) => { await this.client.webPubSub.connectionExists(this.hubName, connectionId, Object.assign(Object.assign({}, updatedOptions), { onResponse })); if (response.status === 200) { return true; } else if (response.status === 404) { return false; } else { // this is sad - wish this was handled by autorest. throw new RestError(response.bodyAsText, { statusCode: response === null || response === void 0 ? void 0 : response.status, request: response === null || response === void 0 ? void 0 : response.request, response: response, }); } }); } /** * Close a specific connection to this hub * * @param connectionId - Connection id to close * @param options - Additional options */ async closeConnection(connectionId, options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.closeConnection", options, (updatedOptions) => { return this.client.webPubSub.closeConnection(this.hubName, connectionId, updatedOptions); }); } /** * Close all connections to this hub * * @param options - Additional options */ async closeAllConnections(options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.closeAllConnections", options, (updatedOptions) => { return this.client.webPubSub.closeAllConnections(this.hubName, updatedOptions); }); } /** * Close all connections with the given user id * * @param user - User id to close * @param options - Additional options */ async closeUserConnections(userId, options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.closeUserConnections", options, (updatedOptions) => { return this.client.webPubSub.closeUserConnections(this.hubName, userId, updatedOptions); }); } /** * Remove a specific user from all groups they are joined to * @param userId - The user id to remove from all groups * @param options - Additional options */ async removeUserFromAllGroups(userId, options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.removeUserFromAllGroups", options, (updatedOptions) => { return this.client.webPubSub.removeUserFromAllGroups(this.hubName, userId, updatedOptions); }); } /** * Remove a specific connection from all groups they are joined to * @param connectionId - The connection id to remove from all groups * @param options - Additional options */ async removeConnectionFromAllGroups(connectionId, options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.removeConnectionFromAllGroups", options, (updatedOptions) => { return this.client.webPubSub.removeConnectionFromAllGroups(this.hubName, connectionId, updatedOptions); }); } /** * Add filtered connections to multiple groups * @param groups - A list of groups which target connections will be added into * @param filter - An OData filter which target connections satisfy * @param options - Additional options */ async addConnectionsToGroups(groups, filter, options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.addConnectionsToGroups", options, (updatedOptions) => { return this.client.webPubSub.addConnectionsToGroups(this.hubName, { groups: groups, filter: filter, }, updatedOptions); }); } /** * Remove filtered connections from multiple groups * @param groups - A list of groups which target connections will be removed from * @param filter - An OData filter which target connections satisfy * @param options - Additional options */ async removeConnectionsFromGroups(groups, filter, options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.removeConnectionsFromGroups", options, (updatedOptions) => { return this.client.webPubSub.removeConnectionsFromGroups(this.hubName, { groups: groups, filter: filter, }, updatedOptions); }); } /** * Check if a particular group exists (i.e. has active connections). * * @param groupName - The group name to check for * @param options - Additional options */ async groupExists(groupName, options = {}) { let response; function onResponse(rawResponse, flatResponse) { response = rawResponse; if (options.onResponse) { options.onResponse(rawResponse, flatResponse); } } return tracingClient.withSpan("WebPubSubServiceClient.groupExists", options, async (updatedOptions) => { await this.client.webPubSub.groupExists(this.hubName, groupName, Object.assign(Object.assign({}, updatedOptions), { onResponse })); if (response.status === 200) { return true; } else if (response.status === 404) { return false; } else { throw new RestError(response.bodyAsText, { statusCode: response === null || response === void 0 ? void 0 : response.status, request: response === null || response === void 0 ? void 0 : response.request, response: response, }); } }); } /** * Check if a particular user is connected to this hub. * * @param username - The user name to check for * @param options - Additional options */ async userExists(username, options = {}) { let response; function onResponse(rawResponse, flatResponse) { response = rawResponse; if (options.onResponse) { options.onResponse(rawResponse, flatResponse); } } return tracingClient.withSpan("WebPubSubServiceClient.userExists", options, async (updatedOptions) => { await this.client.webPubSub.userExists(this.hubName, username, Object.assign(Object.assign({}, updatedOptions), { onResponse })); if (response.status === 200) { return true; } else if (response.status === 404) { return false; } else { // this is sad - wish this was handled by autorest. throw new RestError(response.bodyAsText, { statusCode: response === null || response === void 0 ? void 0 : response.status, request: response === null || response === void 0 ? void 0 : response.request, response: response, }); } }); } /** * Grant permissions to a connection * * @param connectionId - The connection id to grant permissions to * @param Permission - The permission to grant * @param options - Additional options */ async grantPermission(connectionId, permission, options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.grantPermission", options, (updatedOptions) => { return this.client.webPubSub.grantPermission(this.hubName, permission, connectionId, updatedOptions); }); } /** * Revoke permissions from a connection * * @param connectionId - The connection id to revoke permissions from * @param Permission - The permission to revoke * @param options - Additional options */ async revokePermission(connectionId, permission, options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.revokePermission", options, (updatedOptions) => { return this.client.webPubSub.revokePermission(this.hubName, permission, connectionId, updatedOptions); }); } /** * Check if the connection has the specified permission * * @param connectionId - The connection id to check permission * @param Permission - The permission to check * @param options - Additional options */ async hasPermission(connectionId, permission, options = {}) { let response; function onResponse(rawResponse, flatResponse) { response = rawResponse; if (options.onResponse) { options.onResponse(rawResponse, flatResponse); } } return tracingClient.withSpan("WebPubSubServiceClient.hasPermission", options, async (updatedOptions) => { await this.client.webPubSub.checkPermission(this.hubName, permission, connectionId, Object.assign(Object.assign({}, updatedOptions), { onResponse })); if (response.status === 200) { return true; } else if (response.status === 404) { return false; } else { // this is sad - wish this was handled by autorest. throw new RestError(response.bodyAsText, { statusCode: response === null || response === void 0 ? void 0 : response.status, request: response === null || response === void 0 ? void 0 : response.request, response: response, }); } }); } /** * Generate a token for a client to connect to the Azure Web PubSub service. * * @param options - Additional options */ async getClientAccessToken(options = {}) { return tracingClient.withSpan("WebPubSubServiceClient.getClientAccessToken", options, async (updatedOptions) => { const endpoint = this.endpoint.endsWith("/") ? this.endpoint : this.endpoint + "/"; const clientEndpoint = endpoint.replace(/(http)(s?:\/\/)/gi, "ws$2"); const clientProtocol = updatedOptions.clientProtocol; let clientPath = `client/hubs/${this.hubName}`; switch (clientProtocol) { case "mqtt": clientPath = `clients/mqtt/hubs/${this.hubName}`; break; case "socketio": clientPath = `clients/socketio/hubs/${this.hubName}`; } const baseUrl = clientEndpoint + clientPath; let token; if (isTokenCredential(this.credential)) { const response = await this.client.webPubSub.generateClientToken(this.hubName, Object.assign(Object.assign({}, updatedOptions), { clientType: clientProtocol })); token = response.token; } else { const key = this.credential.key; const audience = endpoint + clientPath; const payload = { role: updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.roles, "webpubsub.group": updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.groups, }; const signOptions = { audience: audience, expiresIn: (updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.expirationTimeInMinutes) === undefined ? "1h" : `${updatedOptions.expirationTimeInMinutes}m`, algorithm: "HS256", }; if (updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.userId) { signOptions.subject = updatedOptions === null || updatedOptions === void 0 ? void 0 : updatedOptions.userId; } token = jwt.sign(payload, key, signOptions); } return { token, baseUrl, url: `${baseUrl}?access_token=${token}`, }; }); } } //# sourceMappingURL=hubClient.js.map