feat: sync latest ARR implementation
This commit is contained in:
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Dict, Protocol
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import quote, urlparse
|
||||
|
||||
from arr_ingestion.contracts import ArtifactRef, ROLE_CONTRACTS
|
||||
from arr_processing.contracts import ProcessingRequest, canonical_json_bytes
|
||||
@@ -13,7 +13,7 @@ from arr_storage.aliyun_oss_v2 import AliyunOssConfig
|
||||
from arr_storage.contracts import valid_object_key
|
||||
|
||||
|
||||
PROGRAM_INPUT_VERSION = "arr-opera-daily-program-input-2"
|
||||
PROGRAM_INPUT_VERSION = "arr-opera-daily-program-input-3"
|
||||
|
||||
|
||||
class ProcessingSourceResolver(Protocol):
|
||||
@@ -23,12 +23,12 @@ class ProcessingSourceResolver(Protocol):
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class OssProcessingMessageBuilder:
|
||||
"""Resolve the ARR-owned source object and expose only non-secret OSS routing.
|
||||
"""Resolve one ARR-owned source to its public-read HTTPS object URL.
|
||||
|
||||
``fetch_oss_file`` owns the download and its credential provider. The Agent
|
||||
receives the same attachment-shaped descriptor used by the existing hotel
|
||||
runtime: bucket, endpoint host, exact object key, hash and size. AccessKey,
|
||||
Secret, local paths and signed URLs never enter the message.
|
||||
The Agent receives an attachment-shaped descriptor containing the exact URL
|
||||
that ``fetch_oss_file`` must use, plus non-secret provenance and integrity
|
||||
fields. AccessKey, Secret, local paths and signed URLs never enter the
|
||||
message.
|
||||
"""
|
||||
|
||||
config: AliyunOssConfig
|
||||
@@ -37,6 +37,7 @@ class OssProcessingMessageBuilder:
|
||||
def message(self, request: ProcessingRequest) -> str:
|
||||
source = self.sources.source_for_attempt(request.job_id, request.attempt_no)
|
||||
self._validate_source(request, source)
|
||||
endpoint_host = self._endpoint_host()
|
||||
if request.submission_grant is None:
|
||||
raise ProcessingError(
|
||||
"PROCESSING_SUBMISSION_GRANT_MISSING",
|
||||
@@ -60,8 +61,12 @@ class OssProcessingMessageBuilder:
|
||||
"source_ref": {"source": "oss_attachments", "index": 0},
|
||||
"oss": {
|
||||
"bucket": self.config.bucket,
|
||||
"endpoint": self._endpoint_host(),
|
||||
"endpoint": endpoint_host,
|
||||
"object_key": source.object_key,
|
||||
"url": self._public_object_url(
|
||||
endpoint_host,
|
||||
source.object_key,
|
||||
),
|
||||
},
|
||||
}
|
||||
],
|
||||
@@ -101,12 +106,22 @@ class OssProcessingMessageBuilder:
|
||||
)
|
||||
|
||||
def _endpoint_host(self) -> str:
|
||||
expected_host = f"oss-{self.config.region}.aliyuncs.com"
|
||||
if self.config.endpoint:
|
||||
parsed = urlparse(self.config.endpoint)
|
||||
if parsed.scheme != "https" or not parsed.hostname:
|
||||
if (
|
||||
parsed.scheme != "https"
|
||||
or parsed.hostname != expected_host
|
||||
or parsed.username is not None
|
||||
or parsed.password is not None
|
||||
or parsed.port is not None
|
||||
):
|
||||
raise ProcessingError(
|
||||
"PROCESSING_SOURCE_INVALID",
|
||||
"OSS endpoint is unavailable",
|
||||
"public OSS endpoint is unavailable",
|
||||
)
|
||||
return parsed.netloc
|
||||
return f"oss-{self.config.region}.aliyuncs.com"
|
||||
return expected_host
|
||||
|
||||
def _public_object_url(self, endpoint_host: str, object_key: str) -> str:
|
||||
encoded_key = quote(object_key, safe="/")
|
||||
return f"https://{self.config.bucket}.{endpoint_host}/{encoded_key}"
|
||||
|
||||
Reference in New Issue
Block a user