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>
47 lines
1.3 KiB
Go
47 lines
1.3 KiB
Go
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.5(TDD §8.6.2):firmware-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)
|
||
}
|
||
}
|