jim800121chen ff9bbc81ed feat(local-tool): M9-4.5 — server SIGTERM + Wails OnBeforeClose firmware-aware shutdown
A 階段尾端 milestone、雙層防護避免使用者在 firmware 升級進行中關閉 app 造成 dongle brick。

Server 端 (3 改):
- main.go: SIGTERM/SIGINT goroutine 加 firmware-aware preamble
- server/internal/firmware/shutdown.go: 新 211 行(AwaitActiveTasksOrTimeout + 3 interfaces + shutdownBroadcastTask minimal struct + toBroadcastTasks helper)
- server/internal/firmware/shutdown_test.go: 新 384 行、8 tests

Wails 端 (3 新 + 2 改):
- visiona-local/main.go: OnBeforeClose 從 inline → app.OnBeforeClose
- visiona-local/app.go: App struct 加 firmwareCloseGuard
- visiona-local/firmware_close_guard.go: 新 244 行(CloseGuard + OnBeforeClose + ConfirmForceClose)
- visiona-local/firmware_close_guard_test.go: 新 280 行、8 tests
- visiona-local/query_firmware_active_tasks.go: 新 111 行(HTTP helper、fail-open、1s timeout)
- visiona-local/query_firmware_active_tasks_test.go: 新 250 行、7 tests

行為:
- Server SIGTERM 有 active task → broadcast `server:shutdown-pending` to "system" room → RequestShutdown + WaitForActiveTasks(220s) → 走原本 shutdownFn
- Wails OnBeforeClose 有 active task → emit Wails event `app:firmware-in-progress` + return true 擋住關閉
- ConfirmForceClose binding 給 frontend 第二層 FORCE 確認用、走 graceful 7+1s shutdown(不是 SIGKILL bypass、雙層防護)

Reviewer 兩輪審查:
- Round 1: 0 Critical / 1 Major / 3 Minor / 4 Suggestion
- 第 2 輪修法(3 sub-agent 平行):
  - Architect: TDD §8.6 改 event 名 `firmware:shutdown-rejected` → `server:shutdown-pending`、標題「拒絕」→「延遲」、補 payload schema 註明 tasks 不含 startTs
  - Design: control-panel.md §6a 改「SIGKILL bypass」→「graceful 7+1s 雙層防護」、補「為何不採 SIGKILL」5 點設計理由、§6a.11 IPC 規格對齊
  - Backend: MaxShutdownWait 180s → 220s(KL720 200s upgrade + 20s buffer)+ broadcast 過濾 startTs(shutdownBroadcastTask minimal struct + toBroadcastTasks helper)

測試:
- server: go test ./... -race 全綠(firmware 2.7s + api/ws/handlers)
- wails: go test ./... -race 全綠(visiona-local 11.2s、21 tests)
- 合計新增 23 unit tests race-clean、0 regression

下一步: M9-5 三平台實機驗證 + 順手修 MJ3(backend smoke test schema phase→stage / firmware:progress→firmware_progress)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 15:07:29 +08:00

47 lines
1.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"embed"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/options"
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
)
//go:embed all:frontend
var assets embed.FS
func main() {
app := NewApp()
err := wails.Run(&options.App{
Title: "visionA Local — Edge AI Workspace",
Width: 1280,
Height: 800,
MinWidth: 960,
MinHeight: 640,
AssetServer: &assetserver.Options{
Assets: assets,
},
OnStartup: app.startup,
OnShutdown: app.shutdown,
// M8-4 / R5-2關視窗 = 結束 server + 結束 app預設行為
// 不 hide-to-tray、不彈系統 native 對話框。
//
// M9-4.5TDD §8.6.2firmware-aware close guard。
// - 韌體升降版進行中 → app.OnBeforeClose 回 true、擋住關閉、emit
// `app:firmware-in-progress` event 給前端 Design §6a 攔截 modal
// - 使用者通過 §6a 第二層 FORCE 確認 → 前端呼叫 ConfirmForceClose
// binding → 設旗標 → 觸發 Wails Quit → OnBeforeClose 再被叫 → 放行
// - 沒韌體任務 → 直接 return false、走 OnShutdown → ctrl.Stop()
// 既有 7+1s graceful shutdown
OnBeforeClose: app.OnBeforeClose,
Bind: []interface{}{
app,
},
})
if err != nil {
panic(err)
}
}