Add web dashboard OTA upload with live progress.

Share UART OTA logic between CLI and serve via POST /api/ota, WebSocket progress events, and a dashboard upload UI showing the running partition.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-19 00:45:54 +02:00
co-authored by Cursor
parent 59ca269407
commit 4bf43d8a5e
6 changed files with 463 additions and 198 deletions
+27 -8
View File
@@ -14,11 +14,12 @@ import (
)
type MasterView struct {
Version uint32 `json:"version"`
GitHash string `json:"git_hash"`
Deadzone uint32 `json:"deadzone,omitempty"`
OK bool `json:"ok"`
Error string `json:"error,omitempty"`
Version uint32 `json:"version"`
GitHash string `json:"git_hash"`
RunningPartition string `json:"running_partition,omitempty"`
Deadzone uint32 `json:"deadzone,omitempty"`
OK bool `json:"ok"`
Error string `json:"error,omitempty"`
}
type ClientView struct {
@@ -87,6 +88,23 @@ func (h *wsHub) unregister(c *websocket.Conn) {
h.mu.Unlock()
}
func (h *wsHub) broadcastRaw(v any) {
h.mu.RLock()
conns := make([]*websocket.Conn, 0, len(h.clients))
for c := range h.clients {
conns = append(conns, c)
}
h.mu.RUnlock()
data, err := json.Marshal(v)
if err != nil {
return
}
for _, c := range conns {
_ = c.WriteMessage(websocket.TextMessage, data)
}
}
func pollDashboard(link *managedSerial, portName string) DashboardState {
st := DashboardState{
UpdatedAt: time.Now().Format(time.RFC3339),
@@ -101,9 +119,10 @@ func pollDashboard(link *managedSerial, portName string) DashboardState {
st.UARTConnected = true
st.SerialOK = true
st.Master = MasterView{
Version: ver.GetVersion(),
GitHash: ver.GetGitHash(),
OK: true,
Version: ver.GetVersion(),
GitHash: ver.GetGitHash(),
RunningPartition: ver.GetRunningPartition(),
OK: true,
}
if dz, err := readDeadzone(link, 0); err == nil {
st.Master.Deadzone = dz