fix: print3d_model 예상 출력시간이 항상 6666초로 나오는 CuraEngine CLI 버그 수정

CuraEngine 5.0.0 소스 확인 결과, CommandLine 백엔드는 isSequential()이 항상
true라 슬라이싱 "시작 전"에 G-code 헤더를 미리 써버리고(processStartingCode
-> getFileHeader, print_time 인자 없음) 끝난 뒤 되돌아가 실제값으로 덮어쓰는
코드가 어디에도 없다. 그래서 ;TIME: 헤더는 항상 gcodeExport.cpp에 하드코딩된
더미값(6666)만 남는다 — 확률적 버그가 아니라 CLI 모드의 구조적 한계였음.

실제 값은 슬라이싱 완료 후 stderr(verbose 로그)에 "Print time (s): N"으로만
찍히므로, G-code 파일 헤더 대신 stderr를 파싱하도록 변경.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
kim
2026-09-20 13:16:34 +09:00
co-authored by Claude Sonnet 5
parent fdbed6266e
commit 33b5a258b2
+13 -7
View File
@@ -89,18 +89,20 @@ async function downloadStl(url: string, outPath: string): Promise<{ ok: true } |
return { ok: true };
}
function runCuraEngine(args: string[], timeoutMs: number): Promise<{ ok: true; stdout: string } | { ok: false; detail: string }> {
function runCuraEngine(args: string[], timeoutMs: number): Promise<{ ok: true; stdout: string; stderr: string } | { ok: false; detail: string }> {
return new Promise((resolve) => {
const proc = spawn(CURA_ENGINE_BIN, args, { stdio: ['ignore', 'pipe', 'pipe'] });
let stdout = '';
let stderr = '';
proc.stdout?.on('data', (d: Buffer) => { stdout += d.toString('utf8'); });
proc.stderr?.on('data', (d: Buffer) => { stderr += d.toString('utf8'); if (stderr.length > 4000) stderr = stderr.slice(-4000); });
// 실패시 에러메시지용으로 뒤쪽만 있으면 되지만, 성공시엔 "Print time (s): N" 요약 줄을
// 파싱해야 하므로(아래 CLI 헤더 버그 설명 참고) 여기서는 자르지 않고 전체 보존한다.
proc.stderr?.on('data', (d: Buffer) => { stderr += d.toString('utf8'); });
const killTimer = setTimeout(() => { try { proc.kill('SIGKILL'); } catch { /* noop */ } }, timeoutMs);
proc.on('error', (e) => { clearTimeout(killTimer); resolve({ ok: false, detail: String(e.message || e) }); });
proc.on('close', (code) => {
clearTimeout(killTimer);
if (code === 0) resolve({ ok: true, stdout });
if (code === 0) resolve({ ok: true, stdout, stderr });
else resolve({ ok: false, detail: stderr.split('\n').filter(Boolean).slice(-10).join(' ') || `CuraEngine exit ${code}` });
});
});
@@ -240,10 +242,14 @@ export const print3dModelTool = {
return { success: false, error: '슬라이싱은 끝났는데 G-code 파일이 비정상입니다.' };
}
// CuraEngine은 "Print time (s):" 요약을 stderr(verbose 로그)에 찍고, stdout엔 아무것도
// 안 남긴다 — 대신 생성된 G-code 자체의 헤더 주석(;TIME:초)에서 직접 읽는 게 더 안정적.
const gcodeHead = fs.readFileSync(gcodePath, 'utf8').slice(0, 2000);
const timeMatch = gcodeHead.match(/;TIME:(\d+)/);
// 주의: G-code 파일 자체의 ";TIME:" 헤더는 CLI 모드에서 절대 신뢰할 수 없다 — CuraEngine
// CLI(CommandLine 백엔드)는 슬라이싱 "시작 전"에 헤더를 이미 써버리고(isSequential()이
// 항상 true라 processStartingCode에서 print_time 없이 getFileHeader 호출) 끝난 뒤에도
// 되돌아가 덮어쓰는 코드가 CuraEngine 소스 어디에도 없다 — 그래서 항상 코드에 하드코딩된
// 더미값(gcodeExport.cpp의 `;TIME:6666`)이 그대로 남는다(2026-09-20 소스 확인, 5.0.0).
// 실제 값은 슬라이싱이 끝난 뒤 stderr(verbose 로그, -v 필요)에 "Print time (s): N"으로만
// 찍히므로 거기서 파싱해야 한다.
const timeMatch = slice.stderr.match(/Print time \(s\):\s*(\d+)/);
const printTimeSec = timeMatch ? Number(timeMatch[1]) : null;
const up = await uploadToMoonraker(gcodePath, gcodeFilename);