Files
mokeeText/backend/file_service.py
2026-07-15 16:08:17 +08:00

131 lines
3.8 KiB
Python
Raw Permalink 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.
"""文件对象存储服务客户端 — https://file.wg.zgitm.com
认证方式:一次性 Token每次操作前获取
系统编码mokeetext-edit
"""
import requests
BASE_URL = "https://file.wg.zgitm.com"
SYSTEM_CODE = "mokeetext-edit"
FOLDER_PATH = "/mokeetext-images/" # 图片统一存放目录
def get_token(system_code: str = SYSTEM_CODE) -> str:
"""获取一次性 Token"""
resp = requests.post(
f"{BASE_URL}/api/token",
json={"systemCode": system_code},
timeout=15,
)
data = resp.json()
if data.get("code") != 200:
raise RuntimeError(f"获取文件服务 Token 失败: {data.get('message')}")
return data["data"]["token"]
def upload_file(
file_data: bytes,
filename: str,
content_type: str,
upload_user: str = "",
) -> dict:
"""
上传文件到文件服务
返回: {"fileId": "...", "fileName": "...", "fileSize": 123}
"""
token = get_token()
resp = requests.post(
f"{BASE_URL}/api/upload",
headers={"Authorization": f"Bearer {token}"},
files={"file": (filename, file_data, content_type)},
data={
"folderPath": FOLDER_PATH,
"uploadUser": upload_user,
},
timeout=60,
)
data = resp.json()
if data.get("code") != 200:
raise RuntimeError(f"上传文件失败: {data.get('message')}")
return data["data"]
def download_file(file_id: str) -> tuple[bytes, str, str]:
"""
从文件服务下载文件
返回: (binary_data, content_type, filename)
"""
token = get_token()
resp = requests.get(
f"{BASE_URL}/api/download/{file_id}",
headers={"Authorization": f"Bearer {token}"},
timeout=30,
)
if resp.status_code == 404:
raise FileNotFoundError(f"文件不存在: {file_id}")
if resp.status_code != 200:
try:
err = resp.json()
raise RuntimeError(f"下载文件失败: {err.get('message', resp.text)}")
except ValueError:
raise RuntimeError(f"下载文件失败: HTTP {resp.status_code}")
content_type = resp.headers.get("Content-Type", "application/octet-stream")
# 从 Content-Disposition 提取文件名
filename = file_id
disposition = resp.headers.get("Content-Disposition", "")
if "filename*=" in disposition:
# filename*=UTF-8''原始文件名
parts = disposition.split("filename*=")
if len(parts) > 1:
fname = parts[1].strip()
if "''" in fname:
filename = fname.split("''", 1)[1]
elif 'filename="' in disposition:
filename = disposition.split('filename="')[1].rstrip('"')
return resp.content, content_type, filename
def delete_file(file_id: str) -> bool:
"""删除文件服务中的文件"""
token = get_token()
resp = requests.get(
f"{BASE_URL}/api/delete/{file_id}",
headers={"Authorization": f"Bearer {token}"},
timeout=15,
)
data = resp.json()
if data.get("code") == 404:
return False # 文件已不存在,也算删除成功
if data.get("code") != 200:
raise RuntimeError(f"删除文件失败: {data.get('message')}")
return True
def ensure_folder() -> bool:
"""确保图片存放目录存在"""
token = get_token()
resp = requests.post(
f"{BASE_URL}/api/folder/create",
headers={"Authorization": f"Bearer {token}"},
json={
"folderPath": FOLDER_PATH,
"createdBy": SYSTEM_CODE,
},
timeout=15,
)
data = resp.json()
if data.get("code") == 400 and "已存在" in data.get("message", ""):
return True # 文件夹已存在,没问题
if data.get("code") != 200:
raise RuntimeError(f"创建文件夹失败: {data.get('message')}")
return True