Controladores de CloudEvents de Azure Web PubSub para Express

El servicio Azure Web PubSub es un servicio administrado por Azure que ayuda a los desarrolladores a crear fácilmente aplicaciones web con características en tiempo real y patrón de publicación y suscripción. Cualquier escenario que requiera mensajería de publicación y suscripción en tiempo real entre el servidor y los clientes o entre clientes puede usar el servicio Azure Web PubSub. Las características tradicionales en tiempo real que a menudo requieren sondeo desde el servidor o el envío de solicitudes HTTP también pueden usar el servicio Azure Web PubSub.

Cuando se conecta una conexión WebSocket, el servicio Web PubSub transforma el ciclo de vida de la conexión y los mensajes en eventos en formato CloudEvents. Esta biblioteca proporciona un middleware rápido para controlar eventos que representan el ciclo de vida y los mensajes de la conexión de WebSocket, como se muestra en el diagrama siguiente:

Cloudevents

Los detalles sobre los términos utilizados aquí se describen en la sección de conceptos clave .

Código fuente | Paquete (NPM) | Documentación | Documentación | del productoMuestras

Cómo empezar

Entornos admitidos actualmente

Prerequisites

1. Instalar el @azure/web-pubsub-express paquete

npm install @azure/web-pubsub-express

2. Crear un WebPubSubEventHandler

import { WebPubSubEventHandler } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat");

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Conceptos clave

Conexión

Una conexión, también conocida como cliente o conexión cliente, representa una conexión WebSocket individual conectada al servicio Web PubSub. Cuando se conecta con éxito, el servicio Web PubSub asigna un ID de conexión único a esta conexión.

Hub

Un concentrador es un concepto lógico para un conjunto de conexiones de cliente. Normalmente usas un hub para un solo propósito, por ejemplo, un hub de chat o un hub de notificaciones. Cuando se crea una conexión de cliente, se conecta a un centro y, durante su duración, pertenece a ese centro. Diferentes aplicaciones pueden compartir un servicio de Azure Web PubSub mediante el uso de nombres de centros de conectividad diferentes.

Grupo

Un grupo es un subconjunto de conexiones al centro. Puede agregar una conexión de cliente a un grupo o quitarla de este cuando quiera. Por ejemplo, cuando un cliente se une a una sala de chat o sale de ella, dicha sala puede considerarse un grupo. Un cliente puede unirse a varios grupos, y un grupo puede contener varios clientes.

User

Las conexiones a Web PubSub pueden pertenecer a un usuario. Un usuario puede tener varias conexiones, por ejemplo, cuando está conectado a través de varios dispositivos o distintas pestañas del explorador.

Eventos de cliente

Los eventos se crean durante el ciclo de vida de una conexión con el cliente. Por ejemplo, una simple conexión cliente WebSocket crea un connect evento cuando intenta conectarse al servicio, un connected evento cuando se conecta con éxito al servicio, un message evento cuando envía mensajes al servicio y un disconnected evento cuando se desconecta del servicio.

Controlador de eventos

El gestor de eventos contiene la lógica para gestionar los eventos del cliente. El gestor de eventos debe registrarse y configurarse en el servicio a través del portal o de CLI de Azure de antemano. El lugar donde se aloja la lógica del gestor de eventos se considera generalmente el lado del servidor.

Ejemplos

Gestionar la connect solicitud y la asignación de <userId>

import { WebPubSubEventHandler } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  handleConnect: (req, res) => {
    // auth the connection and set the userId of the connection
    res.success({
      userId: "<userId>",
    });
  },
  allowedEndpoints: ["https://<yourAllowedService>.webpubsub.azure.com"],
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Gestiona la connect solicitud y rechaza la conexión si falla la autenticación

import { WebPubSubEventHandler } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  handleConnect: (req, res) => {
    // auth the connection and reject the connection if auth failed
    res.fail(401, "Unauthorized");
    // the following method is also a valid approach
    // res.failWith({ code: 401, detail: "Unauthorized" });
  },
  allowedEndpoints: ["https://<yourAllowedService>.webpubsub.azure.com"],
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Gestiona la connected solicitud

import { WebPubSubEventHandler } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  onConnected: (connectedRequest) => {
    // Your onConnected logic goes here
  },
  allowedEndpoints: ["https://<yourAllowedService>.webpubsub.azure.com"],
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Gestiona la onGroupJoined solicitud

import { WebPubSubEventHandler } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  onGroupJoined: (groupJoinedRequest) => {
    console.log(
      `Connection ${groupJoinedRequest.context.connectionId} joined group ${groupJoinedRequest.group}`,
    );
  },
  allowedEndpoints: ["https://<yourAllowedService>.webpubsub.azure.com"],
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Gestiona la onGroupLeft solicitud

