"""Constantes globales de la aplicación.""" import sys from pathlib import Path def _resolve_app_dir() -> Path: """Directorio donde vive el ejecutable (persistente).""" if getattr(sys, "frozen", False): return Path(sys.executable).resolve().parent return Path(__file__).resolve().parent.parent def _resolve_bundle_dir() -> Path: """Recursos embebidos en el binario PyInstaller onefile.""" if getattr(sys, "frozen", False): return Path(sys._MEIPASS) platform = "windows" if sys.platform == "win32" else "linux" return _resolve_app_dir() / "packaging" / "bundled" / platform APP_DIR = _resolve_app_dir() CONFIG_DIR = APP_DIR / "config" ENV_PATH = CONFIG_DIR / ".env" DATA_DIR = CONFIG_DIR / "data" LOGS_DIR = CONFIG_DIR / "logs" ODBC_DIR = CONFIG_DIR / "odbc" SEVEN_ZIP_DIR = CONFIG_DIR / "7zip" IS_WINDOWS = sys.platform == "win32" BUNDLE_DIR = _resolve_bundle_dir() BUNDLED_SOURCE_7ZIP = BUNDLE_DIR / "bundled" / "7zip" BUNDLED_SOURCE_ODBC = BUNDLE_DIR / "bundled" / "odbc" def _default_7zip_name() -> str: if IS_WINDOWS: return "7z.exe" return "7zz" BUNDLED_7ZIP_EXE = SEVEN_ZIP_DIR / _default_7zip_name() BUNDLED_7ZIP_FALLBACK = SEVEN_ZIP_DIR / ("7za.exe" if IS_WINDOWS else "7zz") # Carpetas de trabajo junto al ejecutable DIR_ENTRADA = APP_DIR / "Entrada" DIR_PROCESADOS = APP_DIR / "Procesados" DIR_FALLADOS = APP_DIR / "Fallados" DIR_TEMP = APP_DIR / "Temp" DB_PATH = DATA_DIR / "app.db" # Estados de jobs class JobStatus: QUEUED = "queued" EXTRACTING = "extracting" RESTORING = "restoring" CLEANING = "cleaning" COMPLETED = "completed" FAILED = "failed" FAILED_RESTART = "failed_restart" CANCELLED = "cancelled" class LogLevel: DEBUG = "DEBUG" INFO = "INFO" WARNING = "WARNING" ERROR = "ERROR" CRITICAL = "CRITICAL" class StepType: STABILITY_CHECK = "stability_check" NODE_MAPPING = "node_mapping" EXTRACT = "extract" LOCATE_BAK = "locate_bak" SQL_CONNECT = "sql_connect" FILELIST = "filelist" RESTORE = "restore" CLEANUP = "cleanup" SFTP_COPY = "sftp_copy" FORWARD_ZIP = "forward_zip" def default_seven_zip_path() -> str: for candidate in (BUNDLED_7ZIP_EXE, BUNDLED_7ZIP_FALLBACK): if candidate.exists(): return str(candidate) return "" def default_work_paths() -> dict[str, str]: return { "input_folder": str(DIR_ENTRADA), "processed_folder": str(DIR_PROCESADOS), "failed_folder": str(DIR_FALLADOS), "extract_folder": str(DIR_TEMP), "data_sql_folder": "", "seven_zip_exe": default_seven_zip_path(), } DEFAULT_CONFIG = { "paths": default_work_paths(), "sql": { "server": "localhost", "use_windows_auth": IS_WINDOWS, "username": "", "password_encrypted": "", }, "concurrency": { "extract_workers": 1, "restore_workers": 1, }, "stability": { "check_enabled": True, "check_interval_seconds": 5, "stable_duration_seconds": 10, "use_ready_marker": False, }, "timeouts": { "extract_minutes": 30, "restore_minutes": 60, }, "retries": { "max_attempts": 3, "retry_delay_seconds": 60, }, "features": { "dry_run_mode": False, "auto_scan_enabled": True, "scan_interval_seconds": 30, }, "panel": { "api_url": "", "api_token": "", "instance_key": "", "verify_ssl": False, }, }