diff --git a/.env.example b/.env.example index a9d812c..9f474f6 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ # Credentials Claude d'un login ISOLÉ dédié à Monitorink (scope user:profile requis par # /usage -> login complet obligatoire, `claude setup-token` ne suffit PAS). -# Créer via : CLAUDE_CONFIG_DIR=/home/jerem/.monitorink-claude claude auth login +# Créer via : CLAUDE_CONFIG_DIR=$HOME/.monitorink-claude claude auth login # Le backend lit/écrit ce fichier (refresh) ; il est monté dans le conteneur sur /creds. MONITORINK_CLAUDE_CREDS=/creds/.credentials.json # User-Agent attendu par l'endpoint /usage (doit ressembler à claude-code/) @@ -35,13 +35,17 @@ MONITORINK_USAGE_TTL=120 MONITORINK_LAT=48.8566 MONITORINK_LON=2.3522 -# NAS (optionnel) — endpoint /api/status du moniteur maison nas_monitor. -# Laisser vide pour masquer la section NAS. Depuis le conteneur, viser l'IP LAN du host. -MONITORINK_NAS_URL=http://192.168.0.43:8766/api/status +# NAS (optionnel) — endpoint HTTP exposant l'état du NAS au format /api/status (moniteur +# maison ou équivalent). Laisser vide pour masquer la section NAS. Depuis le conteneur, +# viser l'IP LAN du host. +MONITORINK_NAS_URL=http://nas.local:8766/api/status -# Codex (optionnel) — usage ChatGPT/Codex via wham/usage. Token lu dans le auth.json de -# Hermes monté en lecture seule (cf. docker-compose.yml). Laisser vide pour masquer Codex. -MONITORINK_CODEX_TOKEN_FILE=/hermes/auth.json +# Codex (optionnel) — usage ChatGPT/Codex via l'endpoint backend-api/usage. Le token +# openai-codex est lu dans un auth.json maintenu frais par un processus EXTERNE et monté +# en lecture seule (cf. docker-compose.yml). Laisser vide pour masquer Codex. +# MONITORINK_CODEX_DIR = dossier hôte contenant auth.json (monté sur /codex). +MONITORINK_CODEX_DIR=$HOME/.config/codex +MONITORINK_CODEX_TOKEN_FILE=/codex/auth.json # Trackers torrent privés (optionnel) — ratio/envoi/réception du compte, sous le NAS. # Liste des clés actives, puis UN bloc par tracker. v1 : type "unit3d_nuxt" (ex. c411). @@ -78,3 +82,9 @@ MONITORINK_CODEX_TOKEN_FILE=/hermes/auth.json #MONITORINK_TRACKER_YGGREBORN_USER=ton.email@exemple.com #MONITORINK_TRACKER_YGGREBORN_PASS=TonMotDePasse #MONITORINK_TRACKER_TTL=1800 + +# ── Déploiement (docker-compose) ───────────────────────────────────────────── +# Domaine exposé par le reverse proxy (label caddy-docker-proxy). Adapter au tien. +MONITORINK_DOMAIN=monitorink.example.com +# Nom du réseau Docker EXTERNE (déjà créé) auquel rattacher le conteneur. +MONITORINK_NETWORK=monitorink-net diff --git a/backend/config.py b/backend/config.py index 4dc9b78..0d1dfa6 100644 --- a/backend/config.py +++ b/backend/config.py @@ -78,14 +78,14 @@ class Config: weather_lat: float = field(default_factory=lambda: float(_get("MONITORINK_LAT", "48.8566"))) weather_lon: float = field(default_factory=lambda: float(_get("MONITORINK_LON", "2.3522"))) - # --- NAS (moniteur maison nas_monitor, endpoint /api/status) --- + # --- NAS (endpoint HTTP exposant l'état du NAS au format /api/status) --- nas_url: str = field(default_factory=lambda: _get("MONITORINK_NAS_URL")) - # --- Codex (usage ChatGPT/Codex via wham/usage) --- - # Fichier auth.json de Hermes monté en lecture seule : Hermes y maintient un token + # --- Codex (usage ChatGPT/Codex via backend-api/usage) --- + # Fichier auth.json monté en lecture seule : un processus externe y maintient un token # openai-codex frais. Monitorink le relit à chaque rendu (aucun refresh côté Monitorink). codex_token_file: str = field( - default_factory=lambda: _get("MONITORINK_CODEX_TOKEN_FILE", "/hermes/auth.json") + default_factory=lambda: _get("MONITORINK_CODEX_TOKEN_FILE", "/codex/auth.json") ) # --- Trackers torrent privés (ratio du compte) --- diff --git a/backend/integrations/codex.py b/backend/integrations/codex.py index 177b904..5924b42 100644 --- a/backend/integrations/codex.py +++ b/backend/integrations/codex.py @@ -4,8 +4,8 @@ La réponse expose `rate_limit.primary_window` (5 h) et `secondary_window` (hebd `used_percent` + `reset_*`, soit l'équivalent du `/usage` de Claude → on en fait des jauges « % restant ». -Le token d'accès est lu dans le `auth.json` de l'agent maison Hermes (monté en lecture -seule), qui le maintient frais. Monitorink ne fait que le relire (aucun refresh ici). +Le token d'accès est lu dans un `auth.json` maintenu frais par un processus externe (monté +en lecture seule). Monitorink ne fait que le relire (aucun refresh ici). """ from __future__ import annotations @@ -49,7 +49,7 @@ def _human_delay(seconds: int) -> str: def _read_token() -> str | None: - """Lit le token openai-codex dans le auth.json de Hermes (pool actif, sinon provider).""" + """Lit le token openai-codex dans le auth.json (pool actif, sinon provider).""" try: with open(config.codex_token_file) as f: data = json.load(f) diff --git a/backend/integrations/nas.py b/backend/integrations/nas.py index 150fb9f..1976895 100644 --- a/backend/integrations/nas.py +++ b/backend/integrations/nas.py @@ -1,4 +1,4 @@ -"""Statuts du NAS via le moniteur maison `nas_monitor` (`GET /api/status`). +"""Statuts du NAS via un moniteur HTTP exposant `GET /api/status`. Expose : occupation des disques de données (`/mnt/*`), santé des conteneurs Docker, et l'état du port forwardé entre gluetun (VPN) et qBittorrent. diff --git a/dev/probe_usage.py b/dev/probe_usage.py index 4c40aad..b71c084 100755 --- a/dev/probe_usage.py +++ b/dev/probe_usage.py @@ -5,10 +5,10 @@ Lit l'access token depuis un fichier .credentials.json (login Claude isolé) pui /usage. Affiche la structure JSON brute (uniquement des % d'usage, aucun secret) + l'interprétation de Monitorink. Sortie partageable sans risque. -Usage (sur le homelab, après le login isolé) : - python3 dev/probe_usage.py /home/jerem/.monitorink-claude/.credentials.json +Usage (sur le serveur, après le login isolé) : + python3 dev/probe_usage.py ~/.monitorink-claude/.credentials.json ou via env : - MONITORINK_CLAUDE_CREDS=/home/jerem/.monitorink-claude/.credentials.json python3 dev/probe_usage.py + MONITORINK_CLAUDE_CREDS=~/.monitorink-claude/.credentials.json python3 dev/probe_usage.py """ import json import os diff --git a/docker-compose.yml b/docker-compose.yml index 526a30f..2426f9e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,29 +5,31 @@ services: container_name: monitorink restart: unless-stopped env_file: .env - # Port HTTP direct sur le LAN pour la Kobo (busybox wget, sans Caddy/TLS). + # Port HTTP direct sur le LAN pour la Kobo (busybox wget, sans reverse proxy/TLS). ports: - "8899:8080" volumes: # Login Claude ISOLÉ dédié à Monitorink (lecture/écriture pour le refresh du token). - # Créé via: CLAUDE_CONFIG_DIR=/home/jerem/.monitorink-claude claude auth login - - /home/jerem/.monitorink-claude:/creds:rw - # Token openai-codex maintenu frais par Hermes (lecture seule) -> usage Codex. - # On monte le DOSSIER (pas le fichier) : Hermes réécrit auth.json par rename() + # Créé via: CLAUDE_CONFIG_DIR=$HOME/.monitorink-claude claude auth login + - ${HOME}/.monitorink-claude:/creds:rw + # Token openai-codex maintenu frais par un processus EXTERNE (lecture seule) -> Codex. + # On monte le DOSSIER (pas le fichier) : le producteur réécrit auth.json par rename() # atomique (nouvel inode), or un bind-mount de fichier unique reste accroché à # l'inode capturé au démarrage -> le conteneur servirait un token périmé (401). - # Monter le dossier fait re-résoudre /hermes/auth.json à chaque open(). - - /home/jerem/.hermes:/hermes:ro + # Monter le dossier fait re-résoudre /codex/auth.json à chaque open(). + # MONITORINK_CODEX_DIR = dossier hôte contenant auth.json (cf. .env). + - ${MONITORINK_CODEX_DIR:-${HOME}/.config/codex}:/codex:ro # Cache persistant des ratios trackers (survit aux redéploiements -> pas de - # re-login massif des 4 trackers après chaque rebuild). - - /home/jerem/.monitorink-data:/data:rw + # re-login massif des trackers après chaque rebuild). + - ${HOME}/.monitorink-data:/data:rw # Optionnel : burn rate via ccusage (lecture seule des logs Claude Code principaux). # Décommenter + MONITORINK_CCUSAGE=1. - # - /home/jerem/.claude/projects:/root/.claude/projects:ro + # - ${HOME}/.claude/projects:/root/.claude/projects:ro networks: - - nestorr + - proxy labels: - caddy: http://monitorink.homelab.nestor-server.fr + # Exemple pour caddy-docker-proxy ; MONITORINK_DOMAIN défini dans .env. + caddy: http://${MONITORINK_DOMAIN:-monitorink.example.com} caddy.reverse_proxy: "{{upstreams 8080}}" healthcheck: test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0) if urllib.request.urlopen('http://localhost:8080/health').status==200 else sys.exit(1)"] @@ -35,6 +37,8 @@ services: timeout: 10s retries: 3 +# Réseau du reverse proxy, déjà existant (external). Nom réel via MONITORINK_NETWORK (.env). networks: - nestorr: + proxy: external: true + name: ${MONITORINK_NETWORK:-monitorink-net} diff --git a/kobo/monitorink.sh b/kobo/monitorink.sh index 392c8e1..16298c5 100755 --- a/kobo/monitorink.sh +++ b/kobo/monitorink.sh @@ -13,8 +13,8 @@ BASE="/mnt/onboard/.adds/Monitorink" LOG="$BASE/monitorink.log" cd "$BASE" || exit 1 -# --- Configuration --- -export MONITORINK_URL="http://192.168.0.43:8899/image.png" +# --- Configuration --- (adapter à l'IP/host LAN de ton serveur Monitorink) +export MONITORINK_URL="http://192.168.1.50:8899/image.png" export MONITORINK_REFRESH=900 # PROD: refresh partiel 15 min (moins de réveils = batterie) # Cadence du full refresh : côté SERVEUR via MONITORINK_FULL_INTERVAL_MIN (défaut 120 = 2 h), # indépendante du cycle. Entre deux fulls, seuls les blocs modifiés sont rafraîchis (partiel). diff --git a/kobo/monitorinkloop.sh b/kobo/monitorinkloop.sh index dc0c8d6..9b6e5a6 100755 --- a/kobo/monitorinkloop.sh +++ b/kobo/monitorinkloop.sh @@ -9,7 +9,7 @@ BASE="$(dirname "$0")" cd "$BASE" || exit 1 -IMAGE_URL="${MONITORINK_URL:-https://monitorink.homelab.nestor-server.fr/image.png}" +IMAGE_URL="${MONITORINK_URL:-http://monitorink.local/image.png}" # Endpoints du refresh partiel, dérivés de l'URL image (.../image.png -> .../frame.meta|frame.png). BASE_URL="${IMAGE_URL%/image.png}" META_URL="$BASE_URL/frame.meta"