201 lines
7.0 KiB
Python
201 lines
7.0 KiB
Python
"""Carga de variables desde config/.env."""
|
|
|
|
import os
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
from ..constants import (
|
|
APP_DIR,
|
|
DIR_ENTRADA,
|
|
DIR_FALLADOS,
|
|
DIR_PROCESADOS,
|
|
DIR_TEMP,
|
|
ENV_PATH,
|
|
default_seven_zip_path,
|
|
)
|
|
from ..utils.logger import app_logger
|
|
|
|
|
|
def _env_bool(name: str, default: bool = False) -> bool:
|
|
raw = os.getenv(name, "").strip().lower()
|
|
if not raw:
|
|
return default
|
|
return raw in ("1", "true", "yes", "on")
|
|
|
|
|
|
def _env_int(
|
|
name: str,
|
|
default: int,
|
|
*,
|
|
min_value: int | None = None,
|
|
max_value: int | None = None,
|
|
) -> int:
|
|
"""Lee un entero de entorno con validación; ante valor inválido loguea y usa el default."""
|
|
raw = os.getenv(name, "").strip()
|
|
if not raw:
|
|
return default
|
|
try:
|
|
value = int(raw)
|
|
except ValueError:
|
|
app_logger.warning(f"{name}='{raw}' no es un entero válido; se usa {default}")
|
|
return default
|
|
if min_value is not None and value < min_value:
|
|
app_logger.warning(f"{name}={value} < {min_value} (mínimo); se usa {default}")
|
|
return default
|
|
if max_value is not None and value > max_value:
|
|
app_logger.warning(f"{name}={value} > {max_value} (máximo); se usa {default}")
|
|
return default
|
|
return value
|
|
|
|
|
|
def load_env_file() -> bool:
|
|
"""Carga config/.env si existe."""
|
|
if ENV_PATH.is_file():
|
|
load_dotenv(ENV_PATH, override=True)
|
|
return True
|
|
return False
|
|
|
|
|
|
def is_panel_configured() -> bool:
|
|
"""True si URL, token e instancia del panel están definidos."""
|
|
url = os.getenv("CLOUDRESTORE_PANEL_API_URL", "").strip()
|
|
token = os.getenv("CLOUDRESTORE_PANEL_API_TOKEN", "").strip()
|
|
instance = os.getenv("CLOUDRESTORE_PANEL_INSTANCE_KEY", "").strip()
|
|
return bool(url and token and instance)
|
|
|
|
|
|
@dataclass
|
|
class LaunchOptions:
|
|
minimized: bool
|
|
start_engine: bool
|
|
register_autostart: bool
|
|
|
|
|
|
def get_launch_options() -> LaunchOptions:
|
|
load_env_file()
|
|
return LaunchOptions(
|
|
minimized=_env_bool("CLOUDRESTORE_START_MINIMIZED", False),
|
|
start_engine=_env_bool("CLOUDRESTORE_AUTO_START", True),
|
|
register_autostart=_env_bool("CLOUDRESTORE_REGISTER_AUTOSTART", True),
|
|
)
|
|
|
|
|
|
def _path_from_env(name: str, default: Path) -> str:
|
|
value = os.getenv(name, "").strip()
|
|
return value if value else str(default)
|
|
|
|
|
|
def apply_env_overrides(config: dict) -> dict:
|
|
"""Aplica variables de entorno sobre la configuración en memoria."""
|
|
load_env_file()
|
|
|
|
paths = config.setdefault("paths", {})
|
|
paths["input_folder"] = _path_from_env("CLOUDRESTORE_INPUT_FOLDER", DIR_ENTRADA)
|
|
paths["processed_folder"] = _path_from_env(
|
|
"CLOUDRESTORE_PROCESSED_FOLDER", DIR_PROCESADOS
|
|
)
|
|
paths["failed_folder"] = _path_from_env("CLOUDRESTORE_FAILED_FOLDER", DIR_FALLADOS)
|
|
paths["extract_folder"] = _path_from_env("CLOUDRESTORE_EXTRACT_FOLDER", DIR_TEMP)
|
|
data_sql = os.getenv("CLOUDRESTORE_DATA_SQL_FOLDER", "").strip()
|
|
if data_sql:
|
|
paths["data_sql_folder"] = data_sql
|
|
|
|
seven_zip = os.getenv("CLOUDRESTORE_SEVEN_ZIP_EXE", "").strip()
|
|
paths["seven_zip_exe"] = seven_zip or default_seven_zip_path()
|
|
|
|
panel = config.setdefault("panel", {})
|
|
api_url = os.getenv("CLOUDRESTORE_PANEL_API_URL", "").strip()
|
|
if api_url:
|
|
panel["api_url"] = api_url
|
|
api_token = os.getenv("CLOUDRESTORE_PANEL_API_TOKEN", "").strip()
|
|
if api_token:
|
|
panel["api_token"] = api_token
|
|
instance = os.getenv("CLOUDRESTORE_PANEL_INSTANCE_KEY", "").strip()
|
|
if instance:
|
|
panel["instance_key"] = instance
|
|
if os.getenv("CLOUDRESTORE_PANEL_VERIFY_SSL"):
|
|
panel["verify_ssl"] = _env_bool("CLOUDRESTORE_PANEL_VERIFY_SSL", False)
|
|
|
|
sql = config.setdefault("sql", {})
|
|
server = os.getenv("CLOUDRESTORE_SQL_SERVER", "").strip()
|
|
if server:
|
|
sql["server"] = server
|
|
if os.getenv("CLOUDRESTORE_SQL_USERNAME"):
|
|
sql["username"] = os.getenv("CLOUDRESTORE_SQL_USERNAME", "").strip()
|
|
if os.getenv("CLOUDRESTORE_SQL_USE_WINDOWS_AUTH"):
|
|
sql["use_windows_auth"] = _env_bool("CLOUDRESTORE_SQL_USE_WINDOWS_AUTH", False)
|
|
|
|
retention = config.setdefault("retention", {})
|
|
if os.getenv("CLOUDRESTORE_RETENTION_ENABLED"):
|
|
retention["enabled"] = _env_bool("CLOUDRESTORE_RETENTION_ENABLED", True)
|
|
if os.getenv("CLOUDRESTORE_RETENTION_DAYS"):
|
|
retention["days"] = _env_int(
|
|
"CLOUDRESTORE_RETENTION_DAYS", retention.get("days", 2), min_value=0
|
|
)
|
|
if os.getenv("CLOUDRESTORE_RETENTION_FAILED_DAYS"):
|
|
retention["failed_days"] = _env_int(
|
|
"CLOUDRESTORE_RETENTION_FAILED_DAYS", retention.get("failed_days", 7), min_value=0
|
|
)
|
|
if os.getenv("CLOUDRESTORE_RETENTION_RUN_AT_HOUR"):
|
|
retention["run_at_hour"] = _env_int(
|
|
"CLOUDRESTORE_RETENTION_RUN_AT_HOUR",
|
|
retention.get("run_at_hour", 3),
|
|
min_value=0,
|
|
max_value=23,
|
|
)
|
|
if os.getenv("CLOUDRESTORE_RETENTION_CHECK_INTERVAL_SECONDS"):
|
|
retention["check_interval_seconds"] = _env_int(
|
|
"CLOUDRESTORE_RETENTION_CHECK_INTERVAL_SECONDS",
|
|
retention.get("check_interval_seconds", 3600),
|
|
min_value=60,
|
|
)
|
|
if os.getenv("CLOUDRESTORE_RETENTION_DRY_RUN"):
|
|
retention["dry_run"] = _env_bool("CLOUDRESTORE_RETENTION_DRY_RUN", True)
|
|
|
|
return config
|
|
|
|
|
|
def render_env_template(app_dir: Path | None = None) -> str:
|
|
"""Genera contenido inicial de config/.env."""
|
|
base = (app_dir or APP_DIR).resolve()
|
|
sep = "\\" if os.name == "nt" else "/"
|
|
|
|
def p(*parts: str) -> str:
|
|
return sep.join([str(base), *parts])
|
|
|
|
return f"""# CloudRestoreAS — configuración local (editar y reiniciar la app)
|
|
|
|
# Arranca el motor al abrir. La ventana SIEMPRE se muestra al iniciar; cerrar (X) la
|
|
# minimiza a la bandeja del sistema (START_MINIMIZED ya no oculta la ventana).
|
|
CLOUDRESTORE_AUTO_START=true
|
|
CLOUDRESTORE_START_MINIMIZED=false
|
|
CLOUDRESTORE_REGISTER_AUTOSTART=true
|
|
|
|
# Servicio PANEL_BASES_ANEXO24 (enrutamiento automático de nodos)
|
|
CLOUDRESTORE_PANEL_API_URL=
|
|
CLOUDRESTORE_PANEL_API_TOKEN=
|
|
CLOUDRESTORE_PANEL_INSTANCE_KEY=
|
|
CLOUDRESTORE_PANEL_VERIFY_SSL=false
|
|
|
|
# Carpetas de trabajo
|
|
CLOUDRESTORE_INPUT_FOLDER={p("Entrada")}
|
|
CLOUDRESTORE_PROCESSED_FOLDER={p("Procesados")}
|
|
CLOUDRESTORE_FAILED_FOLDER={p("Fallados")}
|
|
CLOUDRESTORE_EXTRACT_FOLDER={p("Temp")}
|
|
|
|
# SQL local (solo si no usa panel para credenciales)
|
|
# CLOUDRESTORE_SQL_SERVER=localhost
|
|
# CLOUDRESTORE_SQL_USERNAME=
|
|
# CLOUDRESTORE_DATA_SQL_FOLDER=
|
|
|
|
# Retención (limpieza diaria de respaldos obsoletos para no saturar el disco)
|
|
# CLOUDRESTORE_RETENTION_ENABLED=true
|
|
# CLOUDRESTORE_RETENTION_DAYS=2 # Procesados: por nodo, respecto al más reciente
|
|
# CLOUDRESTORE_RETENTION_FAILED_DAYS=7 # Fallados: por antigüedad absoluta
|
|
# CLOUDRESTORE_RETENTION_RUN_AT_HOUR=3 # hora local de la corrida diaria (0-23)
|
|
# CLOUDRESTORE_RETENTION_CHECK_INTERVAL_SECONDS=3600
|
|
# CLOUDRESTORE_RETENTION_DRY_RUN=true # true = solo simula; poner false para borrar
|
|
"""
|