feat(nodes): show live speed for node-hosted inbounds

Inbound speed is computed on the dashboard from a 'traffics' delta feed, which only the local Xray poll produced — so node-hosted inbounds showed no speed. The node sync now diffs successive per-inbound cumulative totals (it polls @5s, same as the local poll) and broadcasts the byte deltas as a separate 'nodeTraffics' field, keyed by the central tag the dashboard already matches. The frontend applies 'traffics' to local inbounds and 'nodeTraffics' to node inbounds within their own scope, so the two 5s polls don't clobber each other and idle inbounds still clear. Deltas clamp to 0 on a reset; a node that fails to sync keeps a stale total so its delta is 0 (no phantom speed).
This commit is contained in:
MHSanaei
2026-06-22 18:03:10 +02:00
parent f96e877370
commit 2ce5891f5f
3 changed files with 101 additions and 17 deletions
+23
View File
@@ -201,6 +201,29 @@ func (s *InboundService) SetRemoteTraffic(nodeID int, snap *runtime.TrafficSnaps
return structuralChange, err
}
// GetNodeInboundTrafficTotals returns the current cumulative up/down for every
// node-hosted inbound, keyed by tag. The node sync diffs successive snapshots of
// this to derive per-inbound speed for the dashboard — node inbounds have no
// local Xray poll to produce live deltas the way local inbounds do.
func (s *InboundService) GetNodeInboundTrafficTotals() (map[string][2]int64, error) {
var rows []struct {
Tag string
Up int64
Down int64
}
if err := database.GetDB().Table("inbounds").
Select("tag, up, down").
Where("node_id IS NOT NULL").
Scan(&rows).Error; err != nil {
return nil, err
}
out := make(map[string][2]int64, len(rows))
for _, r := range rows {
out[r.Tag] = [2]int64{r.Up, r.Down}
}
return out, nil
}
func (s *InboundService) setRemoteTrafficLocked(nodeID int, snap *runtime.TrafficSnapshot, dirty bool) (bool, error) {
if snap == nil || nodeID <= 0 {
return false, nil