mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-05 12:44:22 +00:00
fix(online): refresh online-clients list even when no WS frontend is connected (#4515)
XrayTrafficJob and NodeTrafficSyncJob both gated the entire post-traffic-write block behind websocket.HasClients() to skip expensive broadcasts when no browser is open. The block included the RefreshOnlineClientsFromMap call that keeps the in-memory p.onlineClients list current. Several non-WS consumers read that same list: - Telegram bot (tgbot.go calls p.GetOnlineClients in 3 places) - REST GET /panel/api/onlines (returned to API callers) - Internal alerts that check whether a client is online When no browser was watching the dashboard, the list went stale and stayed empty, so the bot reported "nobody online" and the onlines API returned [] even when xray had active sessions. Move RefreshOnlineClientsFromMap above the HasClients guard so the in-memory list is always fresh. Only the actual BroadcastTraffic / BroadcastClientStats / BroadcastOutbounds calls (and the GetAllClientTraffics / GetInboundsTrafficSummary work that feeds them) remain gated by HasClients. Closes #4515
This commit is contained in:
parent
3df0ed2143
commit
934f9bc230
2 changed files with 8 additions and 28 deletions
|
|
@ -101,10 +101,6 @@ func (j *NodeTrafficSyncJob) Run() {
|
||||||
j.structural.set()
|
j.structural.set()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !websocket.HasClients() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
lastOnline, err := j.inboundService.GetClientsLastOnline()
|
lastOnline, err := j.inboundService.GetClientsLastOnline()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warning("node traffic sync: get last-online failed:", err)
|
logger.Warning("node traffic sync: get last-online failed:", err)
|
||||||
|
|
@ -115,6 +111,10 @@ func (j *NodeTrafficSyncJob) Run() {
|
||||||
|
|
||||||
j.inboundService.RefreshOnlineClientsFromMap(lastOnline)
|
j.inboundService.RefreshOnlineClientsFromMap(lastOnline)
|
||||||
|
|
||||||
|
if !websocket.HasClients() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
online := j.inboundService.GetOnlineClients()
|
online := j.inboundService.GetOnlineClients()
|
||||||
if online == nil {
|
if online == nil {
|
||||||
online = []string{}
|
online = []string{}
|
||||||
|
|
|
||||||
|
|
@ -65,18 +65,6 @@ func (j *XrayTrafficJob) Run() {
|
||||||
j.xrayService.SetToNeedRestart()
|
j.xrayService.SetToNeedRestart()
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no frontend client is connected, skip all WebSocket broadcasting
|
|
||||||
// routines — including the active-client DB query and JSON marshaling.
|
|
||||||
if !websocket.HasClients() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Online presence + traffic deltas — small payload, always fits in WS.
|
|
||||||
// Force non-nil slice/map so JSON marshalling produces [] / {} instead of
|
|
||||||
// `null` when everyone is offline. The frontend's traffic handler treats
|
|
||||||
// a missing/null onlineClients field as "no update", so without this the
|
|
||||||
// "everyone went offline" transition was silently dropped — stale online
|
|
||||||
// users lingered in the list and the online filter kept showing them.
|
|
||||||
lastOnlineMap, err := j.inboundService.GetClientsLastOnline()
|
lastOnlineMap, err := j.inboundService.GetClientsLastOnline()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warning("get clients last online failed:", err)
|
logger.Warning("get clients last online failed:", err)
|
||||||
|
|
@ -84,13 +72,12 @@ func (j *XrayTrafficJob) Run() {
|
||||||
if lastOnlineMap == nil {
|
if lastOnlineMap == nil {
|
||||||
lastOnlineMap = make(map[string]int64)
|
lastOnlineMap = make(map[string]int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine online clients from lastOnline timestamps with a 5-second
|
|
||||||
// grace period instead of just the current 5-second traffic poll. This
|
|
||||||
// prevents idle-but-connected clients from randomly disappearing from
|
|
||||||
// the UI between polling windows.
|
|
||||||
j.inboundService.RefreshOnlineClientsFromMap(lastOnlineMap)
|
j.inboundService.RefreshOnlineClientsFromMap(lastOnlineMap)
|
||||||
|
|
||||||
|
if !websocket.HasClients() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
onlineClients := j.inboundService.GetOnlineClients()
|
onlineClients := j.inboundService.GetOnlineClients()
|
||||||
if onlineClients == nil {
|
if onlineClients == nil {
|
||||||
onlineClients = []string{}
|
onlineClients = []string{}
|
||||||
|
|
@ -102,11 +89,6 @@ func (j *XrayTrafficJob) Run() {
|
||||||
"lastOnlineMap": lastOnlineMap,
|
"lastOnlineMap": lastOnlineMap,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Full snapshot every cycle: absolute per-client counters and inbound
|
|
||||||
// totals. Frontend overwrites both in place. The previous delta path
|
|
||||||
// (activeEmails -> GetActiveClientTraffics) silently omitted the
|
|
||||||
// clients array whenever nobody moved bytes in the cycle, leaving the
|
|
||||||
// client rows in the UI stuck at stale traffic/remained/all-time.
|
|
||||||
clientStatsPayload := map[string]any{}
|
clientStatsPayload := map[string]any{}
|
||||||
if stats, err := j.inboundService.GetAllClientTraffics(); err != nil {
|
if stats, err := j.inboundService.GetAllClientTraffics(); err != nil {
|
||||||
logger.Warning("get all client traffics for websocket failed:", err)
|
logger.Warning("get all client traffics for websocket failed:", err)
|
||||||
|
|
@ -122,8 +104,6 @@ func (j *XrayTrafficJob) Run() {
|
||||||
websocket.BroadcastClientStats(clientStatsPayload)
|
websocket.BroadcastClientStats(clientStatsPayload)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Outbounds list is small (one row per outbound, no per-client expansion)
|
|
||||||
// so the full snapshot still fits comfortably in WS.
|
|
||||||
if updatedOutbounds, err := j.outboundService.GetOutboundsTraffic(); err == nil && updatedOutbounds != nil {
|
if updatedOutbounds, err := j.outboundService.GetOutboundsTraffic(); err == nil && updatedOutbounds != nil {
|
||||||
websocket.BroadcastOutbounds(updatedOutbounds)
|
websocket.BroadcastOutbounds(updatedOutbounds)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue