Files
Noxely/server/noxely_server/config.py
T
tuxgyverandClaude Sonnet 5 5b5e90247f Onglet Radio sur le serveur, bouton de synchronisation sur le mobile (2.5.0)
Le serveur gagne un onglet Radio : les stations de l'annuaire, écoutables en
direct dans le navigateur ou enregistrables — jusqu'à l'arrêt ou pour une durée
choisie —, puis réécoutables depuis l'interface. Quatre enregistrements en
parallèle au plus ; si le flux tombe, il est rouvert et le fichier continue.
Les enregistrements rejoignent la bibliothèque : le mobile les reçoit.

Un redémarrage du service clôt proprement les captures en cours, et celles
restées « en cours » après un plantage sont récupérées au démarrage suivant.
La copie de flux sans blocs ICY, propre au guet, est extraite pour être
partagée.

Côté mobile, la synchronisation manuelle n'était qu'un petit lien dans l'onglet
Connexion : elle a maintenant un vrai bouton dans l'onglet Synchronisation.
Deux passages ne se chevauchent plus, et une erreur inattendue s'affiche au lieu
de fermer l'application.

Le code Kotlin n'a pas été compilé sur cette machine (pas de JDK) : il a été
relu, mais reste à construire.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N6pmSE168yjyf8vgV8mZx6
2026-09-20 22:39:59 +02:00

92 lines
3.7 KiB
Python

# Noxely — collecte côté serveur, écoute hors connexion côté mobile.
# Copyright © 2026 Johnny (tuxgyver)
#
# Ce programme est un logiciel libre : vous pouvez le redistribuer et le modifier
# selon les termes de la GNU General Public License, version 3 ou ultérieure,
# telle que publiée par la Free Software Foundation.
#
# Il est distribué dans l'espoir d'être utile, mais SANS AUCUNE GARANTIE.
# Voir le fichier LICENSE à la racine du dépôt pour le texte complet.
"""Configuration du serveur Noxely, lue de l'environnement.
Aucune valeur sensible n'est écrite dans le dépôt : le jeton et les chemins viennent d'un
fichier .env local, à l'image des autres services de la maison.
"""
from __future__ import annotations
import os
import secrets
from dataclasses import dataclass
from pathlib import Path
def _persisted_token(data_dir: Path) -> str:
"""Jeton auto-généré, conservé entre deux démarrages.
Un jeton tiré à chaque lancement obligerait à reconfigurer le téléphone après le moindre
redémarrage : il est donc écrit une fois, en lecture seule pour son propriétaire.
"""
path = data_dir / "token"
if path.exists():
existing = path.read_text().strip()
if existing:
return existing
token = secrets.token_urlsafe(24)
data_dir.mkdir(parents=True, exist_ok=True)
path.write_text(token + "\n")
path.chmod(0o600)
print(f"[noxely] jeton généré et conservé dans {path}")
return token
@dataclass(frozen=True)
class Config:
data_dir: Path
token: str
host: str
port: int
#: Nombre de stations balayées à chaque passage du guet.
watch_stations: int
#: Pause entre deux balayages, en secondes. Le balayage est continu : cette pause n'est
#: qu'un garde-fou pour ne pas marteler l'annuaire si un tour échoue instantanément.
watch_interval: int
#: Stations sondées en parallèle. Plus il est haut, plus un tour complet est bref.
watch_concurrency: int
#: Garder la trace de ce que les stations annoncent, même sans guet en cours.
history: bool
#: Pause entre deux tours quand rien n'est guetté : l'historique n'a pas besoin de la
#: cadence d'un guet, et cela ménage la bande passante.
listen_interval: int
#: Ancienneté maximale de l'historique, en jours. Au-delà, les lignes sont purgées.
history_days: int
#: Durée maximale d'un enregistrement de station, en minutes : garde-fou contre un
#: enregistrement oublié, qui remplirait le disque à raison d'environ 57 Mo par heure.
record_max_minutes: int
@property
def media_dir(self) -> Path:
return self.data_dir / "media"
@property
def db_path(self) -> Path:
return self.data_dir / "noxely.sqlite3"
def load() -> Config:
data_dir = Path(os.environ.get("NOXELY_DATA", "./data")).expanduser().resolve()
token = os.environ.get("NOXELY_TOKEN", "").strip() or _persisted_token(data_dir)
return Config(
data_dir=data_dir,
token=token,
host=os.environ.get("NOXELY_HOST", "0.0.0.0"),
port=int(os.environ.get("NOXELY_PORT", "8710")),
watch_stations=int(os.environ.get("NOXELY_WATCH_STATIONS", "40")),
watch_interval=int(os.environ.get("NOXELY_WATCH_INTERVAL", "5")),
watch_concurrency=int(os.environ.get("NOXELY_WATCH_CONCURRENCY", "8")),
history=os.environ.get("NOXELY_HISTORY", "1").strip().lower() not in ("0", "false", "non", "no"),
listen_interval=int(os.environ.get("NOXELY_LISTEN_INTERVAL", "60")),
history_days=int(os.environ.get("NOXELY_HISTORY_DAYS", "90")),
record_max_minutes=int(os.environ.get("NOXELY_RECORD_MAX_MINUTES", "180")),
)