83 lines
3.2 KiB
Python
83 lines
3.2 KiB
Python
"""把“先持久化,再发一次 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
|