Dies ist eine Demonstrations- und Beispielanwendung, die als einfaches webbasiertes Chat-System für mehrere Benutzer konzipiert ist.
Es bietet dauerhafte Gruppenchats, private Chats von Benutzer zu Benutzer, eine Benutzerliste, Erkennung von Leerlaufzeiten (außerhalb der Tastatur) und mehrere andere Funktionen.
Es basiert auf mehreren Azure-Technologien, darunter: Web PubSub, Static Web Apps und Table Storage
?? Notiz. Dies wurde als persönliches Projekt erstellt, um das Lernen zu unterstützen und gleichzeitig etwas Interessantes aufzubauen. Der Code enthält alle Einschränkungen, die Sie von einem solchen Projekt erwarten können.
Ziele:
Anwendungsfälle und Hauptfunktionen:


Dies ist das Haupt-Web-Frontend, das von Endbenutzern über den Browser verwendet wird.
Die Quelle hierfür befindet sich in client/ und besteht aus einer statischen, eigenständigen reinen ES6-JS-Anwendung, es ist keine Bündelung oder Node.js erforderlich. Es wurde mit Vue.js als unterstützendem Framework und Bulma als CSS-Framework geschrieben.
Einige Anmerkungen:
client/js/app.js zeigt, wie Sie mit diesem Ansatz eine Vue.js-App mit untergeordneten Komponenten erstellen. Der Großteil der Client-Logik befindet sich hier.client/js/components/chat.js ist eine Vue.js-Komponente, die zum Hosten jeder Chat-Registerkarte in der Anwendung verwendet wird.auth/ -Endpunkt, der von Static Web Apps bereitgestellt wird, wird zum Anmelden von Benutzern und zum Abrufen ihrer Benutzerdetails, wie z. B. Benutzer-ID, verwendet.Dies ist das Backend, das Websocket-Ereignisse von und zu Azure Web PubSub verarbeitet und die REST-API für einige Vorgänge bereitstellt.
Die Quelle hierfür befindet sich in api/ und besteht aus einer Node.js Azure Function App. Es stellt eine Verbindung zu Azure Table Storage her, um Gruppenchat und Benutzerdaten beizubehalten (Table Storage wurde ausgewählt, weil es einfach und kostengünstig ist). Dies wird nicht in einer eigenständigen Azure-Funktions-App gehostet, sondern im Rahmen der serverlosen API-Unterstützung in der statischen Web-App bereitgestellt
Es gibt vier HTTP-Funktionen, die alle über den Standardpfad /api/ bereitgestellt werden
eventHandler – Webhook-Empfänger für „Upstream“-Ereignisse, die vom Azure Web PubSub-Dienst gesendet werden, enthält den Großteil der Anwendungslogik. Wird nicht direkt vom Client aufgerufen, sondern nur Azure WebPub Sub.getToken – Wird vom Client aufgerufen, um ein Zugriffstoken und eine URL für die Verbindung über WebSockets mit dem Azure Web PubSub-Dienst abzurufen. Muss mit userId in der URL-Abfrage aufgerufen werden, z. B. GET /api/getToken?userId={user}getUsers – Gibt eine Liste der angemeldeten Benutzer zurück. Beachten Sie, dass die Route für diese Funktion /api/users lautetgetChats – Gibt eine Liste aktiver Gruppenchats zurück. Beachten Sie, dass die Route für diese Funktion /api/chats lautet Der Status wird mit state.js verwaltet, einem ES6-Modul, das Funktionen exportiert, die State CRUD für Benutzer und Chats unterstützen. Dieses Modul führt die gesamte Interaktion mit Azure Tables durch und bietet eine relativ transparente Schnittstelle, sodass ein anderes Speicher-Backend ausgetauscht werden könnte.
Es gibt einen bidirektionalen Nachrichtenfluss zwischen Clients und dem Server über Azure Web PubSub und Ereignishandler
Anstelle grundlegender WebSockets wird das Unterprotokoll json.webpubsub.azure.v1 verwendet. Dies bietet eine Reihe von Funktionen: Benutzer können zu Gruppen hinzugefügt werden, Clients können benutzerdefinierte Ereignisse senden (unter Verwendung von type: event ) und Nachrichten auch direkt an andere Clients senden ohne über den Server zu gehen (mit type: sendToGroup )
Hinweise:
Ereignisse und Chats werden über das Unterprotokoll json.webpubsub.azure.v1 gesendet
Vom Client gesendete Chatnachrichten verwenden sendToGroup und eine benutzerdefinierte JSON-Nutzlast mit den drei Feldern message , fromUserId und fromUserName . Diese Nachrichten werden von Azure Web PubSub von Client zu Client weitergeleitet, der Server wird darüber nie benachrichtigt:
{
type : 's endToGroup ',
group : < chatId > ,
dataType : 'j son ',
data : {
message : < message text > ,
fromUserId : < userId > ,
fromUserName : < userName > ,
},
} Für den Backend-Server bestimmte Ereignisse werden als WebSocket-Nachrichten vom Client über dasselbe Unterprotokoll mit dem event und einem anwendungsspezifischen Untertyp gesendet, z. B
{
type : 'e vent ',
event : 'j oinChat ',
dataType : 't ext ',
data : < chatId > ,
}Die Arten von Veranstaltungen sind:
Die Backend-API-Funktion eventHandler verfügt über Fälle für jedes dieser Benutzerereignisse sowie Handler für Verbindungs- und Trennungssystemereignisse.
Vom Server gesendete Nachrichten haben eine benutzerdefinierte Chatr-App-spezifische Nutzlast wie folgt:
{
chatEvent : < eventType > ,
data : < JSON object type dependant >
} Dabei ist eventType einer von:
Der Client-Code in client/js/app.js verarbeitet diese Nachrichten, sobald sie vom Client empfangen werden, und reagiert entsprechend.
Der Plan dieses Projekts bestand darin, Azure Web PubSub und Azure Static Web Apps zu verwenden und die serverseitige Komponente als eine Reihe serverloser Funktionen in der Static Web Apps API-Unterstützung zu hosten (die eigentlich Azure Functions unter der Haube sind). Azure Static Web Apps wurde ausgewählt, weil es eine hervorragende Unterstützung für die Anmeldung und Authentifizierung von Benutzern ohne Code und Konfiguration bietet, die ich nutzen wollte.
Einige Kommentare zu diesem Ansatz:
webPubSubConnection Bindung zu verwenden. Zum Zurücksenden von Nachrichten an Web PubSub kann das Server-SDK einfach innerhalb des Funktionscodes verwendet werden, anstatt die webPubSub Ausgabebindung zu verwenden. Der Status in Azure Tables besteht aus zwei Tabellen (Sammlungen) mit den Namen chats und users
Da jeder Chat verschachtelte Objekte im Mitgliederfeld enthält, wird jeder Chat als JSON-Zeichenfolge in einem Feld namens data gespeichert. Der PartitionKey wird nicht verwendet und ist fest in die Zeichenfolge „chatr“ codiert. Der RowKey und das ID-Feld im Datenobjekt sind identisch.
Beispiel einer Chat-Datenentität
{
"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 "
}Benutzer werden als Entitäten mit den unten beschriebenen Feldern (Spalten) gespeichert. Da es keine verschachtelten Felder gibt, ist keine Codierung als JSON-String erforderlich. Auch hier wird der PartitionKey nicht verwendet und fest in eine Zeichenfolge „chatr“ codiert.
userId -Feldtwitter , aad oder github angemeldet hat?Siehe 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
Die Bereitstellung ist aufgrund der Anzahl der Komponenten und der Konfiguration zwischen ihnen etwas komplex. Das Makefile-Ziel deploy sollte alles in einem einzigen Schritt für Sie bereitstellen, indem es die Bicep-Vorlagen verwendet, die sich im Ordner „deploy/ “ befinden
Einzelheiten und Anweisungen finden Sie in der Readme-Datei im Bereitstellungsordner
Dies ist möglich, erfordert jedoch ein wenig Aufwand, da der Azure Web PubSub-Dienst in der Lage sein muss, den HTTP-Endpunkt auf Ihrem Standortcomputer aufzurufen, sodass ein Tunnel eingerichtet wurde.
Bei der lokalen Ausführung wird die Static Web Apps-CLI verwendet, die uns einen gefälschten Benutzerauthentifizierungsendpunkt bietet.
Eine Zusammenfassung der Schritte ist:
api/local.settings.sample.json nach api/local.settings.json und bearbeiten Sie die erforderlichen Einstellungswerte.loophole http 7071 --hostname chatrhttps://{{hostname-of-tunnel-service}}/api/eventHandlermake runhttp://localhost:4280/index.html