First commit

This commit is contained in:
2026-07-20 11:05:07 +02:00
commit b592ab669f
159 changed files with 10294 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
"""Agrégats jail/pays partagés entre views.py (calcul local, toujours
disponible) et les commandes management master_listen.py (publication du
roster) / master_client.py (cache Redis du roster reçu, cf. constantes
ROSTER_* ci-dessous) une seule requête à maintenir plutôt que deux
copies qui divergent."""
from django.db.models import Count
from .models import BanEvent
TOP_N = 5
# Cache Redis du roster reçu par un noeud client (master_client.py) — DB
# dédiée (db=2) : db=0 déjà pris par Channels (CHANNEL_LAYERS), db=1 par
# Celery (CELERY_BROKER_URL). Expiration alignée sur NODE_OFFLINE_THRESHOLD_SECONDS
# (views.py) : une donnée périmée doit disparaître plutôt que mentir si le
# roster cesse d'arriver.
ROSTER_REDIS_DB = 2
ROSTER_REDIS_KEY = 'roster:global_stats'
ROSTER_TTL_SECONDS = 180
def with_bar_pct(rows: list[dict]) -> list[dict]:
"""Ajoute `pct` = largeur de barre relative au plus grand compte de la
liste pas un vrai pourcentage (la somme ne fait pas 100), juste une
échelle visuelle pour la barre du widget sidebar."""
max_count = max((row['count'] for row in rows), default=0)
for row in rows:
row['pct'] = round(row['count'] / max_count * 100) if max_count else 0
return rows
def top_jails_and_countries() -> dict[str, list[dict]]:
"""Compteurs globaux (toutes dates, tous noeuds connus de CE process)
sur le master, "tous les noeuds" ; sur un client, seulement lui-même
(d'où le roster, qui republie la version calculée côté master)."""
top_jails = list(
BanEvent.objects.values('jail_name').annotate(count=Count('id')).order_by('-count')[:TOP_N]
)
top_countries = list(
BanEvent.objects.exclude(country='')
.values('country').annotate(count=Count('id')).order_by('-count')[:TOP_N]
)
return {'top_jails': with_bar_pct(top_jails), 'top_countries': with_bar_pct(top_countries)}