Feature(Go): Mouse/keyboard input + user management with users.json (Phase 5 + 7)

This commit is contained in:
yuanyuanxiang
2026-05-18 13:53:44 +02:00
parent f013512c06
commit 98a914f963
7 changed files with 764 additions and 21 deletions

View File

@@ -48,6 +48,7 @@ type Device struct {
Location string // client-reported geo string (reserved field 10)
PeerIP string // network-level remote address as seen by the server
PublicIP string // client-reported public IP (reserved field 11)
Resolution string // client-formatted screen geometry "N:W*H" (reserved field 15)
ConnectedAt time.Time
// Live fields refreshed on every heartbeat. Protected by hub.mu.
@@ -115,6 +116,18 @@ func (h *Hub) MainConn(id string) *connection.Context {
return nil
}
// Capability returns the device's reported capability hex string
// (LOGIN_INFOR.moduleVersion tail). Empty for unknown devices — callers
// should treat that as "no caps" (legacy Windows GBK default).
func (h *Hub) Capability(id string) string {
h.mu.RLock()
defer h.mu.RUnlock()
if d, ok := h.devices[id]; ok {
return d.Capability
}
return ""
}
// DeviceInfo is the JSON-safe projection of Device for the /api/devices
// endpoint and the WS device_list message. Field names match what the
// existing browser front-end expects.
@@ -131,6 +144,7 @@ type DeviceInfo struct {
Location string `json:"location,omitempty"`
IP string `json:"ip"` // client-reported public IP (matches C++ key)
PeerIP string `json:"peer_ip,omitempty"`
Screen string `json:"screen,omitempty"` // "N:W*H" — matches C++ DeviceInfo.screen key
RTT int `json:"rtt"`
ActiveWindow string `json:"activeWindow,omitempty"`
ConnectedAt int64 `json:"connected_at"`
@@ -205,6 +219,30 @@ func (h *Hub) SendToDevice(id string, data []byte) error {
return h.sender(d.conn, data)
}
// SendToScreen routes a payload to the device's currently-bound screen
// sub-connection. Input events (COMMAND_SCREEN_CONTROL) MUST go through the
// screen sub-conn rather than the main conn — the C++ client only dispatches
// these commands from CScreenManager::OnReceive, which reads exclusively from
// the sub-conn (see client/ScreenManager.cpp:1065). Returns ErrDeviceOffline
// when the device is unknown OR has no active screen session, so callers can
// quietly drop input from browsers that haven't called connect yet.
func (h *Hub) SendToScreen(id string, data []byte) error {
h.mu.RLock()
d, ok := h.devices[id]
var sc *connection.Context
if ok {
sc = d.screenConn
}
h.mu.RUnlock()
if !ok || sc == nil {
return ErrDeviceOffline
}
if h.sender == nil {
return ErrNoSender
}
return h.sender(sc, data)
}
// BindScreenConn associates a freshly-arrived sub-connection (the one that
// just sent TOKEN_BITMAPINFO) with the device identified by clientID.
// Returns false if the device is not registered — callers should drop the
@@ -350,6 +388,7 @@ func deviceToInfo(d *Device) DeviceInfo {
Location: d.Location,
IP: d.PublicIP,
PeerIP: d.PeerIP,
Screen: d.Resolution,
RTT: d.RTT,
ActiveWindow: d.ActiveWindow,
ConnectedAt: d.ConnectedAt.Unix(),