Esta es una aplicación de demostración y muestra diseñada para ser un sencillo sistema de chat multiusuario basado en web.
Proporciona chats grupales persistentes, chats privados de usuario a usuario, una lista de usuarios, detección de inactividad (lejos del teclado) y varias otras funciones.
Se basa en varias tecnologías de Azure, incluidas: Web PubSub, aplicaciones web estáticas y almacenamiento de tablas.
?? Nota. Esto fue creado como un proyecto personal, creado para ayudar a aprender mientras se construye algo interesante. El código incluye todas las advertencias que cabe esperar de un proyecto de este tipo.
Objetivos:
Casos de uso y características clave:
Esta es la interfaz web principal utilizada por los usuarios finales a través del navegador.
La fuente para esto se encuentra en client/ y consiste en una aplicación ES6 JS pura, estática e independiente, no se requiere agrupación ni Node.js. Está escrito utilizando Vue.js como marco de soporte y Bulma como marco CSS.
Algunas notas:
client/js/app.js
muestra cómo crear una aplicación Vue.js con componentes secundarios utilizando este enfoque. La mayor parte de la lógica del cliente está aquí.client/js/components/chat.js
es un componente de Vue.js que se utiliza para alojar cada pestaña de chat en la aplicación.auth/
proporcionado por Static Web Apps se utiliza para iniciar sesión en los usuarios y obtener sus detalles de usuario, como el ID de usuario.Este es el backend, que maneja eventos websocket hacia y desde Azure Web PubSub y proporciona API REST para algunas operaciones.
La fuente de esto se encuentra en api/ y consta de una aplicación de función Azure Node.js. Se conecta a Azure Table Storage para conservar el chat grupal y los datos del usuario (se eligió Table Storage porque es simple y económico). Esto no está alojado en una aplicación de funciones de Azure independiente, sino que se implementa en la aplicación web estática como parte de su compatibilidad con API sin servidor.
Hay cuatro funciones HTTP, todas servidas desde la ruta /api/
predeterminada
eventHandler
: receptor de webhook para eventos "ascendentes" enviados desde el servicio Azure Web PubSub, contiene la mayor parte de la lógica de la aplicación. No lo llama directamente el cliente, solo Azure WebPub Sub.getToken
: lo llama el cliente para obtener un token de acceso y una URL para conectarse a través de WebSockets al servicio Azure Web PubSub. Debe llamarse con userId en la consulta URL, por ejemplo, GET /api/getToken?userId={user}
getUsers
: devuelve una lista de usuarios registrados; tenga en cuenta que la ruta para esta función es /api/users
getChats
: devuelve una lista de chats grupales activos; tenga en cuenta que la ruta para esta función es /api/chats
El estado se maneja con state.js
, que es un módulo ES6 que exporta funciones que admiten CRUD de estado para usuarios y chats. Este módulo lleva a cabo toda la interacción con Azure Tables y proporciona una interfaz relativamente transparente, por lo que se podría intercambiar un backend de almacenamiento diferente.
Hay un flujo de mensajes bidireccional entre los clientes y el servidor a través de Azure Web PubSub y controladores de eventos.
Se utiliza el subprotocolo json.webpubsub.azure.v1 en lugar de WebSockets básicos, lo que proporciona una serie de características: los usuarios pueden agregarse a grupos, los clientes pueden enviar eventos personalizados (usando type: event
) y también enviar mensajes directamente a otros clientes. sin pasar por el servidor (usando type: sendToGroup
)
Notas:
Los eventos y el chat se envían mediante el subprotocolo json.webpubsub.azure.v1
Los mensajes de chat enviados desde el cliente usan sendToGroup
y una carga útil JSON personalizada con tres campos message
, fromUserId
y fromUserName
, estos mensajes son retransmitidos de cliente a cliente por Azure Web PubSub, el servidor nunca recibe notificaciones sobre ellos:
{
type : 's endToGroup ',
group : < chatId > ,
dataType : 'j son ',
data : {
message : < message text > ,
fromUserId : < userId > ,
fromUserName : < userName > ,
},
}
Los eventos destinados al servidor backend se envían como mensajes WebSocket desde el cliente a través del mismo subprotocolo con el tipo event
y un subtipo específico de la aplicación, por ejemplo
{
type : 'e vent ',
event : 'j oinChat ',
dataType : 't ext ',
data : < chatId > ,
}
Los tipos de eventos son:
La función eventHandler
de la API backend tiene casos para cada uno de estos eventos de usuario, junto con controladores para eventos del sistema de conexión y desconexión.
Los mensajes enviados desde el servidor tienen una carga útil específica de la aplicación Chatr personalizada de la siguiente manera:
{
chatEvent : < eventType > ,
data : < JSON object type dependant >
}
Donde eventType
es uno de:
El código de cliente en client/js/app.js
maneja estos mensajes a medida que los recibe el cliente y reacciona en consecuencia.
El plan de este proyecto era utilizar Azure Web PubSub y Azure Static Web Apps , y alojar el componente del lado del servidor como un conjunto de funciones sin servidor en el soporte de API de Static Web Apps (que de hecho son Azure Functions bajo el capó). Se seleccionó Azure Static Web Apps porque tiene un soporte increíble para el inicio de sesión y la autenticación de usuarios sin código ni configuración, lo cual quería aprovechar.
Algunos comentarios sobre este enfoque:
webPubSubConnection
. Para enviar mensajes de regreso a Web PubSub, el SDK del servidor simplemente se puede usar dentro del código de función en lugar de usar el enlace de salida webPubSub
. El estado en Azure Tables consta de dos tablas (colecciones) denominadas chats
y users
Como cada chat contiene objetos anidados dentro del campo de miembros, cada chat se almacena como una cadena JSON en un campo llamado data
. La PartitionKey no se utiliza y está codificada en una cadena "chatr". La RowKey y el campo id dentro del objeto de datos son los mismos.
Ejemplo de una entidad de datos de chat
{
"id" : " eab4b030-1a3d-499a-bd89-191578395910 " ,
"name" : " This is a group chat " ,
"members" : {
"0987654321" : {
"userId" : " 0987654321 " ,
"userName" : " Another Guy "
},
"1234567890" : {
"userId" : " 1234567890 " ,
"userName" : " Ben "
}
},
"owner" : " 1234567890 "
}
Los usuarios se almacenan como entidades con los campos (columnas) que se describen a continuación. Como no hay campos anidados, no es necesario codificarlos como una cadena JSON. Nuevamente, PartitionKey no se usa y está codificada en una cadena "chatr".
userId
devuelto desde el punto final de autenticación de Static Web Appstwitter
, aad
o github
Ver archivo MAKE
$ make
help This help message
lint ? Lint & format, will not fix but sets exit code on error
lint-fix Lint & format, will try to fix errors and modify code
run ? Run server locally using Static Web Apps CLI
clean ? Clean up project
deploy Deploy everything to Azure using Bicep
tunnel ? Start loophole tunnel to expose localhost
La implementación es ligeramente compleja debido a la cantidad de componentes y la configuración entre ellos. La deploy
de destino del archivo MAKE debe implementar todo por usted en un solo paso utilizando las plantillas de Bicep que se encuentran en la carpeta implementar/
Consulte el archivo Léame en la carpeta de implementación para obtener detalles e instrucciones.
Esto es posible, pero requiere un poco de esfuerzo, ya que el servicio Azure Web PubSub debe poder llamar al punto final HTTP en su máquina de ubicación, por lo que se ha empleado un túnel.
Cuando se ejecuta localmente, se utiliza la CLI de Static Web Apps y esto nos proporciona un punto final de autenticación de usuario falso.
Un resumen de los pasos es:
api/local.settings.sample.json
a api/local.settings.json
y edite los valores de configuración requeridos.loophole http 7071 --hostname chatr
https://{{hostname-of-tunnel-service}}/api/eventHandler
make run
http://localhost:4280/index.html