9 Commits
Author SHA1 Message Date
D4rkst3randClaude Opus 5 19010e9fde Die Panel-Anbindung entfaellt -- das Panel postet jetzt selbst
Deploy / check (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
Entscheidung des Betreibers am 19.08.2026: das d4rk_gameserver-Panel
baut und stellt seine Status-Embeds ab sofort selbst in den Discord.
Damit hat diese Anbindung keinen Zweck mehr.

WARUM SIE UEBERHAUPT WEG SOLL, und nicht bloss ungenutzt liegenbleibt:
sie war die zweite Meinung ueber denselben Zustand. `zustandText()` gab
`null` zurueck, wenn ein Server LIEF UND BEREIT war -- also im
Normalfall -- und der Monitor fiel dann auf seine gamedig-Abfrage
zurueck. Erreichte die den Server nicht, stand im Kanal "Offline",
waehrend dasselbe Embed RAM und CPU aus dem Panel anzeigte. Ein
Widerspruch, den man von keiner der beiden Seiten aufloesen konnte.

ENTFERNT:

    src/panel.js                      die Anbindung
    src/panel-abgleich.js             das Anlegen/Wegraeumen von Eintraegen
    tools/panel-pruefen.mjs           die zugehoerigen Proben
    tools/panel-abgleich-pruefen.mjs
    panelUrl/panelZeichen             in runtime-settings.js
    panel_url/panel_zeichen           als Einstellung und im Formular
    Servertyp `panel`                 er fragte nicht selbst, sondern las ab

WAS DER MONITOR DAMIT VERLIERT, und es gehoert dazugesagt: die
Schonfrist beim Hochfahren. Ein startendes Modpack antwortet minutenlang
nicht -- am ATM10 gemessen 306 Sekunden -- und meldet dadurch wieder
einen Ausfall, wo vorher "startet gerade" stand. Die
Zwei-Fehlschlaege-Schwelle federt das teilweise ab, nicht ganz.

Fuer Server im Panel ist das kein Verlust: dort postet das Panel und
kennt den Unterschied. Fuer FiveM und LS25 hat es ihn nie gegeben.

Geprueft: alle 281 relativen Importe loesen auf, die geaenderten Dateien
sind syntaktisch in Ordnung, das Frontend baut. Der Bot selbst ist NICHT
neu gestartet worden -- das ist eine Entscheidung des Betreibers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 12:01:21 +02:00
D4rkst3r c81e862992 Wo der Bot nicht hinkommt, fragt das Panel -- Typ panel
Deploy / check (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
Bisher entschied `x.gamedig` darueber, ob aus einem Panel-Server ein
Monitor-Eintrag wird: "kennt unsere Bibliothek dieses Spiel?" Das hat
einen Fall ausgesperrt, den es wirklich gibt -- TeamSpeak.

UND ZWAR NICHT, WEIL GAMEDIG ES NICHT KOENNTE. Am 16.08.2026
nachgeschlagen, nachdem die Annahme "gamedig kennt TeamSpeak nicht"
sich als falsch erwies: gamedig 5.3.3 hat `teamspeak3`, DiscordGSM
fuehrt es ebenfalls. Der Grund ist ein anderer und ein besserer:

    node_modules/gamedig/protocols/teamspeak3.js
      queryPort = options.teamspeakQueryPort || 10011
      'use port=<voice>' -> 'serverinfo' -> 'clientlist'

Es braucht den SERVERQUERY-Port. Beim Betreiber liegt der hier:

    9987/udp  -> 0.0.0.0:9987      Sprache, oeffentlich
    10011/tcp -> 127.0.0.1:9988    ServerQuery, NUR localhost
    30033/tcp -> 0.0.0.0:9989      Dateien, oeffentlich

Der Bot laeuft im Container und erreicht 127.0.0.1 des Hosts nie. Zwei
Gegenproben vom Host aus, beide gescheitert (die zweite auch deshalb,
weil gamedig ohne `teamspeakQueryPort` stur 10011 nimmt -- den es dort
gar nicht gibt). Eine Kennung einzutragen brauechte also einen OFFENEN
Verwaltungsport, und das ist genau das, was die Regel "kein Port geht
ohne Eintrag ins Netz" verhindert.

Das Panel dagegen laeuft auf dem Host, darf hin und hat die
Zugangsdaten -- und schickt seine eigene Messung seit heute im
Statusbericht mit. Also:

  - `taugt` fragt `zeigbar` statt `gamedig`: "kann UEBERHAUPT JEMAND
    diesen Server abfragen -- wir oder das Panel fuer uns?" Mit
    Rueckfall auf `gamedig` fuer ein aelteres Panel; ohne den
    verschwaenden nach diesem Update alle Eintraege, und zwar lautlos.
  - Neuer eigener Typ `panel` neben `fivem` und `http`. Er ersetzt
    nichts: wo gamedig kann, bleibt es bei gamedig -- dessen Antwort
    bringt Karte, Fassung und Ping mit, die das Panel nicht liefert.
  - `spieler === null` heisst KEINE ANTWORT, nicht null Spieler. Das
    Panel sichert dazu einen Grund zu; wir werfen damit und landen im
    selben Zweig wie ein gescheiterter gamedig-Query, statt eine 0 zu
    erfinden. Und kein Ping: die Zahl ist eine gespeicherte Messung des
    Panels, keine Antwortzeit von hier.

EINE FALLE BEIM ZWEITEN PARAMETER: `servers.map(queryServer)` haette
`panelItems` den INDEX untergeschoben -- der erste Server saehe null,
alle weiteren eine Zahl, an der `panelEintrag` still scheitert. Also
`map((s) => queryServer(s, panelItems))`.

Probe erweitert und im neu gebauten Abbild gelaufen, alles gruen --
einschliesslich "null Spieler sind eine Antwort, kein Ausfall".
2026-08-16 12:01:24 +02:00
D4rkst3randClaude Opus 5 228853febd Radio: die zweite Sackgasse von der ersten trennen — und UDP messbar machen
Deploy / check (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
Aus dem Betrieb: alle drei Beitrittsschritte durch, trotzdem "signalling".
Das ist kein Widerspruch. In @discordjs/voice gibt es zwei Wege dorthin:

  - `configureNetworking` steigt aus, wenn der Endpunkt leer ist. Discord
    schickt das bei einem Regionswechsel; kommt keine zweite Meldung, bleibt
    die Verbindung fuer immer stehen.
  - Scheitert der Austausch mit dem Sprachserver, wirft die Bibliothek die
    Verbindung nach "signalling" zurueck und faengt von vorn an. Von aussen
    sieht das genauso aus.

Deshalb schreibt der Adapter jetzt den Endpunkt mit, und die Verbindung
protokolliert ihren Weg. War sie einmal bei "connecting" und ist
zurueckgefallen, ist es der UDP-Austausch — dann steht der Endpunkt in der
Meldung, damit man ihn von Hand pruefen kann.

Dazu tools/udp-pruefen.mjs: im Container aufrufen und es sagt, ob UDP
ueberhaupt rauskommt und ob auch auf hohen Ports. Genau das unterscheidet
"Firewall zu" von "Firewall laesst nur die ueblichen Ports durch" — und
Discord-Sprache braucht die hohen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 12:15:14 +02:00
D4rkst3randClaude Opus 5 b7f54185f7 fix: ein schon von Hand eingetragener Server wird uebernommen, nicht uebergangen
Deploy / check (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
Der Betreiber hat im Panel den Schalter fuer atm11-test umgelegt und im
Discord passierte nichts. Er hat den Fehler bei sich gesucht -- ob er den
Namen falsch geschrieben habe. Hat er nicht: der Server stand schon von
Hand im Monitor, weil ich ihn vorhin selbst dort eingetragen hatte, und
der Abgleich uebersprang ihn mit `continue`, damit nicht zwei Embeds fuer
denselben Server im Kanal stehen.

Das Ueberspringen war richtig, das Schweigen nicht. Wer den Schalter
umlegt, sagt "dieser Server gehoert ans Panel" -- also bekommt der
bestehende Eintrag jetzt den Herkunftsvermerk, statt ignoriert zu werden.
Ein zweites Embed entsteht dabei nicht.

Der Preis gehoert benannt und wird mitgeprueft: ab der Uebernahme nimmt
ein Ausschalten den Eintrag mit, samt Bild und Links, die von Hand daran
haengen. Das ist der Sinn des Schalters, aber es ist eine Uebertragung
von Besitz.

Ueberschrieben wird weiterhin kein Feld -- die Uebernahme setzt nur
panel_name.

Und die Meldung im Protokoll unterscheidet jetzt "neu" von "uebernommen";
vorher hiess beides "uebernommen", was genau die Auskunft verwischt haette,
um die es hier geht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 19:13:58 +02:00
D4rkst3randClaude Opus 5 0982e8cd1b feat: Server aus dem Panel uebernehmen -- und nur die auch wieder loeschen
Deploy / check (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
Im d4rk_gameserver-Panel bekommt jeder Server einen Schalter "Im Discord
anzeigen". Das Panel schreibt dafuer NICHTS hierher: es setzt nur ein
Haekchen, und das reist in dem Statusbericht mit, den der Monitor ohnehin
alle 30 Sekunden abholt. Der Bot legt den Eintrag dann selbst an.

Der umgekehrte Weg -- Panel ruft unsere API -- braeuchte dort ein
Zeichen mit Schreibrecht. So bleibt es bei einem, das nur lesen kann.

ZWEI FALLEN, beide beim Bauen aufgefallen:

Der Abgleich lief zu spaet. In monitorTick stand `if (servers.length ===
0) return` VOR dem Panel-Abruf; beim allerersten Server haette der
Schalter also nichts getan, und zwar stillschweigend. Der Abruf steht
jetzt davor.

Loeschen braucht einen Besitzvermerk. Ohne den nimmt ein Haekchen im
Panel den handgepflegten ATM10 mit -- die einzige verfuegbare Grundlage
waere der Name, und beim ersten Server, der in beiden Werkzeugen gleich
heisst, waere der Eintrag samt Bild, Links und Zugangs-Code weg. Neue
Spalte `panel_name`, leer heisst "von Hand". Die UPDATE-Anweisung fasst
sie nicht an, damit ein Bearbeiten im Webinterface die Herkunft behaelt.

Und der Abgleich ueberschreibt nichts: angelegt und geloescht wird, mehr
nicht.

tools/panel-abgleich-pruefen.mjs prueft das auf einer EIGENEN Datenbank
in /tmp und bricht ab, wenn sie es nicht ist -- eine Probe, die loeschen
kann, darf nicht dort loeschen, wo es zaehlt. Alles gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 19:08:43 +02:00
D4rkst3r d6124fc2cd feat: der Monitor fragt das Panel, wenn eine Abfrage nicht ausreicht
Deploy / check (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
gamedig FRAGT einen Server. Ein startendes Modpack antwortet nicht, und
nach zwei Fehlversuchen stand im Alarm-Kanal eine Ausfallmeldung, obwohl
niemand etwas kaputtgemacht hat -- am ATM10 des Betreibers gemessen jedes
Mal 306 Sekunden Fehlalarm.

Das d4rk_gameserver-Panel SIEHT den Container, statt ihn zu fragen. Neu
ist deshalb `src/panel.js`: Zustand, Fertig-Merkmal, RAM und CPU kommen
als Zusatzauskunft dazu, einmal je Durchlauf abgerufen und 20 Sekunden
zwischengespeichert.

Was das im Alarm-Kanal aendert:

  startet gerade   kein Alarm, aber nur innerhalb einer Gnadenfrist von
                   15 Minuten. Ohne diese Grenze fraesse die Anbindung
                   genau den Alarm, fuer den es sie gibt -- `bereit`
                   wird nie von allein wahr, ein haengender Start bliebe
                   sonst fuer immer stumm.
  im Panel gestoppt  kein Alarm (Code 0/143/137)
  abgestuerzt      ALARM, mit Code im Embed
  OOM-Kill         ALARM, und beim Namen genannt statt als Absturz
                   getarnt -- bei Modpacks die haeufigste Ursache
  Container weg    ALARM

Der Zaehler wird beim Unterdruecken NICHT zurueckgesetzt: ein bereits
gemeldeter Ausfall bleibt gemeldet, sonst verschluckt ein Stopp im Panel
die spaetere "wieder online"-Entwarnung und im Kanal bliebe ein Alarm
ohne Aufloesung stehen.

ES IST DURCHGEHEND OPTIONAL. Adresse und Zeichen stehen im Webinterface
unter "Server" und NICHT in der .env; ohne Eintrag -- und ebenso, wenn
das Panel nicht antwortet -- verhaelt sich der Monitor exakt wie vorher.
Das Zeichen darf nur lesen, damit auch ein verlorenes niemandem einen
Server stoppen kann.

`tools/panel-pruefen.mjs` prueft die Logik ohne Discord und ohne
Datenbank; deshalb laedt panel.js die Einstellungen erst beim Aufruf.
2026-08-13 18:05:24 +02:00
D4rkst3randClaude Opus 5 720785c175 backup: die Sicherung verlaesst das Volume -- tools/abholen.ps1 plus Wachhund
Deploy / check (push) Canceled after 0s
Deploy / deploy (push) Canceled after 0s
Befund 1 aus docs/befunde-2026-08-12.md, der wichtigste: Datenbank und alle
vierzehn Sicherungen lagen im selben Volume. Geht das Volume verloren, geht
beides zusammen verloren -- das ist keine Sicherung, das ist eine Kopie.

tools/abholen.ps1 SICHERT NICHT. Das Archiv baut der Bot selbst; hier wird nur
abgeholt, und zwar so, dass am Ende feststeht, dass die Kopie heil ist und
nicht nur, dass ein Kopierbefehl keinen Fehler geworfen hat:

  1. neuestes Archiv im Container finden (und meckern, wenn es aelter als
     24 Stunden ist -- ein Skript, das treu das Archiv von vorletzter Woche
     abholt und "fertig" sagt, ist schlimmer als eines, das gar nicht laeuft)
  2. docker cp heraus
  3. Pruefsumme IM CONTAINER gegen die Kopie hier -- nicht die Dateigroesse:
     eine abgebrochene Kopie auf eine volle Platte hat oft genau die richtige
     Laenge und trotzdem Nullen am Ende
  4. auspacken und die Datenbank darin oeffnen, mit dem Bot-Abbild, weil dort
     better-sqlite3 schon liegt; integrity_check plus Tabellen zaehlen
  5. Bericht als last_zweitziel zurueck in die Einstellungen
  6. ausduennen

Und es warnt, wenn es DIESELBE PLATTE ist. Verglichen wird die physische Platte
und nicht der Laufwerksbuchstabe: zwei Partitionen derselben NVMe sterben
zusammen.

Echter Lauf, kein Trockentest:

    d4rkbot-2026-08-12.db.gz   993.332 Bytes
    andere Platte: Nr. 1 statt Nr. 0
    identisch (ff08516d293d...)
    in der Sicherung: 55 Tabellen, 86 Einstellungen

DAZU EIN ZWEITER WACHHUND, pruefeZweitziel(). Ein Skript auf dem Wirt, das
still aufhoert zu laufen -- Aufgabe deaktiviert, Laufwerk weg, Pfad geaendert --
waere derselbe Schaden noch einmal, nur eine Ebene weiter aussen. Er meldet nur,
wenn die Abholung schon einmal lief: fehlt der Eintrag ganz, ist sie nicht
eingerichtet, und daraus taeglich eine Meldung zu machen waere Naergelei.

Gegen eine Kopie der Datenbank durchgespielt:

    40 h alt   -> "alt:17863965"
    nochmal    -> unveraendert          (keine Wiederholung)
    Fehlschlag -> "fehler:1786540570974"
    wieder gut -> ""                    (Entwarnung)

Nebenbei gelernt, zum zweiten Mal in diesem Projekt: die Kopie der Datenbank
ohne -wal war leer an der Stelle, die zaehlte -- last_zweitziel stand noch im
Write-Ahead-Log. Dieselbe Falle wie beim Zurueckspielen von d4rk_media.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 15:17:01 +02:00
D4rkst3randClaude Fable 5 07afa094a2 tools/post-devlog.mjs: Devlogs aus diesem Repo posten
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
devlog.py im EcoGame-Repo taugt für Bot-Devlogs nicht: es zählt
EcoGame-Commits, bricht ohne solche ganz ab, betitelt den Post als
„Devlog — EcoGame" und löscht die Bilder nach dem Senden.

Das Skript hier zählt die Commits von d4rkbot, nimmt einen Bilder-Ordner
(max. 4, wie der Endpoint), lässt die Bilder liegen und kann mit --dry
vorher zeigen, was rausginge. Die Webhook-Adresse kommt aus der Umgebung
oder einer Datei und wird nie ausgegeben — auch nicht im Fehlerfall.

Beim Testen gegen einen lokalen Bot ohne Discord gefunden: payload_json
als Blob anzuhängen kommt beim Endpoint als Datei-Teil an und wird
zusammen mit den Nicht-Bildern verworfen — der Post wäre mit „empty
devlog" abgelehnt worden. Muss ein Textfeld sein.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 17:09:10 +02:00
D4rkst3randClaude Opus 4.8 1ed50a6561 Portainer-Deployment: Env-Interpolation statt env_file, lokales Webhook-Test-Skript
- docker-compose.yml: Variablen per Interpolation (lokal aus .env, in Portainer aus Stack-Env)
- tools/test-webhook.mjs: signierte Fake-Testzustellung gegen die lokale Instanz
- README: Portainer-Anleitung präzisiert (Git-Auth für privates Repo, Pull and redeploy)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 23:43:24 +02:00