Files
webref/backend/app/core/storage.py

120 lines
3.3 KiB
Python

"""MinIO storage client utilities."""
import logging
from io import BytesIO
from typing import BinaryIO
import boto3
from botocore.client import Config
from botocore.exceptions import ClientError
from app.core.config import settings
logger = logging.getLogger(__name__)
class StorageClient:
"""MinIO storage client wrapper."""
def __init__(self):
"""Initialize MinIO client."""
self.client = boto3.client(
"s3",
endpoint_url=f"{'https' if settings.MINIO_SECURE else 'http'}://{settings.MINIO_ENDPOINT}",
aws_access_key_id=settings.MINIO_ACCESS_KEY,
aws_secret_access_key=settings.MINIO_SECRET_KEY,
config=Config(signature_version="s3v4"),
)
self.bucket = settings.MINIO_BUCKET
self._ensure_bucket_exists()
def _ensure_bucket_exists(self) -> None:
"""Create bucket if it doesn't exist."""
try:
self.client.head_bucket(Bucket=self.bucket)
except ClientError:
logger.info(f"Creating bucket: {self.bucket}")
self.client.create_bucket(Bucket=self.bucket)
def upload_file(self, file_data: BinaryIO, object_name: str, content_type: str) -> str:
"""Upload file to MinIO.
Args:
file_data: File data to upload
object_name: S3 object name (path)
content_type: MIME type of the file
Returns:
str: Object URL
Raises:
Exception: If upload fails
"""
try:
self.client.upload_fileobj(
file_data,
self.bucket,
object_name,
ExtraArgs={"ContentType": content_type},
)
return f"{settings.MINIO_ENDPOINT}/{self.bucket}/{object_name}"
except ClientError as e:
logger.error(f"Failed to upload file {object_name}: {e}")
raise
def download_file(self, object_name: str) -> BytesIO:
"""Download file from MinIO.
Args:
object_name: S3 object name (path)
Returns:
BytesIO: File data
Raises:
Exception: If download fails
"""
try:
file_data = BytesIO()
self.client.download_fileobj(self.bucket, object_name, file_data)
file_data.seek(0)
return file_data
except ClientError as e:
logger.error(f"Failed to download file {object_name}: {e}")
raise
def delete_file(self, object_name: str) -> None:
"""Delete file from MinIO.
Args:
object_name: S3 object name (path)
Raises:
Exception: If deletion fails
"""
try:
self.client.delete_object(Bucket=self.bucket, Key=object_name)
except ClientError as e:
logger.error(f"Failed to delete file {object_name}: {e}")
raise
def file_exists(self, object_name: str) -> bool:
"""Check if file exists in MinIO.
Args:
object_name: S3 object name (path)
Returns:
bool: True if file exists, False otherwise
"""
try:
self.client.head_object(Bucket=self.bucket, Key=object_name)
return True
except ClientError:
return False
# Global storage client instance
storage_client = StorageClient()