x
This commit is contained in:
+91
-87
@@ -107,102 +107,106 @@ async def get_status(task_id: str, db_session: AsyncSession = Depends(get_db_ses
|
|||||||
如果内存中不存在,则从 PostgreSQL + RustFS 组装一个持久化的任务视图,
|
如果内存中不存在,则从 PostgreSQL + RustFS 组装一个持久化的任务视图,
|
||||||
结构与内存任务保持尽量一致,便于前端集中展示总结性信息。
|
结构与内存任务保持尽量一致,便于前端集中展示总结性信息。
|
||||||
"""
|
"""
|
||||||
# 1. 内存任务(进行中的任务)
|
try:
|
||||||
if task_id in tasks:
|
# 1. 内存任务(进行中的任务)
|
||||||
task = tasks[task_id]
|
if task_id in tasks:
|
||||||
logger.info(f"返回内存任务状态:{task_id} - {task['status']}")
|
task = tasks[task_id]
|
||||||
logger.info(f"内存任务 analysis_result: {task.get('analysis_result', 'None')}")
|
logger.info(f"返回内存任务状态:{task_id} - {task['status']}")
|
||||||
logger.info(f"内存任务 html_file: {task.get('html_file', 'None')}")
|
logger.info(f"内存任务 analysis_result: {task.get('analysis_result', 'None')}")
|
||||||
return task
|
logger.info(f"内存任务 html_file: {task.get('html_file', 'None')}")
|
||||||
|
return task
|
||||||
|
|
||||||
# 2. 持久化任务(已完成/失败,或服务重启后的任务)
|
# 2. 持久化任务(已完成/失败,或服务重启后的任务)
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from models.database import ProcessingTask, STPFile, GeometryData, MeshData, MoldCavityData
|
from models.database import ProcessingTask, STPFile, GeometryData, MeshData, MoldCavityData
|
||||||
storage_service = StorageIntegrationService()
|
storage_service = StorageIntegrationService()
|
||||||
|
|
||||||
# 查询任务和文件元数据
|
# 查询任务和文件元数据
|
||||||
result = await db_session.execute(
|
result = await db_session.execute(
|
||||||
select(ProcessingTask, STPFile)
|
select(ProcessingTask, STPFile)
|
||||||
.join(STPFile, ProcessingTask.stp_file_id == STPFile.id)
|
.join(STPFile, ProcessingTask.stp_file_id == STPFile.id)
|
||||||
.where(ProcessingTask.task_id == task_id)
|
.where(ProcessingTask.task_id == task_id)
|
||||||
)
|
)
|
||||||
row = result.first()
|
row = result.first()
|
||||||
if not row:
|
if not row:
|
||||||
raise HTTPException(404, "任务不存在")
|
raise HTTPException(404, "任务不存在")
|
||||||
|
|
||||||
processing_task, stp_file = row
|
processing_task, stp_file = row
|
||||||
|
|
||||||
# 从 RustFS 取几何 / 型腔 / 网格详细 JSON(小量数据,便于前端展示汇总)
|
# 从 RustFS 取几何 / 型腔 / 网格详细 JSON(小量数据,便于前端展示汇总)
|
||||||
file_with_data = await storage_service.get_stp_file_with_data(
|
try:
|
||||||
db_session, stp_file_id=stp_file.id
|
file_with_data = await storage_service.get_stp_file_with_data(
|
||||||
)
|
db_session, stp_file_id=stp_file.id
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取文件数据失败: {e}")
|
||||||
|
file_with_data = {}
|
||||||
|
|
||||||
geometry_json: Optional[Dict[str, Any]] = None
|
geometry_json: Optional[Dict[str, Any]] = None
|
||||||
if file_with_data.get("geometry_data"):
|
if file_with_data.get("geometry_data"):
|
||||||
# save_geometry_data 保存时可能有两种格式:
|
geo_raw = file_with_data["geometry_data"]
|
||||||
# 1. 直接保存 geometry_data 字典
|
if isinstance(geo_raw, dict):
|
||||||
# 2. 保存 {"geometry_data": {...}} 格式
|
if "geometry_data" in geo_raw:
|
||||||
# get_stp_file_with_data 返回的是从RustFS下载的原始JSON
|
geometry_json = geo_raw["geometry_data"]
|
||||||
geo_raw = file_with_data["geometry_data"]
|
else:
|
||||||
if isinstance(geo_raw, dict):
|
geometry_json = geo_raw
|
||||||
# 如果是包装格式,提取内部数据
|
|
||||||
if "geometry_data" in geo_raw:
|
|
||||||
geometry_json = geo_raw["geometry_data"]
|
|
||||||
else:
|
|
||||||
# 直接就是几何数据字典
|
|
||||||
geometry_json = geo_raw
|
|
||||||
|
|
||||||
cavity_json: Optional[Dict[str, Any]] = file_with_data.get("mold_cavity_data")
|
cavity_json: Optional[Dict[str, Any]] = file_with_data.get("mold_cavity_data")
|
||||||
features_json: List[Dict[str, Any]] = file_with_data.get("features", [])
|
features_json: List[Dict[str, Any]] = file_with_data.get("features", [])
|
||||||
recommendations_json: List[Dict[str, Any]] = file_with_data.get("recommendations", [])
|
recommendations_json: List[Dict[str, Any]] = file_with_data.get("recommendations", [])
|
||||||
|
|
||||||
# 组装网格摘要:从 MeshData 表中读出摘要字段,避免把完整网格 JSON 丢给前端
|
# 组装网格摘要
|
||||||
mesh_summary = None
|
mesh_summary = None
|
||||||
mesh_record = await db_session.execute(
|
mesh_record = await db_session.execute(
|
||||||
select(MeshData).where(MeshData.stp_file_id == stp_file.id)
|
select(MeshData).where(MeshData.stp_file_id == stp_file.id)
|
||||||
)
|
)
|
||||||
mesh_record = mesh_record.scalar_one_or_none()
|
mesh_record = mesh_record.scalar_one_or_none()
|
||||||
if mesh_record:
|
if mesh_record:
|
||||||
mesh_summary = {
|
mesh_summary = {
|
||||||
"vertex_count": mesh_record.vertex_count,
|
"vertex_count": mesh_record.vertex_count,
|
||||||
"face_count": mesh_record.face_count,
|
"face_count": mesh_record.face_count,
|
||||||
"point_count": mesh_record.point_count,
|
"point_count": mesh_record.point_count,
|
||||||
"quality": mesh_record.quality,
|
"quality": mesh_record.quality,
|
||||||
|
}
|
||||||
|
|
||||||
|
# 构造与内存任务兼容的任务视图
|
||||||
|
task_view = {
|
||||||
|
"task_id": processing_task.task_id,
|
||||||
|
"status": processing_task.status,
|
||||||
|
"filename": stp_file.original_filename if stp_file else "",
|
||||||
|
"file_path": stp_file.file_path or "",
|
||||||
|
"file_size": stp_file.file_size if stp_file else 0,
|
||||||
|
"upload_time": processing_task.created_time.isoformat()
|
||||||
|
if processing_task.created_time
|
||||||
|
else "",
|
||||||
|
"completed_at": processing_task.completed_time.isoformat()
|
||||||
|
if processing_task.completed_time
|
||||||
|
else "",
|
||||||
|
"geometry_data": geometry_json,
|
||||||
|
"key_info": cavity_json,
|
||||||
|
"cavity_data": cavity_json,
|
||||||
|
"mesh_summary": mesh_summary,
|
||||||
|
"analysis_result": {
|
||||||
|
"geometry_data": geometry_json,
|
||||||
|
"detected_features": features_json,
|
||||||
|
"design_recommendations": recommendations_json,
|
||||||
|
"quality_metrics": {
|
||||||
|
"volume_utilization": file_with_data.get("analysis_metrics", {}).get("volume_utilization", 0),
|
||||||
|
"topology_complexity": file_with_data.get("analysis_metrics", {}).get("topology_complexity", 0),
|
||||||
|
"wall_uniformity": file_with_data.get("analysis_metrics", {}).get("wall_uniformity", 0)
|
||||||
|
},
|
||||||
|
"analysis_summary": file_with_data.get("analysis_metrics", {}).get("analysis_summary", "分析完成")
|
||||||
|
} if geometry_json or features_json or recommendations_json else None,
|
||||||
|
"error": processing_task.error_message or stp_file.error_message or None,
|
||||||
}
|
}
|
||||||
|
|
||||||
# 构造与内存任务兼容的任务视图
|
logger.info(f"返回持久化任务状态: {task_id} - {processing_task.status}")
|
||||||
task_view = {
|
return task_view
|
||||||
"task_id": processing_task.task_id,
|
except HTTPException:
|
||||||
"status": processing_task.status,
|
raise
|
||||||
"filename": stp_file.original_filename if stp_file else "",
|
except Exception as e:
|
||||||
"file_path": stp_file.file_path or "",
|
logger.error(f"获取任务状态失败: {e}")
|
||||||
"file_size": stp_file.file_size if stp_file else 0,
|
raise HTTPException(500, f"获取任务状态失败: {str(e)}")
|
||||||
"upload_time": processing_task.created_time.isoformat()
|
|
||||||
if processing_task.created_time
|
|
||||||
else "",
|
|
||||||
"completed_at": processing_task.completed_time.isoformat()
|
|
||||||
if processing_task.completed_time
|
|
||||||
else "",
|
|
||||||
"geometry_data": geometry_json,
|
|
||||||
"key_info": cavity_json,
|
|
||||||
"cavity_data": cavity_json,
|
|
||||||
"mesh_summary": mesh_summary,
|
|
||||||
"analysis_result": {
|
|
||||||
"geometry_data": geometry_json,
|
|
||||||
"detected_features": features_json,
|
|
||||||
"design_recommendations": recommendations_json,
|
|
||||||
"quality_metrics": {
|
|
||||||
"volume_utilization": file_with_data.get("analysis_metrics", {}).get("volume_utilization", 0),
|
|
||||||
"topology_complexity": file_with_data.get("analysis_metrics", {}).get("topology_complexity", 0),
|
|
||||||
"wall_uniformity": file_with_data.get("analysis_metrics", {}).get("wall_uniformity", 0)
|
|
||||||
},
|
|
||||||
"analysis_summary": file_with_data.get("analysis_metrics", {}).get("analysis_summary", "分析完成")
|
|
||||||
} if geometry_json or features_json or recommendations_json else None,
|
|
||||||
"error": processing_task.error_message or stp_file.error_message or None,
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info(f"返回持久化任务状态: {task_id} - {processing_task.status}")
|
|
||||||
return task_view
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/debug/tasks")
|
@router.get("/debug/tasks")
|
||||||
|
|||||||
@@ -425,11 +425,25 @@ class StorageIntegrationService:
|
|||||||
async def get_stp_file_with_data(self, session: AsyncSession,
|
async def get_stp_file_with_data(self, session: AsyncSession,
|
||||||
stp_file_id: int) -> Dict[str, Any]:
|
stp_file_id: int) -> Dict[str, Any]:
|
||||||
"""获取STP文件及其所有关联数据"""
|
"""获取STP文件及其所有关联数据"""
|
||||||
|
from sqlalchemy.orm import joinedload
|
||||||
# 1. 获取STP文件记录
|
|
||||||
stp_file = await session.get(STPFile, stp_file_id)
|
try:
|
||||||
if not stp_file:
|
# 1. 获取STP文件记录(使用 joinedload 预加载关联数据)
|
||||||
raise ValueError(f"STP文件不存在: {stp_file_id}")
|
result = await session.execute(
|
||||||
|
select(STPFile).options(
|
||||||
|
joinedload(STPFile.geometry_data),
|
||||||
|
joinedload(STPFile.mesh_data),
|
||||||
|
joinedload(STPFile.mold_cavity_data),
|
||||||
|
joinedload(STPFile.html_file),
|
||||||
|
joinedload(STPFile.analysis_metrics)
|
||||||
|
).where(STPFile.id == stp_file_id)
|
||||||
|
)
|
||||||
|
stp_file = result.scalar_one_or_none()
|
||||||
|
if not stp_file:
|
||||||
|
raise ValueError(f"STP文件不存在: {stp_file_id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"获取STP文件记录失败: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
'metadata': {
|
'metadata': {
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ class RustFSManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 测试连接
|
# 测试连接
|
||||||
self.client.list_buckets()
|
import asyncio
|
||||||
|
await asyncio.to_thread(self.client.list_buckets)
|
||||||
|
|
||||||
self.is_connected = True
|
self.is_connected = True
|
||||||
logger.info(f"RustFS 连接成功: {endpoint}")
|
logger.info(f"RustFS 连接成功: {endpoint}")
|
||||||
@@ -77,9 +78,17 @@ class RustFSManager:
|
|||||||
|
|
||||||
async def _ensure_buckets(self):
|
async def _ensure_buckets(self):
|
||||||
"""确保项目存储桶存在"""
|
"""确保项目存储桶存在"""
|
||||||
try:
|
import asyncio
|
||||||
|
|
||||||
|
def _check_and_create():
|
||||||
if not self.client.bucket_exists(self.bucket_name):
|
if not self.client.bucket_exists(self.bucket_name):
|
||||||
self.client.make_bucket(self.bucket_name)
|
self.client.make_bucket(self.bucket_name)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
created = await asyncio.to_thread(_check_and_create)
|
||||||
|
if created:
|
||||||
logger.info(f"创建项目存储桶: {self.bucket_name}")
|
logger.info(f"创建项目存储桶: {self.bucket_name}")
|
||||||
else:
|
else:
|
||||||
logger.debug(f"项目存储桶已存在: {self.bucket_name}")
|
logger.debug(f"项目存储桶已存在: {self.bucket_name}")
|
||||||
@@ -111,6 +120,8 @@ class RustFSManager:
|
|||||||
original_filename: str,
|
original_filename: str,
|
||||||
metadata: Optional[Dict] = None) -> Dict[str, Any]:
|
metadata: Optional[Dict] = None) -> Dict[str, Any]:
|
||||||
"""上传文件到 RustFS"""
|
"""上传文件到 RustFS"""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise RuntimeError("RustFS 未连接")
|
raise RuntimeError("RustFS 未连接")
|
||||||
|
|
||||||
@@ -124,8 +135,8 @@ class RustFSManager:
|
|||||||
object_key = self._generate_object_key(original_filename, file_type)
|
object_key = self._generate_object_key(original_filename, file_type)
|
||||||
|
|
||||||
# 上传文件
|
# 上传文件
|
||||||
try:
|
def _upload():
|
||||||
result = self.client.fput_object(
|
return self.client.fput_object(
|
||||||
self.bucket_name,
|
self.bucket_name,
|
||||||
object_key,
|
object_key,
|
||||||
str(file_path),
|
str(file_path),
|
||||||
@@ -133,6 +144,9 @@ class RustFSManager:
|
|||||||
metadata=metadata or {}
|
metadata=metadata or {}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = await asyncio.to_thread(_upload)
|
||||||
|
|
||||||
logger.info(f"文件上传成功 RustFS: {self.bucket_name}/{object_key}")
|
logger.info(f"文件上传成功 RustFS: {self.bucket_name}/{object_key}")
|
||||||
|
|
||||||
# 获取文件大小
|
# 获取文件大小
|
||||||
@@ -154,6 +168,8 @@ class RustFSManager:
|
|||||||
json_data: Dict[str, Any],
|
json_data: Dict[str, Any],
|
||||||
file_hash: str) -> Dict[str, Any]:
|
file_hash: str) -> Dict[str, Any]:
|
||||||
"""上传JSON数据到 RustFS"""
|
"""上传JSON数据到 RustFS"""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise RuntimeError("RustFS 未连接")
|
raise RuntimeError("RustFS 未连接")
|
||||||
|
|
||||||
@@ -168,8 +184,8 @@ class RustFSManager:
|
|||||||
import json
|
import json
|
||||||
json_bytes = json.dumps(json_data, ensure_ascii=False).encode('utf-8')
|
json_bytes = json.dumps(json_data, ensure_ascii=False).encode('utf-8')
|
||||||
|
|
||||||
try:
|
def _upload():
|
||||||
result = self.client.put_object(
|
return self.client.put_object(
|
||||||
self.bucket_name,
|
self.bucket_name,
|
||||||
object_key,
|
object_key,
|
||||||
BytesIO(json_bytes),
|
BytesIO(json_bytes),
|
||||||
@@ -177,6 +193,9 @@ class RustFSManager:
|
|||||||
content_type='application/json'
|
content_type='application/json'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = await asyncio.to_thread(_upload)
|
||||||
|
|
||||||
logger.info(f"JSON数据上传成功 RustFS: {self.bucket_name}/{object_key}")
|
logger.info(f"JSON数据上传成功 RustFS: {self.bucket_name}/{object_key}")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -192,18 +211,23 @@ class RustFSManager:
|
|||||||
|
|
||||||
async def download_file(self, file_type: str, object_key: str) -> bytes:
|
async def download_file(self, file_type: str, object_key: str) -> bytes:
|
||||||
"""从 RustFS 下载文件"""
|
"""从 RustFS 下载文件"""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise RuntimeError("RustFS 未连接")
|
raise RuntimeError("RustFS 未连接")
|
||||||
|
|
||||||
if file_type not in self.file_types:
|
if file_type not in self.file_types:
|
||||||
raise ValueError(f"未知的文件类型: {file_type}")
|
raise ValueError(f"未知的文件类型: {file_type}")
|
||||||
|
|
||||||
try:
|
def _download():
|
||||||
response = self.client.get_object(self.bucket_name, object_key)
|
response = self.client.get_object(self.bucket_name, object_key)
|
||||||
data = response.read()
|
data = response.read()
|
||||||
response.close()
|
response.close()
|
||||||
response.release_conn()
|
response.release_conn()
|
||||||
|
return data
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = await asyncio.to_thread(_download)
|
||||||
logger.debug(f"文件下载成功: {self.bucket_name}/{object_key}")
|
logger.debug(f"文件下载成功: {self.bucket_name}/{object_key}")
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@@ -213,14 +237,19 @@ class RustFSManager:
|
|||||||
|
|
||||||
async def get_file_info(self, file_type: str, object_key: str) -> Dict[str, Any]:
|
async def get_file_info(self, file_type: str, object_key: str) -> Dict[str, Any]:
|
||||||
"""获取文件信息"""
|
"""获取文件信息"""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise RuntimeError("RustFS 未连接")
|
raise RuntimeError("RustFS 未连接")
|
||||||
|
|
||||||
if file_type not in self.file_types:
|
if file_type not in self.file_types:
|
||||||
raise ValueError(f"未知的文件类型: {file_type}")
|
raise ValueError(f"未知的文件类型: {file_type}")
|
||||||
|
|
||||||
|
def _get_stat():
|
||||||
|
return self.client.stat_object(self.bucket_name, object_key)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
stat = self.client.stat_object(self.bucket_name, object_key)
|
stat = await asyncio.to_thread(_get_stat)
|
||||||
return {
|
return {
|
||||||
'size': stat.size,
|
'size': stat.size,
|
||||||
'etag': stat.etag,
|
'etag': stat.etag,
|
||||||
@@ -234,14 +263,19 @@ class RustFSManager:
|
|||||||
|
|
||||||
async def delete_file(self, file_type: str, object_key: str):
|
async def delete_file(self, file_type: str, object_key: str):
|
||||||
"""删除 RustFS 中的文件"""
|
"""删除 RustFS 中的文件"""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise RuntimeError("RustFS 未连接")
|
raise RuntimeError("RustFS 未连接")
|
||||||
|
|
||||||
if file_type not in self.file_types:
|
if file_type not in self.file_types:
|
||||||
raise ValueError(f"未知的文件类型: {file_type}")
|
raise ValueError(f"未知的文件类型: {file_type}")
|
||||||
|
|
||||||
try:
|
def _delete():
|
||||||
self.client.remove_object(self.bucket_name, object_key)
|
self.client.remove_object(self.bucket_name, object_key)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await asyncio.to_thread(_delete)
|
||||||
logger.info(f"文件删除成功: {self.bucket_name}/{object_key}")
|
logger.info(f"文件删除成功: {self.bucket_name}/{object_key}")
|
||||||
|
|
||||||
except S3Error as e:
|
except S3Error as e:
|
||||||
@@ -250,6 +284,8 @@ class RustFSManager:
|
|||||||
|
|
||||||
async def list_files(self, file_type: str, prefix: str = '') -> list:
|
async def list_files(self, file_type: str, prefix: str = '') -> list:
|
||||||
"""列出存储桶中的文件"""
|
"""列出存储桶中的文件"""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise RuntimeError("RustFS 未连接")
|
raise RuntimeError("RustFS 未连接")
|
||||||
|
|
||||||
@@ -262,8 +298,11 @@ class RustFSManager:
|
|||||||
if prefix:
|
if prefix:
|
||||||
full_prefix += prefix
|
full_prefix += prefix
|
||||||
|
|
||||||
|
def _list():
|
||||||
|
return list(self.client.list_objects(self.bucket_name, prefix=full_prefix, recursive=True))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
objects = self.client.list_objects(self.bucket_name, prefix=full_prefix, recursive=True)
|
objects = await asyncio.to_thread(_list)
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
'object_key': obj.object_name,
|
'object_key': obj.object_name,
|
||||||
@@ -283,18 +322,23 @@ class RustFSManager:
|
|||||||
expires: int = 3600,
|
expires: int = 3600,
|
||||||
method: str = 'GET') -> str:
|
method: str = 'GET') -> str:
|
||||||
"""生成预签名URL(临时访问链接)"""
|
"""生成预签名URL(临时访问链接)"""
|
||||||
|
import asyncio
|
||||||
|
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
raise RuntimeError("RustFS 未连接")
|
raise RuntimeError("RustFS 未连接")
|
||||||
|
|
||||||
if file_type not in self.file_types:
|
if file_type not in self.file_types:
|
||||||
raise ValueError(f"未知的文件类型: {file_type}")
|
raise ValueError(f"未知的文件类型: {file_type}")
|
||||||
|
|
||||||
try:
|
def _generate_url():
|
||||||
url = self.client.presigned_get_object(
|
return self.client.presigned_get_object(
|
||||||
self.bucket_name,
|
self.bucket_name,
|
||||||
object_key,
|
object_key,
|
||||||
expires=timedelta(seconds=expires)
|
expires=timedelta(seconds=expires)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
url = await asyncio.to_thread(_generate_url)
|
||||||
return url
|
return url
|
||||||
|
|
||||||
except S3Error as e:
|
except S3Error as e:
|
||||||
@@ -311,14 +355,16 @@ class RustFSManager:
|
|||||||
|
|
||||||
async def get_storage_stats(self) -> Dict[str, Any]:
|
async def get_storage_stats(self) -> Dict[str, Any]:
|
||||||
"""获取存储统计信息"""
|
"""获取存储统计信息"""
|
||||||
try:
|
import asyncio
|
||||||
|
|
||||||
|
def _get_stats():
|
||||||
buckets = self.client.list_buckets()
|
buckets = self.client.list_buckets()
|
||||||
total_objects = 0
|
total_objects = 0
|
||||||
total_size = 0
|
total_size = 0
|
||||||
namespace_stats = {}
|
namespace_stats = {}
|
||||||
|
|
||||||
for bucket in buckets:
|
for bucket in buckets:
|
||||||
objects = self.client.list_objects(bucket.name, recursive=True)
|
objects = list(self.client.list_objects(bucket.name, recursive=True))
|
||||||
bucket_count = 0
|
bucket_count = 0
|
||||||
bucket_size = 0
|
bucket_size = 0
|
||||||
|
|
||||||
@@ -340,6 +386,9 @@ class RustFSManager:
|
|||||||
'namespace_stats': namespace_stats
|
'namespace_stats': namespace_stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
return await asyncio.to_thread(_get_stats)
|
||||||
|
|
||||||
except S3Error as e:
|
except S3Error as e:
|
||||||
logger.error(f"RustFS 获取统计信息失败: {e}")
|
logger.error(f"RustFS 获取统计信息失败: {e}")
|
||||||
raise
|
raise
|
||||||
|
|||||||
Reference in New Issue
Block a user