first commit

This commit is contained in:
2026-02-08 14:42:58 +08:00
commit 20e1deae21
8197 changed files with 2264639 additions and 0 deletions

184
backend/app/utils/file.py Normal file
View File

@@ -0,0 +1,184 @@
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_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.")