69 lines
2.6 KiB
Python
69 lines
2.6 KiB
Python
"""Opérations de flotte (fan-out) pour Kazeia-central.
|
|
|
|
§9 du contrat : toute action parc se fait par **fan-out séquentiel par device**, et
|
|
les commandes adb **échouent silencieusement par tablette** → on capture le résultat
|
|
OU l'erreur de CHAQUE device, jamais un échec global qui masquerait les autres. Le
|
|
rapport renvoyé est une liste `{serial, ok, result|error}` exploitable telle quelle.
|
|
|
|
Séquentiel (pas parallèle) volontairement : conforme au contrat, et un `adb` partagé
|
|
sature vite ; pour un parc de quelques tablettes le coût est négligeable.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Callable
|
|
|
|
from ...core.adb import Adb
|
|
from ...core.provider import ProviderClient
|
|
|
|
|
|
def fan_out(adb: Adb, fn: Callable[[str], Any], *,
|
|
serials: list[str] | None = None) -> list[dict[str, Any]]:
|
|
"""Exécute `fn(serial)` sur chaque tablette prête (ou la sous-liste `serials`),
|
|
en isolant les échecs. Renvoie un rapport par device."""
|
|
ready = adb.ready_devices()
|
|
if serials is not None:
|
|
wanted = set(serials)
|
|
ready = [d for d in ready if d.serial in wanted]
|
|
report: list[dict[str, Any]] = []
|
|
for d in ready:
|
|
try:
|
|
report.append({"serial": d.serial, "ok": True, "result": fn(d.serial)})
|
|
except Exception as e: # adb/provider peut échouer pour CE device seulement
|
|
report.append({"serial": d.serial, "ok": False, "error": str(e)})
|
|
return report
|
|
|
|
|
|
def device_overview(adb: Adb, serial: str) -> dict[str, Any]:
|
|
"""Résumé santé d'une tablette pour la vue parc. Chaque sous-requête est isolée :
|
|
une section indisponible ne fait pas tomber tout le résumé (renvoi partiel)."""
|
|
c = ProviderClient(adb, serial)
|
|
|
|
def safe(f, default=None):
|
|
try:
|
|
return f()
|
|
except Exception:
|
|
return default
|
|
|
|
state = safe(lambda: c.state().model_dump())
|
|
updates = safe(lambda: c.updates().model_dump())
|
|
rag = safe(lambda: c.rag_status().model_dump())
|
|
profiles = safe(lambda: c.profiles(), [])
|
|
sessions = safe(lambda: c.sessions(), [])
|
|
crashes = safe(lambda: c.crashes(), [])
|
|
|
|
g = lambda d, k: (d or {}).get(k)
|
|
return {
|
|
"serial": serial,
|
|
"online": state is not None,
|
|
"uptime_s": g(state, "uptime_seconds"),
|
|
"mem_available_mb": g(state, "mem_available_mb"),
|
|
"update_phase": g(updates, "phase"),
|
|
"app_update_available": g(updates, "app_update_available"),
|
|
"rag_ready": g(rag, "ready"),
|
|
"rag_docs": g(rag, "doc_count"),
|
|
"profiles": len(profiles),
|
|
"sessions": len(sessions),
|
|
"crashes": len(crashes),
|
|
}
|