Files
wyndham-ARR/arr_web/legacy_agent_services.py
2026-07-31 15:11:42 +08:00

144 lines
5.4 KiB
Python

"""Inactive ARR1 compatibility adapters; never imported by the ARR2 Web runtime."""
from __future__ import annotations
import os
import tempfile
import uuid
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Dict, Protocol
from arr_ingestion.contracts import IngestionError
from arr_ingestion.direct_contracts import SubmissionGrant
from arr_ingestion.repository import JobRegistration
from arr_processing.callbacks import AgentResultWriteback
from arr_processing.contracts import ProcessingRequest
from arr_processing.errors import ProcessingError
from arr_processing.runner import processing_dispatch_idempotency_key
from arr_storage.store import ManagedObjectStore
from arr_web.contracts import PortalError, validate_upload_filename, validate_xml_payload
class AgentResultCoordinator(Protocol):
def accept(self, raw_signed_result: bytes) -> Dict[str, Any]:
...
class ProcessingStarter(Protocol):
def start(self, request: ProcessingRequest) -> Any:
...
class DirectJobRepository(Protocol):
def register_job(self, registration: JobRegistration) -> None:
...
def issue_grant(
self, job_id: str, attempt_no: int, *, ttl_seconds: int
) -> SubmissionGrant:
...
@dataclass
class ProcessingAgentResultCoordinator:
writeback: AgentResultWriteback
def accept(self, raw_signed_result: bytes) -> Dict[str, Any]:
try:
return self.writeback.accept(raw_signed_result).to_dict()
except (IngestionError, ProcessingError) as error:
code = error.code
if code in {"PROCESSING_SIGNATURE_INVALID", "PROCESSING_SIGNATURE_EXPIRED"}:
status, message = 401, "Agent 结果签名无效或已过期"
elif code.endswith("_NOT_FOUND") or code in {
"JOB_NOT_FOUND",
"PROCESSING_JOB_NOT_FOUND",
}:
status, message = 404, "Agent 结果对应的业务任务不存在"
elif "CONFLICT" in code or code in {
"JOB_TERMINAL",
"PROCESSING_RESULT_MISMATCH",
}:
status, message = 409, "Agent 结果与现有业务任务冲突"
elif getattr(error, "retryable", False) or code.startswith("DATABASE_"):
status, message = 503, "Agent 结果暂时无法写入,请使用相同回调重试"
else:
status, message = 422, "Agent 结果未通过业务验收"
raise PortalError(code, message, status) from None
@dataclass
class ObjectStoreUploadCoordinator:
"""Frozen ARR1 upload/grant/remote-dispatch adapter for compatibility tests."""
object_store: ManagedObjectStore
ingestion_repository: DirectJobRepository
processing_starter: ProcessingStarter
processor_version: str
rule_set_sha256: str
submission_grant_ttl_seconds: int = 900
def submit(self, original_filename: str, payload: bytes) -> Dict[str, Any]:
uploaded_filename = validate_upload_filename(original_filename)
validate_xml_payload(payload)
job_id = "arrjob-" + uuid.uuid4().hex
attempt_no = 1
with tempfile.TemporaryDirectory(prefix="arr-web-upload-") as temporary:
source_path = Path(temporary) / "source.xml"
descriptor = os.open(source_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
try:
with os.fdopen(descriptor, "wb") as target:
descriptor = -1
target.write(payload)
target.flush()
os.fsync(target.fileno())
finally:
if descriptor >= 0:
os.close(descriptor)
stored = self.object_store.upload_committed(
job_id=job_id,
attempt_no=attempt_no,
role="source_xml",
source=source_path,
original_filename="source.xml",
)
source_file_id = "arr_file_" + uuid.uuid4().hex
request_without_grant = ProcessingRequest(
job_id=job_id,
attempt_no=attempt_no,
source_file_id=source_file_id,
processor_version=self.processor_version,
rule_set_sha256=self.rule_set_sha256,
)
self.ingestion_repository.register_job(
JobRegistration(
job_id=job_id,
source=stored.to_artifact_ref(),
processor_version=self.processor_version,
rule_set_sha256=self.rule_set_sha256,
attempt_no=attempt_no,
idempotency_key=processing_dispatch_idempotency_key(request_without_grant),
uploaded_filename=uploaded_filename,
)
)
grant = self.ingestion_repository.issue_grant(
job_id, attempt_no, ttl_seconds=self.submission_grant_ttl_seconds
)
request = ProcessingRequest(
job_id=job_id,
attempt_no=attempt_no,
source_file_id=source_file_id,
processor_version=self.processor_version,
rule_set_sha256=self.rule_set_sha256,
submission_grant=grant.submission_grant,
)
record = self.processing_starter.start(request)
return {
"job_id": job_id,
"status": str(getattr(record, "remote_status", "queued")),
"attempt_no": attempt_no,
"source_sha256": stored.sha256,
"source_byte_size": stored.byte_size,
}