import { WebPubSubEventHandler } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  onGroupLeft: (groupLeftRequest) => {
    console.log(
      `Connection ${groupLeftRequest.context.connectionId} left group ${groupLeftRequest.group}`,
    );
  },
  allowedEndpoints: ["https://<yourAllowedService>.webpubsub.azure.com"],
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Gestiona la onDisconnected solicitud

import { WebPubSubEventHandler } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  onDisconnected: (disconnectedRequest) => {
    // Your onDisconnected logic goes here
  },
  allowedEndpoints: ["https://<yourAllowedService>.webpubsub.azure.com"],
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Gestiona la connect petición para mqtt y asignación <userId> y <mqtt> propiedades

import { WebPubSubEventHandler, MqttConnectRequest } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  handleConnect: (req, res) => {
    if (req.context.clientProtocol === "mqtt") {
      // return mqtt response when request is of MQTT kind
      // get connect request as mqtt request and print it
      const mqttRequest = req as MqttConnectRequest;
      console.log(mqttRequest);

      // auth the connection and return mqtt response
      res.success({
        userId: "user1",
        mqtt: { userProperties: [{ name: "a", value: "b" }] },
      });
    } else {
      res.success({
        userId: "user1",
      });
    }
  },
  allowedEndpoints: ["https://<yourAllowedService>.webpubsub.azure.com"],
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Gestiona la connect solicitud de mqtt y rechaza la conexión si la autenticación falla

import { WebPubSubEventHandler, MqttConnectRequest } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  handleConnect: (req, res) => {
    // auth the connection and reject the connection if auth failed
    if (req.context.clientProtocol === "mqtt") {
      // return mqtt error response when request is of MQTT kind
      // get connect request as mqtt request and print it
      const mqttRequest = req as MqttConnectRequest;
      console.log(mqttRequest);

      // auth the connection and return mqtt failure response
      res.fail(401, "Not Authorized");

      // Or use below method for more fine-grained control over the MQTT return code
      // res.failWith({ mqtt: { code: MqttV500ConnectReasonCode.NotAuthorized } });
    } else res.success();
  },
  allowedEndpoints: ["https://<yourAllowedService>.webpubsub.azure.com"],
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Gestiona la onDisconnected solicitud de MQTT

import { WebPubSubEventHandler, MqttDisconnectedRequest } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  onDisconnected: (disconnectedRequest) => {
    if (disconnectedRequest.context.clientProtocol === "mqtt") {
      // get disconnect request as mqtt request and print it
      const mqttRequest = disconnectedRequest as MqttDisconnectedRequest;
      console.log(mqttRequest.mqtt);
      // Your onDisconnected logic goes here
    } else {
      console.log(disconnectedRequest);
      // Your onDisconnected logic goes here
    }
  },
  allowedEndpoints: ["https://<yourAllowedService>.webpubsub.azure.com"],
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Permitir solo puntos de conexión especificados

import { WebPubSubEventHandler } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  allowedEndpoints: [
    "https://<yourAllowedService1>.webpubsub.azure.com",
    "https://<yourAllowedService2>.webpubsub.azure.com",
  ],
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Configurar la ruta de acceso del controlador de eventos personalizado

import { WebPubSubEventHandler } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  path: "/customPath1",
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  // Azure WebPubSub Upstream ready at http://localhost:3000/customPath1
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Establecimiento y lectura del estado de conexión

import { WebPubSubEventHandler } from "@azure/web-pubsub-express";
import express from "express";

const handler = new WebPubSubEventHandler("chat", {
  handleConnect(req, res) {
    // You can set the state for the connection, it lasts throughout the lifetime of the connection
    res.setState("calledTime", 1);
    res.success();
  },
  handleUserEvent(req, res) {
    const calledTime = req.context.states.calledTime++;
    console.log(calledTime);
    // You can also set the state here
    res.setState("calledTime", calledTime);
    res.success();
  },
});

const app = express();

app.use(handler.getMiddleware());

app.listen(3000, () =>
  console.log(`Azure WebPubSub Upstream ready at http://localhost:3000${handler.path}`),
);

Troubleshooting

Habilitación de registros

Habilitar el registro puede ayudar a descubrir información útil sobre errores. Para ver un registro de solicitudes y respuestas HTTP, establezca la variable de entorno AZURE_LOG_LEVEL en info.

export AZURE_LOG_LEVEL=verbose

Alternativamente, el registro puede activarse en tiempo de ejecución llamando a setLogLevel en el @azure/logger:

import { setLogLevel } from "@azure/logger";

setLogLevel("info");

Para obtener instrucciones más detalladas sobre cómo habilitar los registros, puede consultar los documentos del paquete de @azure/registrador.

Seguimiento dinámico

Use Live Trace desde el portal del servicio Web PubSub para ver el tráfico activo.

Pasos siguientes

Por favor, echa un vistazo al directorio samples para encontrar ejemplos detallados sobre cómo usar esta biblioteca.

Contributing

Si quieres contribuir a esta biblioteca, por favor lee la guía contribución para aprender más sobre cómo construir y probar el código.