mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-21 02:21:01 +00:00
feat(web): broadcast delta client stats above a snapshot threshold
Both 5s broadcasters (the local traffic poll and the node traffic sync) shipped the complete client_traffics table on every cycle while a browser was connected. At 500k clients that is a 1.7s full-table read plus an 86MB marshal per job per poll — and the hub drops any payload over 10MB and sends an invalidate the frontend ignores for these message types, so past ~55k clients all of it was pure waste and the UI got nothing. Installs at or below 5000 clients (clientStatsSnapshotMaxClients) keep the exact full-snapshot behavior — it exists because a pure delta feed left UI rows stale when nothing moved in a cycle (see GetAllClientTraffics) — and the payload now carries snapshot=true. Above the threshold the jobs send only this cycle's active rows (the xray poll's active emails, or the emails online on the synced nodes) with snapshot=false, and scope the last-online map to those rows; the initial full map still arrives over REST and the clients page refetches every 5s. GetActiveClientTraffics gains the overlayGlobalTraffic pass so delta rows carry the same cross-panel usage as snapshot rows. The node job also stops reading the full last-online map before the has-clients gate, which was a wasted full-table read on every tick with no dashboard open. Frontend: useClients keeps its live summary strictly snapshot-driven (snapshot=false payloads skip the allClientStats replace and the summary falls back to the server-computed one); the per-row page merge and the inbounds-page merges already handle deltas.
This commit is contained in:
@@ -928,14 +928,18 @@ func (s *InboundService) GetActiveClientTraffics(emails []string) ([]*xray.Clien
|
||||
}
|
||||
traffics = append(traffics, page...)
|
||||
}
|
||||
overlayGlobalTraffic(db, traffics)
|
||||
return traffics, nil
|
||||
}
|
||||
|
||||
// GetAllClientTraffics returns the full set of client_traffics rows so the
|
||||
// websocket broadcasters can ship a complete snapshot every cycle. The old
|
||||
// delta-only path (GetActiveClientTraffics on activeEmails) silently dropped
|
||||
// the per-client section whenever no client moved bytes in the cycle or a
|
||||
// node sync failed, leaving client rows in the UI stuck at stale numbers.
|
||||
// websocket broadcasters can ship a complete snapshot every cycle. A pure
|
||||
// delta path silently dropped the per-client section whenever no client moved
|
||||
// bytes in the cycle or a node sync failed, leaving client rows in the UI
|
||||
// stuck at stale numbers — so small installs broadcast this snapshot, and only
|
||||
// above the traffic job's snapshot threshold (where the marshaled snapshot
|
||||
// would exceed the hub's payload cap and be dropped wholesale) does the job
|
||||
// fall back to active-row deltas.
|
||||
func (s *InboundService) GetAllClientTraffics() ([]*xray.ClientTraffic, error) {
|
||||
db := database.GetDB()
|
||||
var traffics []*xray.ClientTraffic
|
||||
@@ -946,6 +950,13 @@ func (s *InboundService) GetAllClientTraffics() ([]*xray.ClientTraffic, error) {
|
||||
return traffics, nil
|
||||
}
|
||||
|
||||
func (s *InboundService) CountClientTraffics() (int64, error) {
|
||||
db := database.GetDB()
|
||||
var count int64
|
||||
err := db.Model(xray.ClientTraffic{}).Count(&count).Error
|
||||
return count, err
|
||||
}
|
||||
|
||||
type InboundTrafficSummary struct {
|
||||
Id int `json:"id"`
|
||||
Up int64 `json:"up"`
|
||||
|
||||
Reference in New Issue
Block a user