fix(station): Server nennt Rettungs-Bildsatz im Journal, haertet Umschalter-Lesen ab

main() glob'te die Startzeile weiter flach ueber image_dir und nannte den
geltenden Rettungs-Bildsatz nie - seit image_path() aus rescue_dir() liest,
zeigte das im Rettungsmodus immer "0 image(s)". rescue_set_present() (bisher
toter Code) wird jetzt fuer eine eigene Journalzeile verwendet, analog zur
bestehenden Migrationszeile.

read_image_set() fing nur OSError - eine Umschalterdatei mit ungueltigem
UTF-8 schlug durch, statt auf die sichere Vorgabe zu fallen.
This commit is contained in:
Michael Sauer
2026-09-23 21:58:54 +02:00
parent 6d0f79a6ac
commit e67fc53b20
+31 -7
View File
@@ -104,14 +104,16 @@ RESCUE_SET_DIRS = {"ohne-wlan": "rescue-nocreds", "mit-wlan": "rescue-wlan"}
def read_image_set(path: Path | None) -> str: def read_image_set(path: Path | None) -> str:
"""Der eingestellte Bildsatz, oder DEFAULT_IMAGE_SET, wenn die Datei fehlt, unlesbar """Der eingestellte Bildsatz, oder DEFAULT_IMAGE_SET, wenn die Datei fehlt, unlesbar
ist oder etwas Unbekanntes enthaelt. Wirft nie - eine kaputte Umschalterdatei darf ist (inklusive ungueltigem UTF-8 - Fixrunde 1, Kleinigkeit: ein reines "except
den Server nicht abschiessen, und sie darf vor allem nicht auf den teureren der OSError" liess eine Datei mit kaputten Bytes durchschlagen statt auf die Vorgabe zu
fallen) oder etwas Unbekanntes enthaelt. Wirft nie - eine kaputte Umschalterdatei
darf den Server nicht abschiessen, und sie darf vor allem nicht auf den teureren der
beiden Saetze zeigen (siehe IMAGE_SET_DIRS).""" beiden Saetze zeigen (siehe IMAGE_SET_DIRS)."""
if path is None: if path is None:
return DEFAULT_IMAGE_SET return DEFAULT_IMAGE_SET
try: try:
value = path.read_text().strip() value = path.read_text().strip()
except OSError: except (OSError, UnicodeDecodeError):
return DEFAULT_IMAGE_SET return DEFAULT_IMAGE_SET
return value if value in IMAGE_SET_DIRS else DEFAULT_IMAGE_SET return value if value in IMAGE_SET_DIRS else DEFAULT_IMAGE_SET
@@ -191,8 +193,10 @@ class Station:
def rescue_set_present(self) -> bool: def rescue_set_present(self) -> bool:
"""Liegt der eingestellte Rettungs-Bildsatz ueberhaupt auf dem Pi? Dieselbe Regel """Liegt der eingestellte Rettungs-Bildsatz ueberhaupt auf dem Pi? Dieselbe Regel
wie migrate_set_present() (Verzeichnis vorhanden UND mindestens ein Image wie migrate_set_present() (Verzeichnis vorhanden UND mindestens ein Image
darin) - Panel und CLI sollen fuer die Rettung nach demselben Massstab darin), hier fuer die Startzeile im Journal (main()) verwendet. Panel
urteilen wie fuer die Migration.""" (display.py) und CLI (ninlight-station) sind eigene Prozesse und rufen diese
Methode nicht auf, urteilen aber nach DERSELBEN REGEL - eigene, gleich lautende
Pruefungen, kein gemeinsamer Code."""
try: try:
return any(p.name.endswith(".img") for p in self.rescue_dir().iterdir()) return any(p.name.endswith(".img") for p in self.rescue_dir().iterdir())
except OSError: except OSError:
@@ -718,10 +722,30 @@ def main(argv: list[str] | None = None) -> int:
httpd = ThreadingHTTPServer((a.bind, a.port), Handler) httpd = ThreadingHTTPServer((a.bind, a.port), Handler)
httpd.daemon_threads = True httpd.daemon_threads = True
httpd.station = station # type: ignore[attr-defined] httpd.station = station # type: ignore[attr-defined]
images = sorted(p.name for p in a.image_dir.glob("ninlight_*_ota.img")) # Fixrunde 1, Kleinigkeit: vor dem Bildsatz-Umschalter fuer die Rettung lagen deren
# Abbilder flach in a.image_dir, das Glob dort war also die richtige Auskunft. Seit
# image_path() aus rescue_dir() liest (dem eingestellten Satz), muss diese Zeile
# demselben Verzeichnis folgen - sonst zeigt das Journal "0 image(s)" fuer eine
# Rettung, die tatsaechlich welche hat (oder umgekehrt).
if mode == "recovery":
try:
images = sorted(p.name for p in station.rescue_dir().glob("ninlight_*_ota.img"))
except OSError:
images = []
else:
images = []
print(f"{now_iso()} listening on {a.bind}:{a.port}, mode={mode}, {len(images)} image(s): " print(f"{now_iso()} listening on {a.bind}:{a.port}, mode={mode}, {len(images)} image(s): "
f"{', '.join(images) or 'none'}", flush=True) f"{', '.join(images) or 'none'}", flush=True)
if mode == "migration": if mode == "recovery":
# Bildsatz auch fuer die Rettung im Journal - dieselbe Begruendung wie unten fuer
# die Migration: "warum bekam die Lampe ein Abbild ohne/mit Zugangsdaten?" ist
# sonst nirgends nachschlagbar. rescue_set_present() (bislang toter Code) ist das
# hier tatsaechlich Verwendete.
selected = station.image_set()
present = "vorhanden" if station.rescue_set_present() else "FEHLT"
print(f"{now_iso()} image set: {selected} ({station.rescue_dir()}, {present})",
flush=True)
elif mode == "migration":
# Nur im Migrationsmodus: der Bildsatz betrifft ausschliesslich migrate/-Images. # Nur im Migrationsmodus: der Bildsatz betrifft ausschliesslich migrate/-Images.
# Im Journal, weil "warum kam das Image mit meinem WLAN?" sonst nirgends # Im Journal, weil "warum kam das Image mit meinem WLAN?" sonst nirgends
# nachschlagbar waere - das Panel zeigt nur den JETZIGEN Zustand. # nachschlagbar waere - das Panel zeigt nur den JETZIGEN Zustand.