Retry periodique email + spool galerie en cas de coupure internet
- Spool galerie booth : si upload echoue, photo stockee dans data/booth_spool.json et retentee toutes les 5 min - Email spool : retry periodique (5 min) au lieu de juste au demarrage - Les deux spools traites dans la meme boucle async - Message frontend spool : "sera envoyee des que possible" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import ftplib
|
||||
import json
|
||||
import logging
|
||||
import shutil
|
||||
import threading
|
||||
@@ -6,10 +7,13 @@ from pathlib import Path
|
||||
from urllib.request import Request, urlopen
|
||||
from urllib.error import URLError
|
||||
|
||||
from backend.config import charger_config, mettre_a_jour_config
|
||||
from backend.config import charger_config, mettre_a_jour_config, RACINE
|
||||
|
||||
log = logging.getLogger("photobooth.destinations")
|
||||
|
||||
FICHIER_BOOTH_SPOOL = RACINE / "data" / "booth_spool.json"
|
||||
_booth_spool_lock = threading.Lock()
|
||||
|
||||
|
||||
def distribuer_photo(chemin_photo: Path, imprimee: bool = False, copies: int = 1, format_papier: str | None = None):
|
||||
"""Copie la photo vers toutes les destinations activees."""
|
||||
@@ -118,7 +122,7 @@ def _upload_booth(url: str, api_key: str, event_id: str, chemin_photo: Path) ->
|
||||
|
||||
|
||||
def envoyer_booth(chemin_photo: Path, config_booth: dict):
|
||||
"""Envoie une photo vers la galerie live booth."""
|
||||
"""Envoie une photo vers la galerie live booth. En cas d'echec, met en spool."""
|
||||
url = config_booth.get("url", "").rstrip("/")
|
||||
url_tunnel = config_booth.get("url_tunnel", "").rstrip("/")
|
||||
api_key = config_booth.get("api_key", "")
|
||||
@@ -137,9 +141,93 @@ def envoyer_booth(chemin_photo: Path, config_booth: dict):
|
||||
log.error(f"Booth erreur HTTP via {tentative_url}")
|
||||
except (URLError, OSError) as e:
|
||||
log.warning(f"Echec envoi booth via {tentative_url} : {e}")
|
||||
|
||||
_ajouter_booth_spool(str(chemin_photo))
|
||||
return False
|
||||
|
||||
|
||||
# --- Spool galerie booth ---
|
||||
|
||||
def _ajouter_booth_spool(chemin: str):
|
||||
with _booth_spool_lock:
|
||||
spool = _charger_booth_spool()
|
||||
if chemin not in spool:
|
||||
spool.append(chemin)
|
||||
_sauver_booth_spool(spool)
|
||||
log.info(f"Photo mise en spool galerie ({len(spool)} en attente)")
|
||||
|
||||
|
||||
def _charger_booth_spool() -> list:
|
||||
if not FICHIER_BOOTH_SPOOL.exists():
|
||||
return []
|
||||
try:
|
||||
with open(FICHIER_BOOTH_SPOOL, "r") as f:
|
||||
return json.load(f)
|
||||
except (json.JSONDecodeError, OSError):
|
||||
return []
|
||||
|
||||
|
||||
def _sauver_booth_spool(spool: list):
|
||||
try:
|
||||
with open(FICHIER_BOOTH_SPOOL, "w") as f:
|
||||
json.dump(spool, f)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
def taille_booth_spool() -> int:
|
||||
with _booth_spool_lock:
|
||||
return len(_charger_booth_spool())
|
||||
|
||||
|
||||
def traiter_booth_spool() -> int:
|
||||
"""Retente l'envoi des photos en spool. Retourne le nombre envoyees."""
|
||||
with _booth_spool_lock:
|
||||
spool = _charger_booth_spool()
|
||||
if not spool:
|
||||
return 0
|
||||
|
||||
config = charger_config()
|
||||
booth = config.get("booth", {})
|
||||
if not booth.get("actif", False):
|
||||
return 0
|
||||
|
||||
envoyes = 0
|
||||
restants = []
|
||||
for chemin_str in spool:
|
||||
chemin = Path(chemin_str)
|
||||
if not chemin.exists():
|
||||
log.warning(f"Spool booth: photo introuvable {chemin}, ignoree")
|
||||
continue
|
||||
url = booth.get("url", "").rstrip("/")
|
||||
url_tunnel = booth.get("url_tunnel", "").rstrip("/")
|
||||
api_key = booth.get("api_key", "")
|
||||
event_id = config.get("evenement", {}).get("event_id") or booth.get("event_id", "default")
|
||||
ok = False
|
||||
for tentative_url in [u for u in (url_tunnel, url) if u]:
|
||||
try:
|
||||
if _upload_booth(tentative_url, api_key, event_id, chemin):
|
||||
log.info(f"Spool booth: {chemin.name} envoyee via {tentative_url}")
|
||||
ok = True
|
||||
break
|
||||
except (URLError, OSError):
|
||||
pass
|
||||
if ok:
|
||||
envoyes += 1
|
||||
else:
|
||||
restants.append(chemin_str)
|
||||
break
|
||||
|
||||
if envoyes > 0 or len(restants) < len(spool):
|
||||
idx = envoyes + len(restants)
|
||||
restants.extend(spool[idx:])
|
||||
with _booth_spool_lock:
|
||||
_sauver_booth_spool(restants)
|
||||
log.info(f"Spool booth: {envoyes} envoyee(s), {len(restants)} en attente")
|
||||
|
||||
return envoyes
|
||||
|
||||
|
||||
def recuperer_booth_password() -> dict:
|
||||
"""Recupere le mot de passe et l'info de la session booth."""
|
||||
config = charger_config()
|
||||
|
||||
Reference in New Issue
Block a user