From 33b5a258b28438b4bc6fcc6b303869dc39149395 Mon Sep 17 00:00:00 2001 From: kim Date: Sun, 20 Sep 2026 13:16:34 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20print3d=5Fmodel=20=EC=98=88=EC=83=81=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=EC=8B=9C=EA=B0=84=EC=9D=B4=20=ED=95=AD?= =?UTF-8?q?=EC=83=81=206666=EC=B4=88=EB=A1=9C=20=EB=82=98=EC=98=A4?= =?UTF-8?q?=EB=8A=94=20CuraEngine=20CLI=20=EB=B2=84=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/tools/print3d.ts | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/tools/print3d.ts b/src/tools/print3d.ts index 0c28278..6730734 100644 --- a/src/tools/print3d.ts +++ b/src/tools/print3d.ts @@ -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);