mirror of
https://github.com/MemeMeow-Studio/MemeMeow.git
synced 2026-10-29 06:06:47 +08:00
70 lines
3.6 KiB
Python
70 lines
3.6 KiB
Python
# 上传接收任务的授权关联,复用 operation policy 与持久 grant 仓储。
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Callable
|
|
|
|
from backend.operation_policy import OperationPolicyError, Operations
|
|
|
|
|
|
class UploadAuthorization:
|
|
"""以接收任务标识关联容量预留,图片登记后完成正式计量。"""
|
|
|
|
def __init__(self, scope: Any, gateway: Any, store: Any, *, release: Callable[..., Any], bind: Callable[..., Any] | None = None):
|
|
"""接收可信 scope、策略仓储及宿主释放和容量绑定接口。"""
|
|
self.scope = scope
|
|
self.gateway = gateway
|
|
self.store = store
|
|
self.release = release
|
|
self.bind = bind
|
|
|
|
def request(self, payload: dict[str, Any]) -> Any:
|
|
"""从持久接收字段生成相同 attempt 内稳定的授权请求。"""
|
|
task_id = payload.get("authorization_task_id", payload["receipt_id"])
|
|
return self.gateway.request(self.scope, Operations.IMAGE_UPLOAD, f"upload-receipt:{task_id}", resource_id=payload["receipt_id"], task_id=task_id, source="upload", input_digest=payload["input_digest"])
|
|
|
|
def reserve(self, payload: dict[str, Any]) -> None:
|
|
"""在上传接收或显式重试时预留一个图片名额。"""
|
|
request = self.request(payload)
|
|
existing = self.store.get(request)
|
|
if existing is not None and existing.state == "committed":
|
|
return
|
|
if existing is not None and existing.state == "released":
|
|
# 已释放的预留需要新的授权身份;已计量的身份始终复用。
|
|
payload["authorization_task_id"] = payload["_claim_task_id"]
|
|
from backend.upload_receipts import UploadReceipts
|
|
|
|
receipts = UploadReceipts(self.store.resources, self.scope, None)
|
|
with receipts.resources.environment(self.scope) as environment:
|
|
receipt = environment.tasks.get(payload["receipt_id"], for_update=True)
|
|
receipt.payload = {**receipt.payload, "authorization_task_id": payload["authorization_task_id"]}
|
|
request = self.request(payload)
|
|
self.store.acquire(request, self.gateway)
|
|
|
|
def finish(self, payload: dict[str, Any], meme_id: str, owned: bool) -> None:
|
|
"""依据图片来源完成计量,重复已有图片时释放本次预留。"""
|
|
association = self.store.get(self.request(payload))
|
|
if association is None:
|
|
raise OperationPolicyError("operation_grant_invalid")
|
|
if association.state == "committed":
|
|
return
|
|
if not owned:
|
|
self.release(association.grant)
|
|
return
|
|
if self.bind is not None and not self.bind(association.grant, meme_id):
|
|
raise OperationPolicyError("operation_grant_invalid")
|
|
result = self.gateway.commit(association.grant)
|
|
if not result.ok or result.state not in {"committed", "already_committed"}:
|
|
raise OperationPolicyError(result.reason or "operation_policy_unavailable")
|
|
if not self.store.transition(association.grant, "committed"):
|
|
raise OperationPolicyError("operation_grant_invalid")
|
|
|
|
def discard(self, payload: dict[str, Any]) -> None:
|
|
"""在确认未登记图片后释放已有接收预留,不创建新的授权。"""
|
|
if not payload.get("input_digest"):
|
|
return
|
|
association = self.store.get(self.request(payload))
|
|
if association is not None and association.state in {"acquired", "unknown"}:
|
|
# 调用方已确认未登记图片,恢复程序记录的 unknown 也能依据该事实释放。
|
|
self.release(association.grant)
|