- 新增XCAF转换器,直接从STP到GLB保留完整装配层级 - 修复HTTP API与CLI参数不一致问题 - 修复静默吞没错误的问题,遵循快速失败原则 - 清理旧文件,整理测试文件到tests目录 - 添加URL下载支持,可直接转换远程STP文件 - 更新文档,准确描述XCAF装配保留功能 技术改进: - 使用STEPCAFControl_Reader读取带装配信息的STEP文件 - 通过RWGltf_CafWriter直接导出GLB,无需STL中间格式 - 支持CPU多线程并行三角化 - HTTP API和CLI使用完全一致的转换参数 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
145 lines
4.9 KiB
Python
145 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
任务管理服务
|
||
负责任务的创建、跟踪和状态管理
|
||
"""
|
||
|
||
import asyncio
|
||
import uuid
|
||
from datetime import datetime
|
||
from typing import Dict, Optional
|
||
from core.models import ConvertTask, TaskStatus, ConvertOptions
|
||
from core.converter import StpToGlbConverter
|
||
|
||
|
||
class TaskManager:
|
||
"""任务管理器"""
|
||
|
||
def __init__(self):
|
||
self.tasks: Dict[str, ConvertTask] = {}
|
||
self.running_tasks: Dict[str, asyncio.Task] = {}
|
||
|
||
def create_task(self, input_path: str, output_path: str, options: ConvertOptions) -> ConvertTask:
|
||
"""创建新任务"""
|
||
task_id = str(uuid.uuid4())
|
||
task = ConvertTask(
|
||
task_id=task_id,
|
||
input_path=input_path,
|
||
output_path=output_path,
|
||
options=options
|
||
)
|
||
self.tasks[task_id] = task
|
||
return task
|
||
|
||
def get_task(self, task_id: str) -> Optional[ConvertTask]:
|
||
"""获取任务"""
|
||
return self.tasks.get(task_id)
|
||
|
||
def get_all_tasks(self) -> Dict[str, ConvertTask]:
|
||
"""获取所有任务"""
|
||
return self.tasks.copy()
|
||
|
||
async def process_task(self, task_id: str) -> None:
|
||
"""处理转换任务"""
|
||
task = self.tasks.get(task_id)
|
||
if not task:
|
||
return
|
||
|
||
# 更新任务状态
|
||
task.status = TaskStatus.PROCESSING
|
||
task.started_at = datetime.now()
|
||
task.message = "开始处理转换任务"
|
||
|
||
converter = StpToGlbConverter()
|
||
|
||
# 设置进度回调
|
||
def progress_callback(progress: int, message: str):
|
||
task.progress = progress
|
||
task.message = message
|
||
|
||
converter.set_progress_callback(progress_callback)
|
||
|
||
try:
|
||
# 默认使用层级转换,与CLI保持一致
|
||
await asyncio.get_event_loop().run_in_executor(
|
||
None,
|
||
lambda: converter.convert(
|
||
stp_path=task.input_path,
|
||
glb_path=task.output_path,
|
||
linear_deflection=task.options.precision.linear_deflection,
|
||
angular_deflection=task.options.precision.angular_deflection,
|
||
embed_textures=True,
|
||
y_up=True
|
||
)
|
||
)
|
||
|
||
# 标记完成
|
||
task.status = TaskStatus.COMPLETED
|
||
task.completed_at = datetime.now()
|
||
task.progress = 100
|
||
task.message = "转换完成"
|
||
|
||
except Exception as e:
|
||
# 标记失败
|
||
task.status = TaskStatus.FAILED
|
||
task.completed_at = datetime.now()
|
||
task.error_message = str(e)
|
||
task.message = f"转换失败: {str(e)}"
|
||
|
||
finally:
|
||
# 清理运行任务记录
|
||
if task_id in self.running_tasks:
|
||
del self.running_tasks[task_id]
|
||
|
||
async def start_task(self, task_id: str) -> bool:
|
||
"""启动任务处理"""
|
||
if task_id not in self.tasks:
|
||
return False
|
||
|
||
if task_id in self.running_tasks:
|
||
return False # 任务已在运行
|
||
|
||
# 创建异步任务
|
||
asyncio_task = asyncio.create_task(self.process_task(task_id))
|
||
self.running_tasks[task_id] = asyncio_task
|
||
|
||
return True
|
||
|
||
def cancel_task(self, task_id: str) -> bool:
|
||
"""取消任务"""
|
||
if task_id in self.running_tasks:
|
||
self.running_tasks[task_id].cancel()
|
||
del self.running_tasks[task_id]
|
||
|
||
task = self.tasks.get(task_id)
|
||
if task:
|
||
task.status = TaskStatus.FAILED
|
||
task.error_message = "任务被取消"
|
||
task.message = "任务已取消"
|
||
task.completed_at = datetime.now()
|
||
|
||
return True
|
||
return False
|
||
|
||
def cleanup_completed_tasks(self, max_tasks: int = 100) -> None:
|
||
"""清理已完成的任务,保持任务数量在限制内"""
|
||
if len(self.tasks) <= max_tasks:
|
||
return
|
||
|
||
# 按完成时间排序,保留最新的任务
|
||
completed_tasks = [
|
||
(task_id, task) for task_id, task in self.tasks.items()
|
||
if task.status in [TaskStatus.COMPLETED, TaskStatus.FAILED] and task.completed_at
|
||
]
|
||
|
||
if len(completed_tasks) > max_tasks // 2:
|
||
# 删除最老的已完成任务
|
||
completed_tasks.sort(key=lambda x: x[1].completed_at)
|
||
to_remove = completed_tasks[:len(completed_tasks) - max_tasks // 2]
|
||
|
||
for task_id, _ in to_remove:
|
||
del self.tasks[task_id]
|
||
|
||
|
||
# 全局任务管理器实例
|
||
task_manager = TaskManager() |