"""Flask extension for MinIO storage client initialization""" import logging from flask import Flask from minio import Minio from minio.error import S3Error class StorageExtension: """Flask extension for managing MinIO storage client""" def __init__(self, app: Flask = None): """ Initialize StorageExtension Args: app: Flask application instance (optional) """ self.app = app self.client = None self.logger = logging.getLogger(__name__) if app is not None: self.init_app(app) def init_app(self, app: Flask) -> None: """ Initialize the extension with Flask app Args: app: Flask application instance """ # Store extension on app app.extensions = getattr(app, "extensions", {}) app.extensions["storage"] = self # Store app reference for later use self.app = app # Initialize and validate MinIO client immediately at app startup self._initialize_and_validate(app) def _initialize_and_validate(self, app: Flask) -> None: """ Initialize MinIO client and validate connection Args: app: Flask application instance """ try: # Create MinIO client self.client = Minio( app.config["MINIO_ENDPOINT"], access_key=app.config["MINIO_ACCESS_KEY"], secret_key=app.config["MINIO_SECRET_KEY"], secure=app.config["MINIO_USE_SSL"], ) # Validate connection by listing buckets self.client.list_buckets() app.logger.info("MinIO client initialized and validated successfully") # Ensure all required buckets exist self._ensure_all_buckets_exist(app) except S3Error as e: app.logger.error(f"Failed to initialize MinIO client: {e}") raise RuntimeError( f"Failed to connect to MinIO at {app.config['MINIO_ENDPOINT']}. " "Please check your MINIO_ENDPOINT, MINIO_ACCESS_KEY, " "and MINIO_SECRET_KEY configuration." ) from e except KeyError as e: app.logger.error(f"Missing MinIO configuration: {e}") raise RuntimeError( f"Missing required MinIO configuration: {e}. " "Please ensure MINIO_ENDPOINT, MINIO_ACCESS_KEY, " "MINIO_SECRET_KEY are set." ) from e def _ensure_all_buckets_exist(self, app: Flask) -> None: """ Ensure all required buckets exist Creates buckets if they don't exist Args: app: Flask application instance """ buckets = [ app.config["MINIO_IMAGES_BUCKET"], app.config["MINIO_DOCUMENTS_BUCKET"], app.config["MINIO_THUMBNAILS_BUCKET"], ] for bucket_name in buckets: try: if not self.client.bucket_exists(bucket_name): self.client.make_bucket(bucket_name) app.logger.info(f"Created MinIO bucket: {bucket_name}") else: app.logger.debug(f"MinIO bucket already exists: {bucket_name}") except S3Error as e: app.logger.error(f"Failed to ensure bucket {bucket_name}: {e}") raise RuntimeError( f"Failed to create MinIO bucket '{bucket_name}': {e}" ) from e def get_client(self) -> Minio: """ Get the MinIO client instance Returns: Minio: Initialized MinIO client Raises: RuntimeError: If client has not been initialized """ if self.client is None: raise RuntimeError( "MinIO client has not been initialized. " "Ensure the Flask app context is active " "and before_first_request has run." ) return self.client # Create a singleton instance storage = StorageExtension()