Sprache: C++ mit Lua-Logikkleber.
Der Code wurde für die Kompilierung und Ausführung auf Ubuntu x86, Ubuntu x86_64 und Gentoo x86_64 getestet, sofern die richtige Version von LuaJIT verwendet wird. Änderungen an libjansson, um die erzwungene Formatierung von Gleitkommazahlen mit .0 nach ganzen Zahlen zu entfernen, wurden vorgenommen, um „Ganzzahlen“ ordnungsgemäß zu unterstützen und weiterhin eine automatische Konvertierung von Lua zu ermöglichen, das nur Doppelzahlen unterstützt.
Es lässt sich auch unter Ubuntu 12.04 LTS x86_64 kompilieren, vorausgesetzt, dass libjansson und google-glog manuell erstellt werden.
LuaJIT
libev
evhttpclient
Google-Glog
google-perftools (tcmalloc) – Optional mit geringfügigen Quell- und Makefile-Änderungen
libjansson
Hiredis
libicu – siehe lokalen Paketmanager
Curl – siehe lokalen Paketmanager
boost – Optional, wenn Sie die aufdringlichen Zeiger durch etwas Eigenes ersetzen.
Wahrscheinlich sind Änderungen an src/Makefile erforderlich, um Ihre Installationsordner widerzuspiegeln. Ein robusteres Build-System wird begrüßt, war zum Zeitpunkt der Erstellung des Projekts jedoch nicht erforderlich. (CMake?)
Ich (@zwagoth) habe hier etwas gelernt: Machen Sie beim Schreiben immer Kommentare. Um dies auszugleichen, werde ich die Grundstruktur des Programms dokumentieren, um das Verständnis zu erleichtern.
Entschuldigung für das Durcheinander einer Codebasis. Dies war auch eines meiner ersten C++-Projekte jeglicher Größenordnung und Komplexität.
Enthält fast die gesamte Kernlogik für die Nachrichtenverarbeitung von Protokollnachrichten, RTB-Nachrichten und verschiedenen grundlegenden Ereignisrückrufen wie Verbindung und Trennung.
Die Datei enthält Tabellen anonymer Funktionen, die nach den Ereignissen benannt sind, die sie verarbeiten. Diese Datei sollte keinen Status speichern und wird nur als logischer Speicherbereich betrachtet. Das grundlegende Design dieser Datei besteht darin, eine Leimlogik zu ermöglichen, ohne dass Lua große Anstrengungen unternehmen muss, und die Datenmenge, die in und aus Lua übertragen wird, auf Kosten weiterer Funktionsaufrufe in C++ zu minimieren.
Zur einfacheren Eingabe werden vier Tabellen mit Kurznamen in den globalen Dateinamensraum eingefügt:
u
: Verbindungs-/Zeichen-(Benutzer-)Funktionen
s
: Server-/globale Statusfunktionen
c
: Kanalzustandsfunktionen
const
: Fehler-IDs und konstante Werte
Protokollrückruffunktionen akzeptieren zwei Parameter: die Verbindung, der der Befehl zugeordnet ist, und eine Tabellenkopie der bereitgestellten JSON-Argumente.
Verbindungen sind undurchsichtige Zahlen und sollten NICHT in irgendeiner Weise geändert werden. Das Ändern des Werts einer Verbindung ist unsicher. Sie wurden gewarnt.
Eine Lua-Datei mit Konfigurationsvariablen, die beim Start und Betrieb des Chat-Daemons verwendet werden.
Ein minimalistischer Flash-Richtlinienserver. Wenn Sie Flash unterstützen müssen, führen Sie dieses aus. Passen Sie die integrierte Richtlinie an Ihre Bedürfnisse an.
Einstiegspunkt des Programms. Behandelt die Initialisierung von Hintergrundthreads und Curl.
Macht viel zu viele Dinge. Der Codefluss beginnt bei Server::run()
.
Der Verbindungsablauf ist wie folgt:
listenCallback handshakeCallback connectionWriteCallback connectionReadCallback connectionwriteCallback
listenCallback
richtet pro Verbindung Ereignishandler ein und übergibt den Fluss an ...
handshakeCallback
, der Lesevorgänge für Websocket-Handshakes verarbeitet.
connectionWriteCallback
verarbeitet, wenn eine Verbindung zum Schreiben bereit ist, und wird aktiviert, wenn sich Elemente in der Warteschlange befinden, die in die Verbindung geschrieben werden sollen. Behandelt die Pufferung.
connectionReadCallback
verarbeitet alle Leseereignisse, wenn die Handshake-Phase beendet ist. Die gesamte Protokollanalyse findet hier statt und Befehle werden innerhalb dieser Funktion versendet und ausgeführt.
pingCallback
kümmert sich um das Senden von Ping-Ereignissen an Clients. Wenn das Protokoll geändert wird, sollte dies eine der ersten Maßnahmen sein.
connectionTimerCallback
wird regelmäßig ausgelöst und prüft, ob die Verbindung unterbrochen ist, und bereinigt sie.
runLuaEvent
ist Molchmagie. Auch dort, wo die Magie bei jedem Befehl geschieht. Hier wird jeder Befehl vom C++-Code in den Lua-Code verschoben. Verarbeitet alle Lua-Zustände und den Rückruf, um sicherzustellen, dass Lua nicht in eine Endlosschleife gerät. Behandelt Druckfehler in Lua.
In dieser Datei werden alle Statusdaten zu Kanälen, Verbindungen, Sperren und Moderation gespeichert.
Verbindungen werden in identifizierte und nicht identifizierte Verbindungen aufgeteilt, da die Namen der Charaktere erst bekannt sind, wenn der Anmeldeserver ihre Existenz bestätigt, und um sie aus dem Pool der Charaktere herauszuhalten, die anhand ihres Namens gesucht werden können.
Behandelt das Speichern und Wiederherstellen des Status auf der Festplatte.
Wird als Hintergrundthread ausgeführt, der Anmeldeanfragen und Antworten verarbeitet und sie an den Hauptthread zurückgibt.
Serialisiertes Anmeldesystem, verwendet globale Anmeldewarteschlange. Das könnte noch einiges verbessert werden.
Die Konvertierung in „curl_multi“ wäre schön, erfordert aber eine unterhaltsame Interaktion mit libev oder viele Blindabfragen. Aufgrund des Threadings müssen Warteschlangen vor dem Zugriff gesperrt werden.
Grundlegende Kanalklasse, verwaltet Zustandsdaten über einen Kanal während seiner gesamten Lebensdauer. Alle Low-Level-Aktionen im Zusammenhang mit Kanälen werden in dieser Datei über Hooks in Lua ausgeführt. Normalerweise in einen aufdringlichen Zeiger eingeschlossen, um die Lebensdauer der Instanz zu verwalten.
Hier erfolgt die Serialisierung und Deserialisierung von Kanälen aus JSON.
Verarbeitet alle Verbindungsnetzwerk- und Debug-Lua-Zustände.
Behält Kink-Listen, Status, Statusmeldung und Geschlecht bei.
Behält die Ignorier- und Freundesliste bei.
Griffe pro Verbindungsdrosseln.
Hier erfolgt die Pufferung der Ausgabedaten.
Wird im Allgemeinen mit aufdringlichen Zeigern herumgereicht, um die Instanzlebensdauer zu verwalten.
Verwaltet eine interne Liste der Kanäle, denen beigetreten ist. Dies muss mit der tatsächlichen Kanalbenutzerliste synchron gehalten werden.
Diese Datei ist für die wenigen Funktionen reserviert, die eine hohe Geschwindigkeit anstelle der Anpassbarkeit erfordern. Verarbeitet den Anmeldebefehl ( IDN
). Behandelt den Debug-Befehl ( ZZZ
). Verarbeitet den Suchbefehl ( FKS
).
Alle Lua-Wrapper-Befehle, die in Lua-Dateien unter die Kategorie s
fallen.
Alle Lua-Wrapper-Befehle, die in Lua-Dateien unter die Kategorie u
fallen.
Alle Lua-Wrapper-Befehle, die in Lua-Dateien unter die Kategorie c
fallen.
Alle Lua-Wrapper-Werte, die in Lua-Dateien unter die Kategorie const
fallen.
Fehlermeldungen und Definitionen.
Nutzen Sie die definierten Makros zur Fehler- und Typprüfung! Nur so kann ein Absturz verhindert werden, wenn unerwartet der falsche Typ als Lightweight-Daten an eine Funktion übergeben wird.
Stellen Sie sicher, dass Ihr Lua-Stack ausgeglichen ist. Ich habe mich sehr bemüht, sicherzustellen, dass dies wahr ist, aber Fehler können leicht passieren.
Vermeiden Sie es, Tabellen auf Lua-Code umzustellen, da die Erstellung teuer ist und die Nutzungsdauer oft kurz ist. Nutzen Sie Ihr bestes Urteilsvermögen, um die Kosten für Funktionsaufrufe und die Kosten für die Erstellung von Tabellen abzuwägen.
Vermeiden Sie die unnötige Übergabe von Zeichenfolgen an Lua. Aufgrund von Speicherkopien kann es kostspielig sein.
Missbrauch, dass Lua als native Funktion mehrere Rückgabewerte akzeptiert. Siehe oben zwei Anmerkungen.
Verarbeitet den Nur-Push-Redis-Thread. Ist ein kleiner Wrapper für Redis-Befehle und ihre Rückgabewerte.
Verwendet eine Eingabewarteschlange zum Empfangen von Befehlen. Befehle werden in regelmäßigen Abständen ausgeführt und es gibt keine Garantie für die Zuverlässigkeit. Kann deaktiviert werden und ignoriert Eingaben, wenn diese deaktiviert sind.
gdb eignet sich gut zum Debuggen dieser Anwendung. Das Deaktivieren von tcmalloc und dem JIT-Abschnitt von LuaJIT dürfte bei der Fehlerbehebung bei Abstürzen sehr hilfreich sein (tcmalloc kann einige kleinere Heap-Beschädigungen verbergen).
Die Speicherprofilierungstools in tcmalloc sind ganz nett. Weitere Informationen zur Verwendung finden Sie in der tcmalloc-Dokumentation.