Feature: Offline device history with delete and remote uninstall
Persist every device that has ever logged in to the Go server in a small JSON store (devices.json, overridable with YAMA_DEVICES_FILE and capped by YAMA_DEVICES_MAX, default 1000 newest). The store follows the users.json convention: atomic temp-file write with fsync and rename, a 500 ms debounce for bursts of reconnects, first_seen preserved across logins, and pruning that evicts offline records before devices that are still connected. Devices connected at shutdown are stamped offline before the final flush so last_seen stays accurate across restarts. The server advertises an offlineDevices capability and device_list now appends historical devices that are not online, marked with online:false and last_seen. The web UI shows an Offline checkbox after Total/Showing (state kept in localStorage), renders offline cards dimmed and dashed, and always lists them in the screen-wall sidebar. Older servers without the capability keep the online-only list. Grid and List cards gain a delete button after the terminal button, admin only, behind a confirmation dialog. Deleting an offline device removes its history record; deleting an online device first sends the single-byte TOKEN_UNINSTALL command (matching the MFC OnOnlineUninstall flow) and then removes the record too, so the device does not come back as a dead offline entry. The agent's own disconnect then runs the existing cleanup path: screen and terminal sub-connections are closed, the hub entry is removed, and browsers receive device_offline to release their watch sets, wall sessions, and stream references. Wall mode exposes no delete action. Tests cover history persistence/pruning/recovery, offline ordering, the device_list merge, and all three delete outcomes (offline removal, online uninstall with a single 0x3F byte, and viewer rejection). Co-Authored-By: deepseek-flash
This commit is contained in:
1 parent
1922f87dd2
commit
b1ddec1b8a
12 files changed
+1212
-27
No files matched your search
@@ -165,6 +165,9 @@ type DeviceInfo struct {
|
||||
ActiveWindow string `json:"activeWindow,omitempty"`
|
||||
ConnectedAt int64 `json:"connected_at"`
|
||||
Online bool `json:"online"`
|
||||
// LastSeen is unix seconds of the last login/disconnect. Only populated
|
||||
// for offline entries in device_list; online devices leave it zero.
|
||||
LastSeen int64 `json:"last_seen,omitempty"`
|
||||
}
|
||||
|
||||
// EventHandler receives notifications about device lifecycle, per-tick live
|
||||
@@ -240,6 +243,17 @@ func (h *Hub) SetSender(fn SendFunc) {
|
||||
h.sender = fn
|
||||
}
|
||||
|
||||
// IsOnline reports whether id is currently registered with a live main
|
||||
// connection. Callers that need to choose between an online-only command and
|
||||
// an offline bookkeeping action should check this first; SendToDevice can
|
||||
// still turn into ErrDeviceOffline if the device drops in between.
|
||||
func (h *Hub) IsOnline(id string) bool {
|
||||
h.mu.RLock()
|
||||
d, ok := h.devices[id]
|
||||
h.mu.RUnlock()
|
||||
return ok && d.conn != nil
|
||||
}
|
||||
|
||||
// SendToDevice forwards an already-formed command payload to the device's
|
||||
// main connection. data should be the raw command bytes (the sender takes
|
||||
// care of framing / compression at the protocol layer).
|
||||
|
||||
Reference in new issue
Block a user