feature/implementacion de gestor de informacion y archivos minIO
This commit is contained in:
143
api/utils/minio_client.py
Normal file
143
api/utils/minio_client.py
Normal file
@@ -0,0 +1,143 @@
|
||||
# backend/utils/minio_client.py
|
||||
from datetime import timedelta
|
||||
import os
|
||||
from minio import Minio
|
||||
from minio.error import S3Error
|
||||
from django.conf import settings
|
||||
from typing import Optional, BinaryIO
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MinIOClient:
|
||||
"""Cliente singleton para MinIO con operaciones avanzadas"""
|
||||
|
||||
_instance = None
|
||||
_client = None
|
||||
_bucket_name = None
|
||||
|
||||
def __new__(cls):
|
||||
if cls._instance is None:
|
||||
cls._instance = super().__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def __init__(self):
|
||||
if self._client is None and settings.STORAGE_BACKEND == 'minio':
|
||||
self._initialize_client()
|
||||
|
||||
def _initialize_client(self):
|
||||
"""Inicializa el cliente de MinIO"""
|
||||
try:
|
||||
endpoint = os.getenv('MINIO_ENDPOINT', 'minio:9000')
|
||||
access_key = os.getenv('MINIO_ACCESS_KEY')
|
||||
secret_key = os.getenv('MINIO_SECRET_KEY')
|
||||
secure = os.getenv('MINIO_SECURE', 'false').lower() == 'true'
|
||||
|
||||
self._client = Minio(
|
||||
endpoint=endpoint,
|
||||
access_key=access_key,
|
||||
secret_key=secret_key,
|
||||
secure=secure
|
||||
)
|
||||
|
||||
self._bucket_name = os.environ.get('MINIO_BUCKET_NAME', 'efc-backend-dev')
|
||||
|
||||
# Asegurar que el bucket existe
|
||||
if not self._client.bucket_exists(self._bucket_name):
|
||||
self._client.make_bucket(self._bucket_name)
|
||||
|
||||
except Exception as e:
|
||||
raise
|
||||
|
||||
def upload_file(
|
||||
self,
|
||||
object_name: str,
|
||||
file_path: str = None,
|
||||
file_data: BinaryIO = None,
|
||||
content_type: str = None,
|
||||
metadata: dict = None
|
||||
) -> bool:
|
||||
"""
|
||||
Sube un archivo a MinIO
|
||||
|
||||
Args:
|
||||
object_name: Ruta del objeto en el bucket (ej: 'documents/archivo.xml')
|
||||
file_path: Ruta local del archivo (opcional)
|
||||
file_data: Datos del archivo en memoria (opcional)
|
||||
content_type: MIME type del archivo
|
||||
metadata: Metadatos adicionales
|
||||
|
||||
Returns:
|
||||
bool: True si se subió correctamente
|
||||
"""
|
||||
try:
|
||||
if file_path:
|
||||
self._client.fput_object(
|
||||
bucket_name=self._bucket_name,
|
||||
object_name=object_name,
|
||||
file_path=file_path,
|
||||
content_type=content_type,
|
||||
metadata=metadata
|
||||
)
|
||||
elif file_data:
|
||||
self._client.put_object(
|
||||
bucket_name=self._bucket_name,
|
||||
object_name=object_name,
|
||||
data=file_data,
|
||||
length=-1,
|
||||
part_size=10*1024*1024, # 10MB
|
||||
content_type=content_type,
|
||||
metadata=metadata
|
||||
)
|
||||
else:
|
||||
raise ValueError("You must provide file_path or file_data")
|
||||
|
||||
return True
|
||||
|
||||
except S3Error as e:
|
||||
return False
|
||||
|
||||
def get_file_url(self, object_name: str, expires: int = 3600) -> Optional[str]:
|
||||
"""Genera una URL firmada para acceder al archivo"""
|
||||
try:
|
||||
url = self._client.presigned_get_object(
|
||||
bucket_name=self._bucket_name,
|
||||
object_name=object_name,
|
||||
expires=timedelta(seconds=expires)
|
||||
)
|
||||
|
||||
# Reemplazar endpoint interno por público si está configurado
|
||||
public_endpoint = os.getenv('MINIO_PUBLIC_ENDPOINT')
|
||||
if public_endpoint and url:
|
||||
internal_endpoint = os.getenv('MINIO_ENDPOINT', 'minio:9000')
|
||||
url = url.replace(internal_endpoint, public_endpoint)
|
||||
|
||||
return url
|
||||
except S3Error as e:
|
||||
return None
|
||||
|
||||
def delete_file(self, object_name: str) -> bool:
|
||||
"""Elimina un archivo del bucket"""
|
||||
try:
|
||||
self._client.remove_object(
|
||||
bucket_name=self._bucket_name,
|
||||
object_name=object_name
|
||||
)
|
||||
return True
|
||||
except S3Error as e:
|
||||
return False
|
||||
|
||||
def file_exists(self, object_name: str) -> bool:
|
||||
"""Verifica si un archivo existe en el bucket"""
|
||||
try:
|
||||
self._client.stat_object(
|
||||
bucket_name=self._bucket_name,
|
||||
object_name=object_name
|
||||
)
|
||||
return True
|
||||
except S3Error:
|
||||
return False
|
||||
|
||||
# Singleton para uso global
|
||||
minio_client = MinIOClient()
|
||||
Reference in New Issue
Block a user