# 🔄 สัญญาทางเทคนิค: วงจรชีวิตของระบบอัปเดต (Updater Temp Lifecycle Contract) เอกสารนี้ระบุข้อตกลงและสัญญาทางเทคนิค (Contract) สำหรับระบบอัปเดตและบิลด์ในเครื่องของ G-Launcher ซึ่งครอบคลุมทั้งสคริปต์ PowerShell ([`scripts/bootstrap.ps1`](../scripts/bootstrap.ps1)) และบริการ Go Backend ([`internal/git-service/launcher.go`](../internal/git-service/launcher.go)) --- ## 1. วัตถุประสงค์และข้อจำกัดของระบบปฏิบัติการ (Operating System Constraints) ### ปัญหาข้อจำกัดของ Windows: 1. **Windows Executable Locking:** เมื่อโปรเซส `.exe` กำลังทำงานอยู่ ระบบปฏิบัติการจะเปิดแฮนเดิลไฟล์ด้วยการล็อกแบบแชร์การอ่าน (`FILE_SHARE_READ`) แต่ไม่อนุญาตให้เขียน (`GENERIC_WRITE`) หรือลบทิ้ง (`DELETE`) โดยตรง 2. **ข้อยกเว้นการเปลี่ยนชื่อ (Rename Privilege):** บน Windows อนุญาตให้ **เปลี่ยนชื่อ (Rename/Move)** ไฟล์ executable ที่กำลังทำงานอยู่ได้ ตราบใดที่ยังอยู่บนโวลุม (Volume/Drive) เดียวกัน 3. **การหลีกเลี่ยง Build In-Place:** การรัน `git pull` หรือ `go build` ทับโฟลเดอร์หลักของ Launcher ขณะที่ตัว Launcher รันอยู่ จะทำให้เกิด Exception `Access is denied` ทันที และอาจทำให้โฟลเดอร์ซอร์สโค้ดค้างอยู่ในสถานะไม่สมบูรณ์ --- ## 2. ขั้นตอนทั้ง 4 ของวงจรชีวิต (The 4 Lifecycle Phases) ### Phase 1: การจัดเตรียมพื้นที่ชั่วคราวและการดาวน์โหลด (Download to Temp) * **PowerShell:** * โฟลเดอร์เป้าหมาย: `$tempBuildDir = Join-Path $rootDir "temp\build_workspace"` * หากมีโฟลเดอร์ตกค้างจากรอบก่อน ให้สั่งลบทิ้งก่อนสร้างใหม่เสมอ * สั่ง `git clone --depth 1 --branch Dev https://gaytea.cod-algieba.ts.net/GaCy/G-Launcher.git $tempBuildDir` * หากการ Clone ผ่านเน็ตเวิร์กล้มเหลว (เช่น ทำงานแบบออฟไลน์) สคริปต์จะสลับไป Clone จากโฟลเดอร์ท้องถิ่น (`$rootDir`) เข้าสู่ `$tempBuildDir` แทน * **Go Backend:** * ใช้ `tempDir, err := os.MkdirTemp("", "g-launcher-build-*")` * สั่งงาน Git ผ่านฟังก์ชัน `ensureGit()` เพื่อรับประกันว่ามี Portable MinGit ทำงานได้โดยไม่ต้องพึ่งสิทธิ์ Administrator ### Phase 2: การคอมไพล์แบบแยกส่วนในโฟลเดอร์ชั่วคราว (Isolated Build) * สวิตช์ Working Directory เข้าสู่โฟลเดอร์ชั่วคราว (`Push-Location $tempBuildDir` หรือ `cmd.Dir = tempDir`) * ลำดับการคอมไพล์: 1. `npm --prefix frontend install --no-audit --no-fund` (ติดตั้ง dependencies ของ React 19) 2. `npm --prefix frontend run build` (คอมไพล์ assets ผ่าน Vite 8 ได้ผลลัพธ์ลง `frontend/dist/`) 3. `go mod tidy` (จัดระเบียบ Go modules) 4. `wails3 generate syso` (สร้าง Windows PE Resource, Manifest, DPI awareness, และ Icon) 5. `go build -tags production -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui" -o bin/G-Launcher.exe .` * ตรวจสอบว่าไฟล์ไบนารีผลลัพธ์ถูกสร้างขึ้นจริง และมีขนาดมากกว่า 0 ไบต์ * สลับกลับสู่ Working Directory เดิม (`Pop-Location`) ก่อนเริ่มขั้นตอนถัดไป ### Phase 3: การสลับไฟล์ไบนารีอย่างปลอดภัยและการ Rollback (Atomic Swap & Safe Rollback) * หากไฟล์เป้าหมาย `bin/G-Launcher.exe` มีอยู่เดิม: 1. เปลี่ยนชื่อไฟล์เดิมเป็น `bin/G-Launcher.exe.old` 2. ย้ายไฟล์ใหม่จากโฟลเดอร์ Temp มาวางที่ `bin/G-Launcher.exe` 3. หากการย้ายไฟล์ล้มเหลว (เกิด Exception): * **Rollback ทันที:** ย้าย `bin/G-Launcher.exe.old` กลับมาเป็น `bin/G-Launcher.exe` เพื่อให้ผู้ใช้ยังสามารถเปิดโปรแกรมเดิมได้ * แจ้งข้อผิดพลาดและยุติการทำงาน 4. หากการย้ายไฟล์สำเร็จ: * ลบไฟล์ `bin/G-Launcher.exe.old` (หากโปรแกรมเดิมกำลังรันอยู่และยังลบไม่ได้ ไฟล์นี้จะถูกเพิกเฉยและรอการลบในรอบถัดไป) * ในฝั่ง Go Backend ใช้ไลบรารี `github.com/minio/selfupdate`: * ฟังก์ชัน `selfupdate.Apply(newBinaryReader, selfupdate.Options{})` ดำเนินการ Rename & Swap แบบ Atomic ในระดับ Native Windows API ### Phase 4: การทำลายโฟลเดอร์ชั่วคราว (Guaranteed Temp Purge) * **PowerShell:** * ครอบกระบวนการทั้งหมดด้วยบล็อก `try { ... } finally { ... }` * ในบล็อก `finally`: ```powershell Set-Location $rootDir if (Test-Path $tempBuildDir) { Remove-Item -LiteralPath $tempBuildDir -Recurse -Force -ErrorAction SilentlyContinue } ``` * การันตีว่าโฟลเดอร์ Temp จะถูกลบออก 100% เสมอ ไม่ว่าการบิลด์จะสำเร็จหรือเกิดข้อผิดพลาด * **Go Backend:** * ใช้คำสั่ง `defer os.RemoveAll(tempDir)` ทันทีหลังสร้าง `os.MkdirTemp` สำเร็จ --- ## 3. หลักฐานการตรวจสอบจริง (Empirical Verification Log) ผลการทดสอบสคริปต์จริงในสภาพแวดล้อม Windows 64-bit (Task ID: `task-607`): * โฟลเดอร์ชั่วคราว: `C:\Users\Phitchayut\Desktop\G Launcher\temp\build_workspace` * เวลาในการดาวน์โหลดและแตกแพ็กเกจ Frontend: 21 วินาที * เวลาในการคอมไพล์ Vite Frontend: 751 มิลลิวินาที * ขนาดไฟล์ Executable ผลลัพธ์: **28,677,632 ไบต์ (27.35 MB)** * ผลการตรวจสอบการล้างขยะ: คำสั่ง `Test-Path .\temp\build_workspace` คืนค่า **`False`** (โฟลเดอร์ชั่วคราวถูกลบทิ้งหมดจด ไร้ขยะตกค้าง)