77 lines
2.6 KiB
Python
77 lines
2.6 KiB
Python
|
|
# services/stp_materializer.py
|
||
|
|
"""按 task_id 把 STP 原件从持久化存储落盘为临时文件(方案 B)。
|
||
|
|
|
||
|
|
任务完成后 TopoDS_Shape 不驻留内存/Redis;需要几何的端点(倒扣检测、
|
||
|
|
按需重导出等)通过 STP 原件重建:PG(object_key) -> RustFS 下载 -> 临时文件,
|
||
|
|
OCC 解析在常驻子进程内完成(occ_worker 的 detect_undercuts 等操作,见
|
||
|
|
occ_process_pool)。本模块只负责把原件落到调用方可传路径的临时文件。
|
||
|
|
"""
|
||
|
|
import tempfile
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import Optional
|
||
|
|
|
||
|
|
from sqlalchemy import select
|
||
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
|
|
||
|
|
from moldinsight.models import ProcessingTask, STPFile
|
||
|
|
from shared.utils.logger import get_logger
|
||
|
|
|
||
|
|
logger = get_logger(__name__)
|
||
|
|
|
||
|
|
|
||
|
|
class STPMaterializer:
|
||
|
|
"""任务 STP 原件落盘器"""
|
||
|
|
|
||
|
|
async def materialize_stp_for_task(
|
||
|
|
self, db_session: AsyncSession, task_id: str
|
||
|
|
) -> Optional[Path]:
|
||
|
|
"""重建任务的产品几何原件为临时文件。
|
||
|
|
|
||
|
|
任务不存在或 STP 原件不可用时返回 None;返回的临时文件由调用方
|
||
|
|
finally 清理(unlink)。
|
||
|
|
"""
|
||
|
|
result = await db_session.execute(
|
||
|
|
select(ProcessingTask, STPFile)
|
||
|
|
.join(STPFile, ProcessingTask.stp_file_id == STPFile.id)
|
||
|
|
.where(ProcessingTask.task_id == task_id)
|
||
|
|
)
|
||
|
|
row = result.first()
|
||
|
|
if not row:
|
||
|
|
logger.warning(f"STP 原件落盘失败:任务不存在 {task_id}")
|
||
|
|
return None
|
||
|
|
|
||
|
|
_, stp_file = row
|
||
|
|
if not stp_file.object_key:
|
||
|
|
logger.warning(f"STP 原件落盘失败:任务缺少 object_key {task_id}")
|
||
|
|
return None
|
||
|
|
|
||
|
|
from moldinsight.storage.rustfs_storage import rustfs_manager
|
||
|
|
|
||
|
|
try:
|
||
|
|
data = await rustfs_manager.download_file(
|
||
|
|
file_type="stp_files", object_key=stp_file.object_key
|
||
|
|
)
|
||
|
|
except Exception as exc:
|
||
|
|
logger.error(f"STP 原件落盘失败:下载失败 {task_id}: {exc}")
|
||
|
|
return None
|
||
|
|
|
||
|
|
original_name = Path(stp_file.original_filename or "model.stp").name or "model.stp"
|
||
|
|
tmp = tempfile.NamedTemporaryFile(
|
||
|
|
suffix=Path(original_name).suffix or ".stp", prefix=f"mold_{task_id}_", delete=False
|
||
|
|
)
|
||
|
|
tmp.write(data)
|
||
|
|
tmp.close()
|
||
|
|
logger.debug(f"STP 原件已落盘: {tmp.name}")
|
||
|
|
return Path(tmp.name)
|
||
|
|
|
||
|
|
|
||
|
|
# 惰性单例
|
||
|
|
_stp_materializer: Optional[STPMaterializer] = None
|
||
|
|
|
||
|
|
|
||
|
|
def get_stp_materializer() -> STPMaterializer:
|
||
|
|
global _stp_materializer
|
||
|
|
if _stp_materializer is None:
|
||
|
|
_stp_materializer = STPMaterializer()
|
||
|
|
return _stp_materializer
|