"""Local entry point. Production injects private OSS and processing adapters.""" from __future__ import annotations import argparse import sys from pathlib import Path from typing import Any, Callable, Dict, Optional, Sequence from arr_web.app import PortalApplication, RuntimeHealth from arr_web.agent_writeback_runtime import ( AgentWritebackRuntime, compose_oss_agent_writeback, ) from arr_web.company_jobs import ( PersistentCompanyReportCoordinator, ProgramCompanyReportExecutor, ) from arr_web.downloads import ControlledProjectArtifactReader from arr_web.repository import PostgresPortalRepository, UnavailablePortalRepository from arr_web.processing_runtime import ( ProcessingInputRuntime, compose_oss_processing_input, ) from arr_web.server import serve from arr_web.services import ProgramMonthlyCoordinator from monthly_reports.publishing import ArtifactToolBuilder, AtomicReportPublisher from monthly_reports.repository import DatabaseConfig, PostgresReportRepository from monthly_reports.service import MonthlyReportService from company_reports.publishing import ( ArtifactToolBuilder as CompanyArtifactToolBuilder, AtomicReportPublisher as AtomicCompanyReportPublisher, ) from company_reports.repository import ( DatabaseConfig as CompanyDatabaseConfig, PostgresReportRepository as PostgresCompanyReportRepository, ) from company_reports.service import CompanyReportService PROJECT_ROOT = Path(__file__).resolve().parents[1] def _parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(prog="arr-web") parser.add_argument("--host", default="127.0.0.1") parser.add_argument("--port", type=int, default=8765) parser.add_argument( "--db-config", type=Path, help="local controlled ARR_DB_* env file; values are never logged", ) parser.add_argument( "--driver-path", type=Path, help="optional local directory containing the PostgreSQL driver", ) parser.add_argument( "--enable-monthly-generation", action="store_true", help="enable the database monthly-report mutation endpoint", ) parser.add_argument( "--enable-company-reports", action="store_true", help="enable Bangkok-gated five-company channel-detail jobs", ) parser.add_argument( "--enable-agent-writeback", action="store_true", help="enable signed Super Agent result callbacks backed by private OSS", ) parser.add_argument( "--enable-processing", action="store_true", help="enable private OSS upload and Open Agent dispatch", ) parser.add_argument( "--secure-cookies", action="store_true", help="mark browser session cookies Secure for an HTTPS deployment", ) parser.add_argument("--node-binary", type=Path) parser.add_argument("--artifact-tool-module", type=Path) return parser def _read_controlled_database(path: Path) -> Dict[str, object]: values: Dict[str, str] = {} for raw in path.read_text(encoding="utf-8").splitlines(): line = raw.strip() if not line or line.startswith("#") or "=" not in line: continue key, value = line.split("=", 1) values[key.strip()] = value.strip().strip('"').strip("'") required = ("ARR_DB_HOST", "ARR_DB_PORT", "ARR_DB_USER", "ARR_DB_PASSWORD", "ARR_DB_NAME") if any(not values.get(key) for key in required): raise ValueError("controlled database configuration is incomplete") return { "host": values["ARR_DB_HOST"], "port": int(values["ARR_DB_PORT"]), "user": values["ARR_DB_USER"], "password": values["ARR_DB_PASSWORD"], "dbname": values["ARR_DB_NAME"], } def _controlled_connect( config_path: Path, driver_path: Optional[Path], ) -> Callable[[str], Any]: if driver_path is not None: resolved = driver_path.expanduser().resolve() if not resolved.is_dir(): raise ValueError("database driver path is unavailable") sys.path.insert(0, str(resolved)) import psycopg # type: ignore[import-not-found] parameters = _read_controlled_database(config_path.expanduser().resolve()) def connect(_dsn: str) -> Any: return psycopg.connect(**parameters, autocommit=False) return connect def main(argv: Optional[Sequence[str]] = None) -> int: args = _parser().parse_args(argv) connect: Optional[Callable[[str], Any]] = None try: if args.db_config: connect = _controlled_connect(args.db_config, args.driver_path) repository = PostgresPortalRepository("controlled", connect=connect) else: repository = PostgresPortalRepository.from_environment() repository.list_months() database_ready = True except Exception: repository = UnavailablePortalRepository() database_ready = False monthly = None monthly_ready = False if args.enable_monthly_generation and database_ready: try: report_repository = PostgresReportRepository( DatabaseConfig("controlled"), connect=connect, ) if connect is not None else PostgresReportRepository(DatabaseConfig.from_environment()) builder = ArtifactToolBuilder( PROJECT_ROOT / "monthly_reports" / "xlsx" / "build_workbook.mjs", node_binary=str(args.node_binary) if args.node_binary else None, artifact_tool_module=args.artifact_tool_module, ) output_root = PROJECT_ROOT / "outputs" / "monthly_reports" monthly = ProgramMonthlyCoordinator( MonthlyReportService( report_repository, builder, AtomicReportPublisher(PROJECT_ROOT, output_root), output_root / ".staging", ) ) monthly_ready = True except Exception: monthly = None monthly_ready = False company_reports = None company_reports_ready = False if args.enable_company_reports and database_ready: try: company_repository = ( PostgresCompanyReportRepository( CompanyDatabaseConfig("controlled"), connect=connect, ) if connect is not None else PostgresCompanyReportRepository( CompanyDatabaseConfig.from_environment() ) ) company_builder = CompanyArtifactToolBuilder( PROJECT_ROOT / "company_reports" / "xlsx" / "build_workbook.mjs", node_binary=str(args.node_binary) if args.node_binary else None, artifact_tool_module=args.artifact_tool_module, ) company_output_root = PROJECT_ROOT / "outputs" / "company_reports" company_service = CompanyReportService( company_repository, company_builder, AtomicCompanyReportPublisher(PROJECT_ROOT, company_output_root), company_output_root / ".staging", ) company_reports = PersistentCompanyReportCoordinator( PROJECT_ROOT, company_output_root, ProgramCompanyReportExecutor(company_service), ) company_reports_ready = True except Exception: company_reports = None company_reports_ready = False agent_writeback: Optional[AgentWritebackRuntime] = None agent_writeback_ready = False if args.enable_agent_writeback and database_ready: try: agent_writeback = compose_oss_agent_writeback( project_root=PROJECT_ROOT, connect=connect, ) agent_writeback_ready = True except Exception: agent_writeback = None agent_writeback_ready = False processing_input: Optional[ProcessingInputRuntime] = None processing_ready = False if args.enable_processing and database_ready: try: processing_input = compose_oss_processing_input( project_root=PROJECT_ROOT, connect=connect, ) processing_ready = True except Exception: processing_input = None processing_ready = False application = PortalApplication( repository=repository, upload=( processing_input.coordinator if processing_input is not None else None ), agent_results=( agent_writeback.coordinator if agent_writeback is not None else None ), monthly=monthly, company_reports=company_reports, artifact_reader=( ControlledProjectArtifactReader(PROJECT_ROOT) if database_ready else None ), health=RuntimeHealth( database_ready=database_ready, upload_ready=processing_ready, monthly_ready=monthly_ready, download_ready=database_ready, company_reports_ready=company_reports_ready, agent_writeback_ready=agent_writeback_ready, ), secure_cookies=args.secure_cookies, ) try: serve(application, args.host, args.port) finally: if company_reports is not None: company_reports.close() if agent_writeback is not None: agent_writeback.close() if processing_input is not None: processing_input.close() return 0 if __name__ == "__main__": raise SystemExit(main())