mirror of
https://github.com/Jeuners/Logpy-AgentOne.git
synced 2026-09-15 09:46:12 +02:00
feat: Störungswache (pipe.monitor) + Verschlüsselung-at-rest dokumentiert
Dienste-Ampel (Telefon, Verarbeitung, Spracherkennung, Nextcloud) alarmierte bisher nur im offenen Leitstand. pipe/monitor.py laeuft jetzt als eigener Dauerprozess, prueft dieselbe Ampel (neu ausgelagert nach pipe/dienste.py) periodisch und alarmiert bei Stoerung lokal per macOS-Benachrichtigung + Ton (pipe/alarm.py) - unabhaengig davon, ob pipe.watch oder pipe.server laufen. Wird ab jetzt von telefon/starten.sh mitgestartet. Verschluesselung at rest: keine App-eigene Verschluesselung eingebaut, stattdessen im README als Betreiber-Pflicht dokumentiert (FileVault aktivieren) - App verlaesst sich auf Festplattenverschluesselung durch das Betriebssystem. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EbdWYnDtyMgxsq4eN1WnrQ
This commit is contained in:
parent
be0252c907
commit
6e5fe59c53
8 changed files with 266 additions and 90 deletions
70
pipe/monitor.py
Normal file
70
pipe/monitor.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
"""Störungswache: prüft die Dienste-Ampel (pipe.dienste) periodisch und
|
||||
alarmiert lokal (macOS-Benachrichtigung + Ton), wenn ein Dienst ausfällt -
|
||||
auch wenn gerade niemand auf den Leitstand schaut.
|
||||
|
||||
python3 -m pipe.monitor [--einmal]
|
||||
|
||||
Läuft als eigener Prozess (siehe telefon/starten.sh), unabhängig von
|
||||
pipe.watch und pipe.server - fällt einer der beiden aus, kann die Wache das
|
||||
trotzdem noch melden. Alarmiert nur bei echten Störungen ("schlecht"/"aus"),
|
||||
nicht bei "unklar" (z. B. Nextcloud nicht konfiguriert - das ist gewollt,
|
||||
kein Fehler).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import time
|
||||
|
||||
from . import alarm, config, dienste
|
||||
|
||||
GESTOERT = {"schlecht", "aus"}
|
||||
|
||||
|
||||
def pruefe(letzte_alarme: dict[str, float]) -> None:
|
||||
"""Ein Durchlauf: Ampel abfragen, bei Bedarf alarmieren.
|
||||
|
||||
`letzte_alarme` hält je Dienstname den Zeitpunkt (time.monotonic) des
|
||||
letzten Alarms - fehlt ein Name, gilt der Dienst aktuell als nicht
|
||||
gestört. Der Aufrufer reicht dasselbe dict über alle Durchläufe weiter.
|
||||
"""
|
||||
jetzt = time.monotonic()
|
||||
for dienst in dienste.status()["dienste"]:
|
||||
name, zustand, text = dienst["name"], dienst["zustand"], dienst["text"]
|
||||
letzter_alarm = letzte_alarme.get(name)
|
||||
if zustand in GESTOERT:
|
||||
if letzter_alarm is None:
|
||||
alarm.sende(f"⚠ {name} gestört", text)
|
||||
letzte_alarme[name] = jetzt
|
||||
elif jetzt - letzter_alarm >= config.MONITOR_WIEDERHOLUNG_MIN * 60:
|
||||
alarm.sende(f"⚠ {name} weiterhin gestört", text)
|
||||
letzte_alarme[name] = jetzt
|
||||
elif zustand == "gut" and letzter_alarm is not None:
|
||||
alarm.sende(f"✓ {name} wieder ok", text)
|
||||
del letzte_alarme[name]
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
p = argparse.ArgumentParser(
|
||||
description="Dienste-Ampel beobachten und bei Störung lokal alarmieren.")
|
||||
p.add_argument("--einmal", action="store_true",
|
||||
help="nur einmal prüfen statt dauerhaft zu beobachten")
|
||||
args = p.parse_args(argv)
|
||||
|
||||
letzte_alarme: dict[str, float] = {}
|
||||
if args.einmal:
|
||||
pruefe(letzte_alarme)
|
||||
return 0
|
||||
|
||||
print(f"Störungswache aktiv - Takt {config.MONITOR_TAKT_S}s, "
|
||||
f"Erinnerung alle {config.MONITOR_WIEDERHOLUNG_MIN} min - Abbruch mit Strg-C")
|
||||
try:
|
||||
while True:
|
||||
pruefe(letzte_alarme)
|
||||
time.sleep(config.MONITOR_TAKT_S)
|
||||
except KeyboardInterrupt:
|
||||
print("\nBeobachtung beendet.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loading…
Add table
Add a link
Reference in a new issue