"""Production composition for ARR-owned programmatic XML processing.""" from __future__ import annotations import os from dataclasses import dataclass from pathlib import Path from typing import Any, Callable, Optional from arr_ingestion.postgres import DatabaseConfig, PostgresIngestionRepository from arr_ingestion.service import IngestionService from arr_ingestion.validation import DeliveryValidator from arr_processing.local import LocalDailyProcessor from arr_processing.policy import load_processor_policy from arr_storage.aliyun_oss_v2 import AliyunOssConfig, AliyunOssV2Client from arr_storage.contracts import ObjectKeyPolicy from arr_storage.remote import CloudObjectBackend from arr_storage.store import ManagedObjectStore from arr_web.programmatic import ProgrammaticUploadCoordinator @dataclass class ProcessingInputRuntime: coordinator: ProgrammaticUploadCoordinator oss_client: AliyunOssV2Client object_store: ManagedObjectStore def close(self) -> None: self.oss_client.close() @dataclass class ObjectStoreRuntime: """Shared OSS/object-store runtime for report publishers and downloads.""" oss_client: AliyunOssV2Client object_store: ManagedObjectStore def close(self) -> None: self.oss_client.close() def compose_object_store() -> ObjectStoreRuntime: oss_client = AliyunOssV2Client(AliyunOssConfig.from_environment()) try: oss_client.assert_immutable_writes_supported() object_store = ManagedObjectStore( CloudObjectBackend(oss_client), ObjectKeyPolicy(os.environ.get("ARR_OBJECT_PREFIX", "arr")), ) return ObjectStoreRuntime(oss_client, object_store) except Exception: try: oss_client.close() except Exception: pass raise def compose_programmatic_processing( *, project_root: Path, connect: Optional[Callable[[str], Any]] = None, ) -> ProcessingInputRuntime: storage = compose_object_store() try: oss_client = storage.oss_client object_store = storage.object_store database_config = ( DatabaseConfig("controlled") if connect is not None else DatabaseConfig.from_environment() ) repository = PostgresIngestionRepository( database_config, connect=connect, ) policy = load_processor_policy(project_root) coordinator = ProgrammaticUploadCoordinator( object_store=object_store, ingestion_repository=repository, ingestion_service=IngestionService( DeliveryValidator(object_store, policy), repository, ), processor=LocalDailyProcessor(policy), processor_version=policy.processor_version, rule_set_sha256=policy.rule_set_sha256, ) return ProcessingInputRuntime(coordinator, oss_client, object_store) except Exception: storage.close() raise # Compatibility name for older local launch wrappers. compose_oss_processing_input = compose_programmatic_processing