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:
"""Der eingestellte Bildsatz, oder DEFAULT_IMAGE_SET, wenn die Datei fehlt, unlesbar
ist oder etwas Unbekanntes enthaelt. Wirft nie - eine kaputte Umschalterdatei darf
den Server nicht abschiessen, und sie darf vor allem nicht auf den teureren der
ist (inklusive ungueltigem UTF-8 - Fixrunde 1, Kleinigkeit: ein reines "except
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)."""
if path is None:
return DEFAULT_IMAGE_SET
try:
value = path.read_text().strip()
except OSError:
except (OSError, UnicodeDecodeError):
return 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:
"""Liegt der eingestellte Rettungs-Bildsatz ueberhaupt auf dem Pi? Dieselbe Regel
wie migrate_set_present() (Verzeichnis vorhanden UND mindestens ein Image
darin) - Panel und CLI sollen fuer die Rettung nach demselben Massstab
urteilen wie fuer die Migration."""
darin), hier fuer die Startzeile im Journal (main()) verwendet. Panel
(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:
return any(p.name.endswith(".img") for p in self.rescue_dir().iterdir())
except OSError:
@@ -718,10 +722,30 @@ def main(argv: list[str] | None = None) -> int:
httpd = ThreadingHTTPServer((a.bind, a.port), Handler)
httpd.daemon_threads = True
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): "
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.
# Im Journal, weil "warum kam das Image mit meinem WLAN?" sonst nirgends
# nachschlagbar waere - das Panel zeigt nur den JETZIGEN Zustand.