import io import logging from minio import Minio from minio.error import S3Error from app.config import settings logger = logging.getLogger("app.services.storage") _client: Minio | None = None def get_minio_client() -> Minio: global _client if _client is None: logger.info("Initializing MinIO client: endpoint=%s, secure=%s", settings.MINIO_ENDPOINT, settings.MINIO_SECURE) _client = Minio( endpoint=settings.MINIO_ENDPOINT, access_key=settings.MINIO_ACCESS_KEY, secret_key=settings.MINIO_SECRET_KEY, secure=settings.MINIO_SECURE, ) logger.info("MinIO client created, checking bucket '%s'...", settings.MINIO_BUCKET) if not _client.bucket_exists(settings.MINIO_BUCKET): _client.make_bucket(settings.MINIO_BUCKET) logger.info("Created MinIO bucket: %s", settings.MINIO_BUCKET) else: logger.info("MinIO bucket '%s' already exists", settings.MINIO_BUCKET) return _client def upload_file(object_name: str, data: bytes, content_type: str = "application/octet-stream") -> str: """Upload file to MinIO. Returns the object name (key).""" logger.info("Uploading to MinIO: object=%s, size=%d bytes, content_type=%s", object_name, len(data), content_type) client = get_minio_client() client.put_object( bucket_name=settings.MINIO_BUCKET, object_name=object_name, data=io.BytesIO(data), length=len(data), content_type=content_type, ) logger.info("Upload complete: %s/%s", settings.MINIO_BUCKET, object_name) return object_name def download_file(object_name: str) -> bytes: """Download file from MinIO.""" logger.info("Downloading from MinIO: %s/%s", settings.MINIO_BUCKET, object_name) client = get_minio_client() response = client.get_object(settings.MINIO_BUCKET, object_name) try: data = response.read() logger.info("Download complete: %s, size=%d bytes", object_name, len(data)) return data finally: response.close() response.release_conn() def delete_file(object_name: str) -> None: """Delete file from MinIO.""" logger.info("Deleting from MinIO: %s/%s", settings.MINIO_BUCKET, object_name) client = get_minio_client() client.remove_object(settings.MINIO_BUCKET, object_name) logger.info("Deleted: %s", object_name)