Implementierung von Room Messaging Server, bei der ein bidirektionales RPC-Protokoll verwendet wird, um die Chat-ähnliche Kommunikation zu implementieren. Entwickelt, um allgemeine Probleme mit dem öffentlichen Netzwerk Messaging wie zuverlässige Lieferung, mehrere Verbindungen eines einzelnen Benutzer, Echtzeitberechtigungen und Präsenz zu behandeln. Die RPC-Anfragen beantragt die Verarbeitung und ein Raummeldungsformat über Hooks, sodass alles von einem Chatrooms-Server bis zu einer kollaborativen Anwendung mit einer komplexen Konfliktlösung implementiert werden kann. Zimmermeldungen können auch zur Erstellung öffentlicher APIs oder zur Tunnel -M2M -Kommunikation für IoT -Geräte verwendet werden.
Zuverlässige Raumnachrichten mit einem Server -Side -History -Speicher und einer Synchronisierungs -API.
Beliebiges Nachrichtenformat über nur eine Validierungsfunktion (Hook), wodurch benutzerdefinierte/heterogene Nachrichtenformate (einschließlich Binärdaten innerhalb von Nachrichten) ermöglicht werden.
Benutzerpräsenz-API pro Zimmer mit Benachrichtigungen.
Echtzeitraumerstellung und Benutzerverwaltungs-APIs pro Zimmer. Unterstützung für Blacklist- oder Whitelist -basierte Zugriffsmodi und eine optionale Administratorgruppe.
Nahlose Unterstützung mehrerer Benutzerverbindungen von verschiedenen Entwicklungen zu einer Serviceinstanz.
Als staatenloser Microservice geschrieben, verwendet Redis (unterstützt auch Cluster -Konfigurationen) als Statusspeicher und kann bei Bedarf horizontal skaliert werden.
Umfangreiche Anpassungsunterstützung. Benutzerdefinierte Funktionen können über Hooks vor/nach einer Client -Anforderungsverarbeitung hinzugefügt werden. Und Anfragen (Befehle) Handler können über eine API auf Serverseite aufgerufen werden.
Pluginable Networking Transport. Die Kunden-Server-Kommunikation erfolgt über ein bidirektionales RPC-Protokoll. Die Implementierung von Socket.io Transport ist enthalten.
Pluginable State Store. Speicher- und Redis -Stores sind enthalten.
Unterstützt einen leichten Online -Benutzer für Online -Benutzernachrichten.
Lesen Sie diesen Artikel für weitere Hintergrundinformationen.
Dieses Projekt ist ein Knotenmodul, das über NPM erhältlich ist. Schauen Sie sich sie an, wenn Sie sie nicht lokal installiert haben.
$ npm i chat-serviceDefinieren Sie zuerst eine Serverkonfiguration. Definieren Sie auf einem serverseitigen Definieren eines Socket-Verbindungshakens, da sich der Dienst auf eine externe Authu-Implementierung stützt. Ein Benutzer muss nur eine AUTH -Prüfung übergeben, es ist kein explizite Benutzer hinzuzufügen, der Schritt hinzufügt.
const ChatService = require ( 'chat-service' )
const port = 8000
function onConnect ( service , id ) {
// Assuming that auth data is passed in a query string.
let { query } = service . transport . getHandshakeData ( id )
let { userName } = query
// Actually check auth data.
// ...
// Return a promise that resolves with a login string.
return Promise . resolve ( userName )
} Das Erstellen eines Servers ist eine einfache Objekt -Instanziierung. HINWEIS: Die close muss aufgerufen werden, um eine Serviceinstanz korrekt herunterzuschalten (siehe Failures Recovery).
const chatService = new ChatService ( { port } , { onConnect } )
process . on ( 'SIGINT' , ( ) => chatService . close ( ) . finally ( ( ) => process . exit ( ) ) ) Der Server wird jetzt auf Port 8000 ausgeführt, wobei der memory verwendet wird. Standardmäßig wird der Namespace '/chat-service' Socket.io verwendet. Fügen Sie einen Raum mit admin -Benutzer als Raumbesitzer hinzu. Alle Zimmer müssen explizit erstellt werden (Option, damit auch die Erstellung von Räumen von einer Kundenseite von einer Kunderseite bereitgestellt werden kann).
// The room configuration and messages will persist if redis state is
// used. addRoom will reject a promise if the room is already created.
chatService . hasRoom ( 'default' ) . then ( hasRoom => {
if ( ! hasRoom ) {
return chatService . addRoom ( 'default' , { owner : 'admin' } )
}
} ) Bei einem Client ist nur eine socket.io-client Implementierung erforderlich. Um eine Anfrage (Befehl) zu senden, verwenden Sie die emit -Methode, das Ergebnis (oder ein Fehler) wird in Socket.io ACK -Rückruf zurückgegeben. So hören Sie Servermeldungen on die Methode an.
const io = require ( 'socket.io-client' )
// Use https or wss in production.
let url = 'ws://localhost:8000/chat-service'
let userName = 'user' // for example and debug
let token = 'token' // auth token
let query = `userName= ${ userName } &token= ${ token } `
let opts = { query }
// Connect to a server.
let socket = io . connect ( url , opts )
// Rooms messages handler (own messages are here too).
socket . on ( 'roomMessage' , ( room , msg ) => {
console . log ( ` ${ msg . author } : ${ msg . textMessage } ` )
} )
// Auth success handler.
socket . on ( 'loginConfirmed' , userName => {
// Join room named 'default'.
socket . emit ( 'roomJoin' , 'default' , ( error , data ) => {
// Check for a command error.
if ( error ) { return }
// Now we will receive 'default' room messages in 'roomMessage' handler.
// Now we can also send a message to 'default' room:
socket . emit ( 'roomMessage' , 'default' , { textMessage : 'Hello!' } )
} )
} )
// Auth error handler.
socket . on ( 'loginRejected' , error => {
console . error ( error )
} ) Es handelt sich um einen Runnable -Code, Dateien befinden sich im example .
Es ist möglich, andere Transporte als Socket.io zu verwenden. Es gibt einen Proof of Concept-Transport, der eine WebSocket-Verbindung mit einer minimalen API-Abstraktionsschicht WS-Messaging und einem einfachen Emitter-Pubsub-Broker als Backend-Messaging-Fanout-Abstraktion verwendet.
Hier sind die wichtigsten Dinge, die ein Transport zulassen muss:
Senden Sie Nachrichten von einem Server an Gruppen von Clients (basierend auf einer einzigen String -Übereinstimmungskriterien, auch bekannt als Room Messaging).
Implementieren Sie die Request-Repry-Kommunikation von einem Client auf einen Server.
Implementieren Sie eine anhaltende Verbindung (oder semantisch äquivalent), sie ist für eine Präsenzverfolgung erforderlich.
Der Chat -Service nutzt Redis als gemeinsam genutztes Geschäft mit Persistenz. In einer realen Anwendung können einige dieser Informationen von anderen Diensten benötigt werden, aber es ist nicht praktisch, den staatlichen Laden vollständig neu zu implementieren. Ein besserer alternativer Ansatz ist die Verwendung von Haken. Zum Beispiel kann alle Raummeldungen in einer anderen Datenbank speichern, nur ein roomMessageAfter -Haken kann verwendet werden. Auch ServiceAPI kann über Backend Messaging -Busse anderen internen Servern ausgesetzt werden.
Unter normalen Umständen sind alle Fehler, die an einen Dienstbenutzer zurückgegeben werden (über Anforderungsantworten, loginConfirmed oder loginRejected Messungen) Instanzen von ChatServiceError . Alle anderen Fehler geben einen Programmfehler oder einen Fehler in einer Serviceinfrastruktur an. Um die Debug -Protokollierung solcher Fehler zu aktivieren, verwenden Sie export NODE_DEBUG=ChatService . Die Bibliothek verwendet Bluebird ^3.0.0 Verspricht die Implementierung. Daher aktivieren Sie lange Stapelspuren export BLUEBIRD_DEBUG=1 . Es wird dringend empfohlen, Versprechenversionen von APIs für Haken und ChatServiceError -Unterklassen für die Rückgabe von Haken -Haken -Fehlern zu verwenden.
Server -Side -API und RPC -Dokumentation sind online verfügbar.
Der Service wird ein Verbindungskonzept aus einem Benutzerkonzept vollständig abstrahiert, sodass ein einzelner Benutzer mehr als eine Verbindung haben kann (einschließlich Verbindungen über verschiedene Knoten hinweg). Für die Benutzerpräsenz muss die Anzahl der zusammengeschlossenen Steckdosen nur größer als Null sein. Alle APIs, die so konzipiert sind, dass sie auf Benutzerebene arbeiten und die mehreren Verbindungen des Benutzers nahtlos behandeln.
Verbindungen sind völlig unabhängig, es ist kein zusätzlicher Client -Seitenunterstützung erforderlich. Es gibt jedoch Informationen und Befehle, mit denen Informationen über die Verbindungen anderer Benutzer abgerufen werden können. Es ermöglicht die Realisierung von synchronisierten Synchronisierungsmustern von clientseitig, z.
Jedes Zimmer verfügt über ein Berechtigungssystem. Es gibt einen einzelnen Eigentümerbenutzer, der über alle Administratorberechtigungen verfügt und Benutzer der Administratorengruppe zuweisen kann. Administratoren können die Zugriffsberechtigungen anderer Benutzer verwalten. Zwei Modi werden unterstützt: Blacklist und Whitelist. Nach Zugriffslisten/Modus -Änderungen entfernt wird der Service automatisch Benutzer entfernt, die eine Zugriffserlaubnis verloren haben.
Wenn die Optionen enableRoomsManagement aktiviert sind, können Benutzer Räume über roomCreate -Befehl erstellen. Der Schöpfer eines Raumes ist sein Besitzer und kann ihn auch über den Befehl roomDelete löschen.
Bevor Hooks zur Implementierung zusätzlicher Berechtigungssysteme verwendet werden können.
Wenn ein Benutzer eine Raummeldung sendet, wird in RPC die Nachrichten id zurückgegeben. Dies bedeutet, dass die Nachricht in einem Geschäft gespeichert wurde (in einem nur hängenden kreisförmigen Pufferstruktur). Raummeldung -IDs sind eine Sequenz ab 1 , die für jede erfolgreich gesendete Nachricht im Raum um eins steigt. Ein Kunde kann die Last Room Message ID jederzeit über den Befehl roomHistoryInfo überprüfen und mit dem Befehl mit dem roomHistoryGet fehlende Nachrichten verwenden. Ein solcher Ansatz stellt sicher, dass eine Nachricht empfangen werden kann, es sei denn, sie wird aufgrund von Rotation gelöscht.
Standardmäßig kann ein Client Nachrichten senden, die nur auf eine {textMessage: 'Some string'} . So aktivieren Sie benutzerdefinierte Nachrichtenformat, liefern directMessagesChecker oder roomMessagesChecker -Haken. Wenn sich ein Haken auflöst, wird ein Nachrichtenformat akzeptiert. Nachrichten können willkürliche Daten mit wenigen Einschränkungen sein. Die obere Ebene muss ein Object ohne timestamp , author oder id -Felder sein (der Dienst wird diese Felder erfüllt, bevor sie Nachrichten senden). Die verschachtelten Ebenen können willkürliche Datentypen (sogar binär) enthalten, aber keine verschachtelten Objekte mit einem auf 'Buffer' festgelegten type (verwendet für binäre Datenmanipulationen).
Jeder Benutzerbefehl unterstützt vor und nach dem Hinzufügen von Hook, und auch eine Client -Verbindung/eine Disconnection -Hooks werden unterstützt. Befehl und Hooks werden nacheinander ausgeführt: vor Hook - Befehl - nach dem Hook (es wird auch auf Befehlsfehler aufgerufen). Die Sequenzabschlusspartierung in Before Hooks ist möglich. Kunden können zusätzliche Befehlsargumente senden, Hooks können sie lesen und mit zusätzlichen Argumenten antworten.
Um einen Benutzerbefehlsserver auszuführen, wird execUserCommand bereitgestellt. Außerdem gibt es einige mehr Server -Seite, nur Methoden, die von ServiceAPI und TransportInterface bereitgestellt werden. Suchen Sie in Anpassungsbeispielen nach Anpassungsfällen.
Der Service hält Benutzerpräsenz und Verbindungsdaten in einem Speicher, der möglicherweise anhaltend oder gemeinsam genutzt wird. Wenn also eine Instanz falsch heruntergefahren wird (ohne auf das Abschluss close zu rufen oder zu warten) oder eine vollständige Netzwerkverbindung zu einem Speicher verloren hat, werden die Anwesenheitsdaten falsch. Um diesen Fall zu beheben, wird instanceRecovery -Methode bereitgestellt.
Außerdem gibt es subtilere Fälle in Bezug auf die Konsistenz von Verbindungsabhängigen. Transportkommunikationsinstanzen und Speicherinstanzen können verschiedene Arten von Netzwerk-, Software- oder Hardwarefehlern erleben. In einigen Randfällen (wie der Betrieb mehrerer Benutzer) können solche Fehler zu Inkonsistenzen führen (zum größten Teil werden Fehler an die Emittenten des Befehls zurückgegeben). Diese Ereignisse werden über einen Instanzemitter (wie storeConsistencyFailure -Ereignis) gemeldet, und Daten können über RecoveryAPI -Methoden synchronisiert werden.
Standardmäßig wird angenommen, dass jeder Benutzer eine eindeutige Anmeldung (Benutzername) hat. Anstatt die Generierung von Namen zu verwalten, kann eine Integration mit einem separaten Transport verwendet werden (oder eine Multiplex -Verbindung, beispielsweise ein anderer Socket.io -Namespace). Zimmermeldungen können nach dem Haken an einen Transport von roomMessage weitergeleitet werden, die ohne Anmeldung zugänglich ist. Und umgekehrt können einige Service -Befehle von anonymen Benutzern über execUserCommand ausgeführt werden, wobei die Option zur Umgehungsberechtigung eingeschaltet wird.
Ein roomMessage nach dem Haken kann auch verwendet werden, um Nachrichten von einem Raum in einen anderen zu leiten. Daher können Zimmer für Nachrichtenaggregation aus anderen Räumen verwendet werden. Da Hooks nur Funktionen sind und einen vollständigen Zugriff auf Nachrichteninhalte haben, können beliebige inhaltsbasierte Weiterleitungsregeln implementiert werden. Einschließlich der Implementierung von Systemen mit hochpersonalisierten Benutzer (Client) spezifische Feeds.
Standardmäßig gibt es für andere Benutzer keine Möglichkeit, die Anzahl und die Arten von Benutzerverbindungen zu kennen. Solche Informationen können übergeben werden, beispielsweise in einer Abfragezeichenfolge und dann über einen Verbindungshaken gespeichert. Die Ankündigung kann in onJoin und onLeave -Hooks unter Verwendung einer direkten Transport sendToChannel -Methode erfolgen. Außerdem sollten zusätzliche Informationen zu Verbindungsgerätentypen nach dem Hook von roomGetAccessList gesendet werden (wenn der Listename gleich 'userlist' ist).
Es gibt keinen Löschen oder Bearbeitungsbetrieb, da sie in einer Raumhistorie Inkonsistenzen machen. Eine häufige Alternative zum Löschen und Bearbeiten besteht darin, Raummeldungen mit einer besonderen Bedeutung zu verwenden, mit der Kunden Nachrichten ausblenden oder ändern.
Wenn Sie in diesem Paket auf einen Fehler stoßen, senden Sie bitte einen Fehlerbericht an Github Repo -Probleme.
PRs werden ebenfalls akzeptiert.
MIT