"""把“先持久化,再发一次 HTTP”固化成 T-304/T-306 的唯一集成入口。""" from __future__ import annotations from cmbuyer_client.core.errors import ( AmbiguousRemoteError, CredentialRemoteError, ManualRemoteError, ProtocolRemoteError, ) from cmbuyer_client.core.models import AssetReceipt, ClaimedTask, ScreenshotAsset from cmbuyer_client.core.ports import EvidenceSink, TaskSource from .store import LocalStateStore class DurableClientGateway: """不隐藏重试;每次方法调用最多发一次请求,结果不明保留原槽。""" def __init__(self, store: LocalStateStore, task_source: TaskSource, evidence_sink: EvidenceSink) -> None: self._store = store self._task_source = task_source self._evidence_sink = evidence_sink def claim_next(self, profile_id: str) -> ClaimedTask | None: request = self._store.prepare_claim(profile_id) credentials = self._store.load_profile(profile_id).credentials try: claimed = self._task_source.claim_next(credentials, request) except AmbiguousRemoteError: raise except CredentialRemoteError: raise except ProtocolRemoteError: self._store.mark_claim_terminal(profile_id, request, "PROTOCOL") raise except ManualRemoteError: self._store.mark_claim_terminal(profile_id, request, "MANUAL") raise if claimed is None: self._store.commit_claim_empty(profile_id, request) return None self._store.commit_claim_success(profile_id, request, claimed) return claimed def renew(self, profile_id: str): request = self._store.prepare_renew(profile_id) credentials = self._store.load_profile(profile_id).credentials try: result = self._task_source.renew(credentials, request) except AmbiguousRemoteError: raise except CredentialRemoteError: raise except ProtocolRemoteError: self._store.mark_renew_terminal(profile_id, request, "PROTOCOL") raise except ManualRemoteError: self._store.mark_renew_terminal(profile_id, request, "MANUAL") raise self._store.commit_renew_success(profile_id, request, result) return result def upload_evidence(self, profile_id: str, asset: ScreenshotAsset) -> AssetReceipt: prepared = self._store.prepare_or_resume_evidence(profile_id, asset) if isinstance(prepared, AssetReceipt): return prepared credentials = self._store.load_profile(profile_id).credentials try: receipt = self._evidence_sink.upload(credentials, prepared) except AmbiguousRemoteError: raise except CredentialRemoteError: raise except ProtocolRemoteError: self._store.mark_evidence_terminal(profile_id, prepared, "PROTOCOL") raise except ManualRemoteError: self._store.mark_evidence_terminal(profile_id, prepared, "MANUAL") raise self._store.commit_evidence_success(profile_id, prepared, receipt) return receipt