Files
zhuangxiu/services/api/app/integrations/storage.py
T

66 lines
2.0 KiB
Python

from dataclasses import dataclass
import boto3
from botocore.client import Config
from app.config import Settings
@dataclass(frozen=True)
class PresignedUpload:
method: str
url: str
object_key: str
expires_in: int
class S3Storage:
def __init__(self, settings: Settings) -> None:
self.settings = settings
@property
def configured(self) -> bool:
values = (
self.settings.s3_endpoint,
self.settings.s3_access_key_id,
self.settings.s3_secret_access_key,
)
return all(values) and not any(value.startswith("replace_with_") for value in values)
def _client(self, public: bool = False):
endpoint = (
self.settings.s3_public_endpoint
if public and self.settings.s3_public_endpoint
else self.settings.s3_endpoint
)
return boto3.client(
"s3",
endpoint_url=endpoint,
aws_access_key_id=self.settings.s3_access_key_id,
aws_secret_access_key=self.settings.s3_secret_access_key,
region_name=self.settings.s3_region,
config=Config(
signature_version="s3v4",
s3={"addressing_style": "path" if self.settings.s3_force_path_style else "auto"},
),
)
def presign_input_upload(self, object_key: str, content_type: str) -> PresignedUpload:
if not self.configured:
raise RuntimeError("MinIO/S3 is not configured.")
url = self._client(public=True).generate_presigned_url(
"put_object",
Params={
"Bucket": self.settings.s3_bucket_inputs,
"Key": object_key,
"ContentType": content_type,
},
ExpiresIn=self.settings.s3_presigned_url_ttl_seconds,
)
return PresignedUpload(
method="PUT",
url=url,
object_key=object_key,
expires_in=self.settings.s3_presigned_url_ttl_seconds,
)