Files
algorithm/backend/app/utils/file.py
2026-02-18 09:36:18 +08:00

206 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from minio import Minio
from minio.error import S3Error
from typing import Optional, Tuple
import io
import os
import logging
from app.config.settings import settings
class MinioClient:
"""MinIO客户端类"""
def __init__(self):
"""初始化MinIO客户端"""
try:
self.client = Minio(
settings.MINIO_ENDPOINT,
access_key=settings.MINIO_ACCESS_KEY,
secret_key=settings.MINIO_SECRET_KEY,
secure=settings.MINIO_SECURE
)
self.bucket_name = settings.MINIO_BUCKET_NAME
self.is_connected = True # 先设置为True这样在调用其他方法时不会报错
# 确保存储桶存在
self._ensure_bucket_exists()
except Exception as e:
logging.warning(f"Failed to connect to MinIO: {e}. Running in offline mode.")
self.client = None
self.bucket_name = settings.MINIO_BUCKET_NAME
self.is_connected = False
def _ensure_bucket_exists(self):
"""确保存储桶存在"""
if not self.is_connected:
return
try:
if not self.client.bucket_exists(self.bucket_name):
self.client.make_bucket(self.bucket_name)
except S3Error as e:
logging.warning(f"MinIO bucket error: {e}")
def upload_file(self, file_path: str, object_name: str) -> bool:
"""上传文件"""
if not self.is_connected:
logging.warning("MinIO is not connected. Upload skipped.")
return False
try:
self.client.fput_object(
self.bucket_name,
object_name,
file_path
)
return True
except S3Error as e:
logging.warning(f"MinIO upload error: {e}")
return False
def upload_from_bytes(self, data: bytes, object_name: str) -> bool:
"""从字节数据上传文件"""
if not self.is_connected:
logging.warning("MinIO is not connected. Upload skipped.")
return False
try:
import io
file_obj = io.BytesIO(data)
self.client.put_object(
self.bucket_name,
object_name,
file_obj,
length=len(data),
part_size=10*1024*1024
)
return True
except S3Error as e:
logging.warning(f"MinIO upload error: {e}")
return False
def upload_fileobj(self, file_obj: io.BytesIO, object_name: str, content_type: str = "application/octet-stream") -> bool:
"""上传文件对象"""
if not self.is_connected:
logging.warning("MinIO is not connected. Upload skipped.")
return False
try:
self.client.put_object(
self.bucket_name,
object_name,
file_obj,
length=-1,
part_size=10*1024*1024,
content_type=content_type
)
return True
except S3Error as e:
logging.warning(f"MinIO upload error: {e}")
return False
def download_file(self, object_name: str, file_path: str) -> bool:
"""下载文件"""
if not self.is_connected:
logging.warning("MinIO is not connected. Download skipped.")
return False
try:
self.client.fget_object(
self.bucket_name,
object_name,
file_path
)
return True
except S3Error as e:
logging.warning(f"MinIO download error: {e}")
return False
def get_object(self, object_name: str) -> Optional[bytes]:
"""获取对象内容"""
if not self.is_connected:
logging.warning("MinIO is not connected. Get object skipped.")
return None
try:
response = self.client.get_object(
self.bucket_name,
object_name
)
data = response.read()
response.close()
response.release_conn()
return data
except S3Error as e:
logging.warning(f"MinIO get object error: {e}")
return None
def delete_object(self, object_name: str) -> bool:
"""删除对象"""
if not self.is_connected:
logging.warning("MinIO is not connected. Delete object skipped.")
return False
try:
self.client.remove_object(
self.bucket_name,
object_name
)
return True
except S3Error as e:
logging.warning(f"MinIO delete error: {e}")
return False
def list_objects(self, prefix: str = "") -> list:
"""列出对象"""
if not self.is_connected:
logging.warning("MinIO is not connected. List objects skipped.")
return []
try:
objects = []
for obj in self.client.list_objects(
self.bucket_name,
prefix=prefix,
recursive=True
):
objects.append(obj.object_name)
return objects
except S3Error as e:
logging.warning(f"MinIO list objects error: {e}")
return []
def get_presigned_url(self, object_name: str, expires: int = 604800) -> Optional[str]:
"""获取预签名URL"""
if not self.is_connected:
logging.warning("MinIO is not connected. Get presigned URL skipped.")
return None
try:
url = self.client.presigned_get_object(
self.bucket_name,
object_name,
expires=expires
)
return url
except S3Error as e:
logging.warning(f"MinIO presigned url error: {e}")
return None
# 创建全局文件存储实例
try:
file_storage = MinioClient()
except Exception as e:
# 如果初始化失败,创建一个模拟实例
class MockFileStorage:
def __getattr__(self, name):
def mock_method(*args, **kwargs):
logging.warning(f"MinIO is not available. Method '{name}' will not execute.")
return None if name.startswith('get_') or name == 'list_objects' else False
return mock_method
file_storage = MockFileStorage()
logging.warning(f"Failed to initialize MinIO client: {e}. Using mock instance.")