- Reemplaza config_loader/config_model/hana_client/logger_utilities/outlook_utilities por core.py (pipeline funcional), hana_manager.py, logger_manager.py, scheduler.py y descargador_sovos.py (Playwright/Firefox) según la plantilla de servicios. - main.py pasa a loop continuo dirigido por scheduler.json, con manejo de SIGINT/SIGTERM. - Agrega Dockerfile, docker-compose.yml (restart unless-stopped) y certs/ para despliegue. - Agrega smb_transfer.py para la transferencia a carpeta compartida. - Saca las credenciales de HANA de config.json y las mueve a .env (HANA_HOST/PORT/USER/PASSWORD).
62 lines
2.2 KiB
Python
62 lines
2.2 KiB
Python
"""scheduler.py — franja horaria activa para el while loop de main.py.
|
|
|
|
Lee scheduler.json (HORARIOS + DIAS_ACTIVOS) y responde dos preguntas:
|
|
* franja_actual(): si ahora cae dentro de una franja, con qué modo.
|
|
* proximo_inicio(): si no, cuándo empieza la próxima franja activa.
|
|
"""
|
|
import json
|
|
from pathlib import Path
|
|
from datetime import datetime, timedelta
|
|
|
|
# ============================================================================
|
|
SCHEDULER_FILE = Path(__file__).parent / "scheduler.json"
|
|
|
|
INTERVALOS_POR_MODO = {
|
|
"rapido": 10 * 60,
|
|
"full": 60 * 60,
|
|
}
|
|
|
|
# ============================================================================
|
|
def cargar_scheduler(path: Path | None = None) -> dict:
|
|
p = path or SCHEDULER_FILE
|
|
with open(p, encoding="utf-8") as f:
|
|
return json.load(f)
|
|
|
|
|
|
def _minutos(hora: int, minuto: int) -> int:
|
|
return hora * 60 + minuto
|
|
|
|
|
|
def franja_actual(cfg: dict, ahora: datetime) -> dict | None:
|
|
if ahora.weekday() not in cfg.get("DIAS_ACTIVOS", []):
|
|
return None
|
|
|
|
minutos_ahora = _minutos(ahora.hour, ahora.minute)
|
|
for h_ini, m_ini, h_fin, m_fin, modo in cfg.get("HORARIOS", []):
|
|
if _minutos(h_ini, m_ini) <= minutos_ahora < _minutos(h_fin, m_fin):
|
|
return {"modo": modo, "intervalo": INTERVALOS_POR_MODO.get(modo, 600)}
|
|
return None
|
|
|
|
|
|
def proximo_inicio(cfg: dict, ahora: datetime) -> datetime:
|
|
dias_activos = cfg.get("DIAS_ACTIVOS", [])
|
|
horarios = cfg.get("HORARIOS", [])
|
|
if not dias_activos or not horarios:
|
|
raise ValueError("scheduler.json sin DIAS_ACTIVOS o HORARIOS configurados")
|
|
|
|
for delta in range(0, 8):
|
|
candidato = ahora + timedelta(days=delta)
|
|
if candidato.weekday() not in dias_activos:
|
|
continue
|
|
inicios = []
|
|
for h_ini, m_ini, h_fin, m_fin, _modo in horarios:
|
|
inicio = candidato.replace(hour=h_ini, minute=m_ini, second=0, microsecond=0)
|
|
if delta == 0 and inicio <= ahora:
|
|
continue
|
|
inicios.append(inicio)
|
|
if inicios:
|
|
return min(inicios)
|
|
|
|
raise ValueError("No se encontró una próxima franja activa en los próximos 7 días")
|
|
# ============================================================================
|