diff --git a/package.json b/package.json index 8d5d905..1bda7ce 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minecraft-music-quiz-installer", - "version": "0.4.10", + "version": "0.4.11", "description": "마인크래프트 음악퀴즈 간편설치기 + 관리 사이트", "main": "dist/installer/main.js", "scripts": { diff --git a/src/installer-rp/main.ts b/src/installer-rp/main.ts index 701871b..12a53ad 100644 --- a/src/installer-rp/main.ts +++ b/src/installer-rp/main.ts @@ -702,8 +702,37 @@ app.whenReady().then(() => { }) }) +// 종료 시 임시 파일(.temp) 정리. 예전엔 window-all-closed 에서 fsp.rm 을 fire-and-forget +// 으로 호출하고 곧바로 app.quit() 해서, 삭제가 끝나기 전에 프로세스가 죽어 미리 받아둔 +// 내용이 남곤 했다. 또 '재시도 중' 이면 yt-dlp/ffmpeg 자식이 파일을 잠가 삭제가 실패한다. +// → 자식을 먼저 죽여 잠금을 풀고, 삭제가 끝날 때까지 종료를 미룬 뒤 실제로 종료한다. +let rpExitCleanupDone = false +async function cleanupTempOnExit(): Promise { + state.cancelRequested = true + for (const child of state.activeChildren) { + try { if (!child.killed) child.kill() } catch { /* noop */ } + } + const tempDir = path.join(getMcCustomDir(), '.temp') + // 자식 종료로 파일 잠금이 풀릴 시간을 주며 몇 번 재시도. + for (let attempt = 0; attempt < 3; attempt++) { + await new Promise((r) => setTimeout(r, attempt === 0 ? 200 : 400)) + try { + await fsp.rm(tempDir, { recursive: true, force: true }) + if (!fs.existsSync(tempDir)) return + } catch { /* 잠금 등 — 다음 시도 */ } + } +} + +app.on('before-quit', (event) => { + if (rpExitCleanupDone) return + event.preventDefault() + void cleanupTempOnExit().finally(() => { + rpExitCleanupDone = true + app.quit() + }) +}) + app.on('window-all-closed', () => { - // 강제 종료 시에도 임시 파일은 정리. - fsp.rm(path.join(getMcCustomDir(), '.temp'), { recursive: true, force: true }).catch(() => {}) + // app.quit() → before-quit 에서 임시 파일을 정리한 뒤 실제 종료. if (process.platform !== 'darwin') app.quit() })