7. Admin Manager : Régulateur de la Citadelle (v5.25)
Le admin-manager est le cœur opérationnel hors-bande du framework ECHO. Il opère en tant que micro-service Python (Flask) isolé. Cette documentation détaille l'intégralité des fonctions, algorithmes et choix architecturaux du code source.
1. Résilience & Dégradation Gracieuse (Graceful Degradation)
Le script s'initialise avec une série de blocs try...except ImportError. Cela permet au Manager de démarrer même si l'environnement est partiellement dégradé ou incomplet. Des drapeaux booléens gèrent la disponibilité des sous-systèmes :
- DOCKER_AVAILABLE : Contrôle l'accès à
dockeretparamiko. Si False, les sauvegardes et redémarrages sont désactivés silencieusement. - HAS_PSUTIL : Désactive les statistiques CPU/RAM sans crasher l'API.
- HAS_SCHEDULER / HAS_MAINT_SCHEDULER : Sépare le moteur de backups temporels (APScheduler) du moteur d'élagage (Schedule).
2. Helpers & Utilitaires Bas Niveau
Plusieurs fonctions de bas niveau assurent la traduction entre le système de fichiers brut et l'interface utilisateur :
Convertit itérativement un entier (octets) en format lisible (KB, MB, GB) avec une précision d'une décimale.
get_cpu_model_name() :
Lit directement
/proc/cpuinfo au lieu d'invoquer des commandes lourdes, en cherchant la première occurrence de "model name".get_echo_version() :
Tente de lire le fichier statique
/app/ECHO_VERSION injecté au build. Retourne "v?.?" en cas d'échec (Fail-Safe).
3. Vérité Sémantique & Monitoring Holistique
La fonction get_dir_stats(path, filter_ext) parcourt récursivement les dossiers avec os.walk. Elle intègre un bloc try...except autour de os.path.getsize pour ignorer les fichiers verrouillés en cours d'écriture (ex: .db-shm ou journaux actifs).
- Sessions Actives (Real Sessions) : La route
index()ignore les bases techniques. Elle filtre chirurgicalement les répertoires contenant/chats/pour ne compter que les vraies conversations.
4. L'Engine d'Élagage Sémantique (LIFECYCLE)
La fonction run_semantic_pruning() prévient l'atrophie et la saturation :
- Purge des Orphelins : Connexion SQLite en lecture seule (
mode=ro) surwebui.dbpour extraire les UIDs valides. Tout dossier dans/data/users/non référencé et dont la taille du nom dépasse 30 caractères (UUID) est détruit viashutil.rmtree(). - Atrophie Temporelle : prune_recursive() utilise un
cutoff = time.time() - (days * 86400). Le fichieridentity.dbest passé en argument desanctuary_fileset est immunisé contre la suppression. - Optimisation Physique (VACUUM) : Chaque base de données de chat subit un
db.execute("VACUUM;")avec un timeout de 10.0s pour défragmenter les index.
5. Gestion Dynamique des Configurations
Pour éviter les plantages dus à des fichiers JSON malformés, le Manager utilise un pattern de "Fusion avec dictionnaire par défaut" (Dictionary Merging).
1. Crée une copie locale de
DEFAULT_BACKUP_CONFIG (ou maint).2. Lit le fichier cible (ex:
settings.json) via orjson.loads().3. Applique un
c.update(json.load(f)) pour écraser les valeurs par défaut avec les valeurs utilisateur, tout en préservant les clés manquantes.save_settings(new_s) :
Met à jour le dictionnaire et force l'écriture asynchrone, puis déclenche immédiatement
update_backup_schedule() pour recompiler les tâches CRON.
6. Sauvegardes & Atomicité
La fonction perform_backup_task() orchestre l'état Docker via le socket :
# Séquence :
target.stop() # Figement immédiat du conteneur
subprocess.run(['tar', '-czf', fpath, ...]) # Compression
target.start() # Redémarrage
Logique d'Horodatage
La fonction update_backup_schedule() recalcule dynamiquement le point de départ de la prochaine sauvegarde. Si l'heure cible (ex: "03:00") est déjà passée aujourd'hui (start <= now), elle ajoute un datetime.timedelta(days=1) pour programmer à demain, évitant un déclenchement immédiat non désiré.
7. Matrice des Routes API & Multiplexeur d'Actions
Le serveur expose une API REST Flask robuste. Les actions longues sont détachées dans des threads démons pour ne pas bloquer l'interface Web (Gunicorn/Flask Worker).
- GET /api/user_stats : Ouvre `webui.db` en Read-Only, extrait nom, email et rôle, puis croise ces données avec le système de fichiers pour compter les bases de chat physiques de chaque utilisateur.
- GET /api/stats : Interface
psutil. Retourne un JSON consolidé (CPU %, Charge 1/5/15m, RAM %, Disk %). Le frontend interroge cette route en polling toutes les 3 secondes via JS. - POST /action/<action> : Le multiplexeur central.
backup/pruning: Lancethreading.Thread(target=...)pour exécution asynchrone.restore: Exécute de manière bloquante unrm -rf /app/backend/data/*destructeur, suivi de l'extraction de l'archive.restart: Invoquedocker.from_env().containers.get(cid).restart().
8. SSH Stealth & Sécurité
L'Admin Manager utilise paramiko via host.docker.internal.
Instancie un terminal virtuel interactif (
invoke_shell) car la commande Linux passwd exige un TTY. Elle injecte des délais (time.sleep) entre les envois (ancien mot de passe, nouveau x2) pour pallier la latence du shell hôte, puis parse la réponse à la recherche de la sous-chaîne de succès.
- Secret Maître : L'API
/api/admin/passwordlit physiquement le fichier monté dans l'enclave/app/secrets/.owui-admin-secret. - Purge des clés (Auth Reset) : Parcourt tous les fichiers
identity.dbet exécuteDELETE FROM auth_data WHERE key LIKE 'google_%'pour invalider les connexions SSO globales.
9. Schedulers & Threads Démons
Le bloc d'exécution principal (if __name__ == '__main__':) initialise deux moteurs distincts :
- BackgroundScheduler (APScheduler) : Gère les sauvegardes. Il offre une précision avancée et permet d'annuler/remplacer des tâches dynamiquement (
remove_all_jobs()). - Schedule (Thread Démon) : Gère le cycle de vie (LIFECYCLE). Un thread personnalisé exécute une boucle
while True: schedule.run_pending(); time.sleep(60). Ce thread meurt avec le conteneur (Daemon=True).