Files
G-Launcher/Doc/updater-temp-lifecycle.md
T

75 lines
8.0 KiB
Markdown

# 🔄 สัญญาทางเทคนิค: วงจรชีวิตของระบบอัปเดต (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`** (โฟลเดอร์ชั่วคราวถูกลบทิ้งหมดจด ไร้ขยะตกค้าง)