@azure/web-pubsub
Version:
Azure client library for Azure Web PubSub
367 lines • 17.1 kB
JavaScript
// 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