from contextlib import asynccontextmanager import aiobotocore.session from app.config import get_settings from app.storage.backend import StorageBackend class S3StorageBackend(StorageBackend): def __init__(self) -> None: self._settings = get_settings() self._session = aiobotocore.session.get_session() @asynccontextmanager async def _client(self): s = self._settings async with self._session.create_client( "s3", region_name=s.s3_region, endpoint_url=s.s3_endpoint_url or None, aws_access_key_id=s.s3_access_key_id, aws_secret_access_key=s.s3_secret_access_key, ) as client: yield client async def put(self, key: str, data: bytes, content_type: str) -> None: async with self._client() as client: await client.put_object( Bucket=self._settings.s3_bucket_name, Key=key, Body=data, ContentType=content_type, ) async def get_presigned_url(self, key: str, expires_in_seconds: int = 3600) -> str: async with self._client() as client: url = await client.generate_presigned_url( "get_object", Params={"Bucket": self._settings.s3_bucket_name, "Key": key}, ExpiresIn=expires_in_seconds, ) return url async def delete(self, key: str) -> None: async with self._client() as client: await client.delete_object(Bucket=self._settings.s3_bucket_name, Key=key)