Este é um aplicativo de demonstração e exemplo projetado para ser um sistema simples de bate-papo multiusuário baseado na web.
Ele fornece bate-papos em grupo persistentes, bate-papos privados de usuário para usuário, uma lista de usuários, detecção de inatividade (longe do teclado) e vários outros recursos.
Ele é baseado em diversas tecnologias do Azure, incluindo: Web PubSub, Static Web Apps e Table Storage
?? Observação. Este foi criado como um projeto pessoal, criado para auxiliar no aprendizado e na construção de algo interessante. O código vem com todas as advertências que você esperaria de tal projeto.
Metas:
Casos de uso e recursos principais:
Este é o principal frontend da web usado pelos usuários finais por meio do navegador.
A fonte para isso é encontrada em client/ e consiste em um aplicativo ES6 JS puro e estático, nenhum pacote ou Node.js é necessário. Ele foi escrito usando Vue.js como estrutura de suporte e Bulma como estrutura CSS.
Algumas notas:
client/js/app.js
mostra como criar um aplicativo Vue.js com componentes filhos usando esta abordagem. A maior parte da lógica do cliente está aqui.client/js/components/chat.js
é um componente Vue.js usado para hospedar cada guia de chat no aplicativo.auth/
especial fornecido por Static Web Apps é usado para conectar usuários e buscar seus detalhes de usuário, como userId.Este é o back-end, manipulando eventos de websocket de e para o Azure Web PubSub e fornecendo API REST para algumas operações.
A fonte para isso é encontrada em api/ e consiste em um aplicativo Node.js Azure Function. Ele se conecta ao Azure Table Storage para persistir bate-papo em grupo e dados do usuário (o Table Storage foi escolhido por ser simples e barato). Isso não está hospedado em um aplicativo de função do Azure autônomo, mas sim implantado no aplicativo Web estático como parte do suporte de API sem servidor
Existem quatro funções HTTP, todas atendidas a partir do caminho /api/
padrão
eventHandler
– receptor Webhook para eventos "upstream" enviados do serviço Azure Web PubSub, contém a maior parte da lógica do aplicativo. Não chamado diretamente pelo cliente, apenas Azure WebPub Sub.getToken
– Chamado pelo cliente para obter um token de acesso e uma URL para se conectar via WebSockets ao serviço Azure Web PubSub. Deve ser chamado com userId na consulta URL, por exemplo, GET /api/getToken?userId={user}
getUsers
- Retorna uma lista de usuários conectados, observe que a rota para esta função é /api/users
getChats
– Retorna uma lista de chats em grupo ativos, observe que a rota para esta função é /api/chats
O estado é tratado com state.js
, que é um módulo ES6 que exporta funções que suportam CRUD de estado para usuários e chats. Este módulo realiza toda a interação com as Tabelas do Azure e fornece uma interface relativamente transparente, para que um back-end de armazenamento diferente possa ser trocado.
Há um fluxo de mensagens bidirecional entre clientes e o servidor por meio do Azure Web PubSub e manipuladores de eventos
O subprotocolo json.webpubsub.azure.v1 é usado em vez de WebSockets básicos, o que fornece vários recursos: usuários podem ser adicionados a grupos, clientes podem enviar eventos personalizados (usando type: event
) e também enviar mensagens diretamente para outros clientes sem passar pelo servidor (usando type: sendToGroup
)
Notas:
Eventos e bate-papo são enviados usando o subprotocolo json.webpubsub.azure.v1
As mensagens de bate-papo enviadas do cliente usam sendToGroup
e uma carga JSON personalizada com três campos message
, fromUserId
e fromUserName
, essas mensagens são retransmitidas de cliente para cliente pelo Azure Web PubSub, o servidor nunca é notificado sobre elas:
{
type : 's endToGroup ',
group : < chatId > ,
dataType : 'j son ',
data : {
message : < message text > ,
fromUserId : < userId > ,
fromUserName : < userName > ,
},
}
Os eventos destinados ao servidor back-end são enviados como mensagens WebSocket do cliente por meio do mesmo subprotocolo do tipo event
e de um subtipo específico do aplicativo, por exemplo
{
type : 'e vent ',
event : 'j oinChat ',
dataType : 't ext ',
data : < chatId > ,
}
Os tipos de eventos são:
A função eventHandler
da API de back-end possui casos para cada um desses eventos de usuário, juntamente com manipuladores para eventos de sistema de conexão e desconexão.
As mensagens enviadas do servidor têm uma carga útil específica do aplicativo Chatr personalizado, como segue:
{
chatEvent : < eventType > ,
data : < JSON object type dependant >
}
Onde eventType
é um dos seguintes:
O código do cliente em client/js/app.js
trata essas mensagens conforme elas são recebidas pelo cliente e reage de acordo.
O plano deste projeto era usar Azure Web PubSub e Azure Static Web Apps e hospedar o componente do lado do servidor como um conjunto de funções sem servidor no suporte da API Static Web Apps (que na verdade é o Azure Functions nos bastidores). O Azure Static Web Apps foi selecionado porque tem suporte incrível para login e autenticação de usuário sem código e sem configuração, que eu queria aproveitar.
Alguns comentários sobre esta abordagem:
webPubSubConnection
. Para enviar mensagens de volta ao Web PubSub, o SDK do servidor pode simplesmente ser usado no código de função em vez de usar a ligação de saída webPubSub
. O estado nas tabelas do Azure consiste em duas tabelas (coleções) denominadas chats
e users
Como cada chat contém objetos aninhados dentro do campo de membros, cada chat é armazenado como uma string JSON em um campo chamado data
. O PartitionKey não é usado e codificado em uma string "chatr". O RowKey e o campo id dentro do objeto de dados são iguais.
Exemplo de entidade de dados 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 "
}
Os usuários são armazenados como entidades com os campos (colunas) descritos abaixo. Como não há campos aninhados, não há necessidade de codificar como uma string JSON. Novamente, o PartitionKey não é usado e codificado em uma string "chatr".
userId
retornado do endpoint de autenticação de aplicativos Web estáticostwitter
, aad
ou github
Veja makefile
$ 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
A implantação é um pouco complexa devido ao número de componentes e à configuração entre eles. A deploy
do alvo makefile deve implantar tudo para você em uma única etapa usando modelos Bicep encontrados na pasta deploy/
Consulte o leia-me na pasta de implantação para obter detalhes e instruções
Isto é possível, mas requer um pouco de esforço, uma vez que o serviço Azure Web PubSub precisa de ser capaz de chamar o ponto final HTTP na sua máquina de localização, pelo que foi utilizado um túnel.
Ao executar localmente, a CLI do Static Web Apps é usada e isso fornece um ponto final de autenticação de usuário falso para nós.
Um resumo das etapas é:
api/local.settings.sample.json
para api/local.settings.json
e edite os valores de configurações necessários.loophole http 7071 --hostname chatr
https://{{hostname-of-tunnel-service}}/api/eventHandler
make run
http://localhost:4280/index.html