chore: bootstrap storage migrations and frontend
This commit is contained in:
@@ -1,28 +1,108 @@
|
||||
import os
|
||||
from io import BytesIO
|
||||
|
||||
# 先实现本地文件存储,MinIO 作为选项
|
||||
from minio import Minio
|
||||
from minio.error import S3Error
|
||||
|
||||
|
||||
STORAGE_BASE = os.getenv("LOCAL_STORAGE_PATH", "./data/files")
|
||||
MINIO_ENDPOINT = os.getenv("MINIO_ENDPOINT", "localhost:9000")
|
||||
MINIO_ACCESS_KEY = os.getenv("MINIO_ACCESS_KEY", "minioadmin")
|
||||
MINIO_SECRET_KEY = os.getenv("MINIO_SECRET_KEY", "minioadmin")
|
||||
MINIO_SECURE = os.getenv("MINIO_SECURE", "false").lower() == "true"
|
||||
|
||||
|
||||
def save_file(content: bytes, file_path: str) -> str:
|
||||
"""保存文件到本地存储,返回完整路径"""
|
||||
full_path = os.path.join(STORAGE_BASE, file_path)
|
||||
def _local_path(bucket: str, file_path: str) -> str:
|
||||
return os.path.join(STORAGE_BASE, bucket, file_path)
|
||||
|
||||
|
||||
def _save_local(bucket: str, file_path: str, content: bytes) -> str:
|
||||
full_path = _local_path(bucket, file_path)
|
||||
os.makedirs(os.path.dirname(full_path), exist_ok=True)
|
||||
with open(full_path, "wb") as f:
|
||||
f.write(content)
|
||||
return full_path
|
||||
|
||||
|
||||
def read_file(file_path: str) -> bytes:
|
||||
"""读取文件内容"""
|
||||
full_path = os.path.join(STORAGE_BASE, file_path)
|
||||
with open(full_path, "rb") as f:
|
||||
def _read_local(bucket: str, file_path: str) -> bytes:
|
||||
with open(_local_path(bucket, file_path), "rb") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def get_minio_client() -> Minio:
|
||||
return Minio(
|
||||
MINIO_ENDPOINT,
|
||||
access_key=MINIO_ACCESS_KEY,
|
||||
secret_key=MINIO_SECRET_KEY,
|
||||
secure=MINIO_SECURE,
|
||||
)
|
||||
|
||||
|
||||
def ensure_bucket(bucket_name: str) -> bool:
|
||||
"""确保 bucket 存在;MinIO 不可用时返回 False 表示使用本地降级。"""
|
||||
try:
|
||||
client = get_minio_client()
|
||||
if not client.bucket_exists(bucket_name):
|
||||
client.make_bucket(bucket_name)
|
||||
return True
|
||||
except S3Error:
|
||||
return False
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def upload_file(bucket: str, file_path: str, content: bytes) -> str:
|
||||
"""上传文件到 MinIO;连接失败时降级保存到本地文件系统。"""
|
||||
if ensure_bucket(bucket):
|
||||
try:
|
||||
client = get_minio_client()
|
||||
client.put_object(
|
||||
bucket,
|
||||
file_path,
|
||||
BytesIO(content),
|
||||
length=len(content),
|
||||
content_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
)
|
||||
return f"minio://{bucket}/{file_path}"
|
||||
except S3Error:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return _save_local(bucket, file_path, content)
|
||||
|
||||
|
||||
def download_file(bucket: str, file_path: str) -> bytes:
|
||||
"""从 MinIO 下载文件;读取失败时尝试本地降级路径。"""
|
||||
if ensure_bucket(bucket):
|
||||
try:
|
||||
client = get_minio_client()
|
||||
response = client.get_object(bucket, file_path)
|
||||
try:
|
||||
return response.read()
|
||||
finally:
|
||||
response.close()
|
||||
response.release_conn()
|
||||
except S3Error:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return _read_local(bucket, file_path)
|
||||
|
||||
|
||||
def save_file(content: bytes, file_path: str) -> str:
|
||||
"""兼容旧调用:保存到默认 templates bucket。"""
|
||||
return upload_file("templates", file_path, content)
|
||||
|
||||
|
||||
def read_file(file_path: str) -> bytes:
|
||||
"""兼容旧调用:从默认 templates bucket 读取。"""
|
||||
return download_file("templates", file_path)
|
||||
|
||||
|
||||
def delete_file(file_path: str):
|
||||
"""删除文件"""
|
||||
full_path = os.path.join(STORAGE_BASE, file_path)
|
||||
"""删除本地降级文件。MinIO 对象删除后续按接口需要再补充。"""
|
||||
full_path = _local_path("templates", file_path)
|
||||
if os.path.exists(full_path):
|
||||
os.remove(full_path)
|
||||
|
||||
Reference in New Issue
Block a user