Files
G-Launcher/Doc/UPDATER_SYSTEM.md
T

104 lines
7.3 KiB
Markdown

# 🚀 G-Launcher Updater & Bootstrap Build System
เอกสารนี้อธิบายรายละเอียดเชิงลึกของระบบ **Auto-Update & Local Build Bootstrap** ของ G-Launcher ซึ่งถูกออกแบบมาเพื่อรองรับกรณีที่ผู้ใช้หรือเซิร์ฟเวอร์ Git (เช่น Gitea) ไม่มี CI/CD Runner บนคลาวด์สำหรับคอมไพล์ไบนารีล่วงหน้า
---
## 🎯 กฎเหล็กของระบบอัปเดต (The Golden Updater Rule)
> **"โหลด Temp มา -> Build ใหม่ใน Temp -> นำมาแทนของเก่า -> ลบ Temp ทิ้ง 100%"**
### เหตุผลทางสถาปัตยกรรม (Architectural Rationale)
1. **ป้องกัน Windows File Lock:** ระบบปฏิบัติการ Windows จะล็อกไฟล์ `.exe` ที่กำลังทำงานอยู่ทันที ทำให้ไม่สามารถเขียนทับ (overwrite) ตัวเองได้โดยตรง แต่ Windows อนุญาตให้ **เปลี่ยนชื่อ (Rename)** ไฟล์ executable ที่กำลังทำงานอยู่ได้
2. **รักษาความสะอาดของโปรเจกต์ (Zero Pollution):** ไม่ทำการ build หรือ pull โค้ดทับโฟลเดอร์ทำงานหลักโดยตรง เพื่อป้องกันไฟล์ขยะหรือ node_modules ปนเปื้อน
3. **Atomic Rollback:** หากกระบวนการคอมไพล์ใน Temp ล้มเหลว โปรแกรมเวอร์ชันเดิมจะยังคงทำงานได้สมบูรณ์ ไม่เสียหาย
---
## 🔄 วงจรชีวิตของระบบอัปเดต (Updater Lifecycle)
```mermaid
sequenceDiagram
autonumber
actor User as ผู้ใช้งาน / Contributor
participant Bootstrap as bootstrap.ps1 / Go GitService
participant TempDir as โฟลเดอร์ชั่วคราว (Temp)
participant Git as Git Repository (Dev Branch)
participant Target as bin/G-Launcher.exe
User->>Bootstrap: รัน update-and-build.bat หรือกด Update ใน UI
Note over Bootstrap: ตรวจสอบและเตรียม Portable Git, Go, Node.js (tools/)
Bootstrap->>TempDir: 1. สร้างโฟลเดอร์ชั่วคราว (temp/build_workspace)
Bootstrap->>Git: 2. Clone โค้ดสาขา Dev ลงใน TempDir
Git-->>TempDir: ดาวน์โหลดซอร์สโค้ดสำเร็จ
rect rgb(30, 40, 60)
Note over TempDir: 3. บิลด์ทั้งหมดภายใน TempDir
TempDir->>TempDir: npm install & npm run build (React Frontend)
TempDir->>TempDir: go mod tidy
TempDir->>TempDir: wails3 generate syso (Manifest & Icon)
TempDir->>TempDir: go build -tags production -> bin/G-Launcher.exe
end
rect rgb(40, 60, 40)
Note over Bootstrap,Target: 4. สลับไฟล์ไบนารี (Atomic Swap & Rollback)
Bootstrap->>Target: เปลี่ยนชื่อตัวเก่าเป็น G-Launcher.exe.old
Bootstrap->>Target: ย้ายตัวใหม่จาก TempDir มาแทนที่ Target
alt ย้ายไฟล์สำเร็จ
Bootstrap->>Target: ลบไฟล์ G-Launcher.exe.old
else เกิดข้อผิดพลาด
Bootstrap->>Target: Rollback ย้าย .old กลับมาเป็นตัวหลัก
end
end
rect rgb(60, 30, 30)
Note over Bootstrap,TempDir: 5. ล้างและทำลายโฟลเดอร์ชั่วคราว (finally / defer)
Bootstrap->>TempDir: ลบโฟลเดอร์ TempDir ทั้งหมด (Purge 100%)
end
Bootstrap->>Target: 6. รัน G-Launcher.exe เวอร์ชันใหม่
```
---
## 🛠️ ไฟล์ที่เกี่ยวข้องและการทำงาน
### 1. [`update-and-build.bat`](../update-and-build.bat)
* สคริปต์ Batch สั้นๆ สำหรับดับเบิลคลิกบน Windows
* ตั้งค่า UTF-8 (`chcp 65001`) และส่งต่อการทำงานไปยัง `scripts/bootstrap.ps1` ผ่านคำสั่ง:
```cmd
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\bootstrap.ps1" %*
```
### 2. [`scripts/bootstrap.ps1`](../scripts/bootstrap.ps1)
* **การตรวจหาและดาวน์โหลดเครื่องมือพกพา (Prerequisites):**
* `Git`: หากในเครื่องไม่มี จะดาวน์โหลด **Portable MinGit** มาไว้ที่ `tools/mingit/`
* `Go`: หากไม่มี Go compiler จะดาวน์โหลด **Portable Go 1.24** มาไว้ที่ `tools/go/`
* `Node.js & npm`: หากไม่มี Node.js จะดาวน์โหลด **Portable Node.js v22** มาไว้ที่ `tools/node/`
* `Wails v3 CLI`: ติดตั้งผ่าน `go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0-alpha.74`
* **Isolated Temp Build:**
* ใช้โฟลเดอร์ `$tempBuildDir = Join-Path $rootDir "temp\build_workspace"`
* สั่ง `git clone --depth 1 --branch Dev <RepoUrl> $tempBuildDir`
* รัน `npm install`, `npm run build`, และ `go build` ภายใน Temp
* **Atomic Replacement & Rollback:**
* เปลี่ยนชื่อ `bin/G-Launcher.exe` เดิมเป็น `.old`
* ย้ายตัวใหม่เข้ามาแทนที่ หากล้มเหลวจะคืนค่า `.old` ทันที
* **Guaranteed Cleanup:**
* วางคำสั่งลบโฟลเดอร์ชั่วคราวไว้ในบล็อก `finally { ... }` เพื่อรับประกันว่าจะถูกลบออก 100% แม้สคริปต์จะหยุดทำงานกลางคัน
### 3. Go Backend: [`internal/git-service/launcher.go`](../internal/git-service/launcher.go)
* ฟังก์ชัน [`BuildAndUpdateFromSource(branch string)`](../internal/git-service/launcher.go#L95) ใน `GitService`:
```go
// 1. สร้างโฟลเดอร์ชั่วคราว
tempDir, err := os.MkdirTemp("", "g-launcher-build-*")
defer os.RemoveAll(tempDir) // รับประกันการลบโฟลเดอร์ Temp เสมอ
// 2. Clone โค้ดต้นทาง
cloneCmd := exec.Command(gitExe, "clone", "--depth", "1", "--branch", branch, constant.LauncherRepoURL, tempDir)
...
// 3. Build ใน Temp
...
// 4. สลับไฟล์ที่กำลังรันอยู่ด้วย selfupdate.Apply
err = selfupdate.Apply(builtFile, selfupdate.Options{})
```