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()
|
||||
}
|
||||
|
||||
if !websocket.HasClients() {
|
||||
return
|
||||
}
|
||||
|
||||
lastOnline, err := j.inboundService.GetClientsLastOnline()
|
||||
if err != nil {
|
||||
logger.Warning("node traffic sync: get last-online failed:", err)
|
||||
|
|
@ -115,6 +111,10 @@ func (j *NodeTrafficSyncJob) Run() {
|
|||
|
||||
j.inboundService.RefreshOnlineClientsFromMap(lastOnline)
|
||||
|
||||
if !websocket.HasClients() {
|
||||
return
|
||||
}
|
||||
|
||||
online := j.inboundService.GetOnlineClients()
|
||||
if online == nil {
|
||||
online = []string{}
|
||||
|
|
|
|||
|
|
@ -65,18 +65,6 @@ func (j *XrayTrafficJob) Run() {
|
|||
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()
|
||||
if err != nil {
|
||||
logger.Warning("get clients last online failed:", err)
|
||||
|
|
@ -84,13 +72,12 @@ func (j *XrayTrafficJob) Run() {
|
|||
if lastOnlineMap == nil {
|
||||
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)
|
||||
|
||||
if !websocket.HasClients() {
|
||||
return
|
||||
}
|
||||
|
||||
onlineClients := j.inboundService.GetOnlineClients()
|
||||
if onlineClients == nil {
|
||||
onlineClients = []string{}
|
||||
|
|
@ -102,11 +89,6 @@ func (j *XrayTrafficJob) Run() {
|
|||
"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{}
|
||||
if stats, err := j.inboundService.GetAllClientTraffics(); err != nil {
|
||||
logger.Warning("get all client traffics for websocket failed:", err)
|
||||
|
|
@ -122,8 +104,6 @@ func (j *XrayTrafficJob) Run() {
|
|||
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 {
|
||||
websocket.BroadcastOutbounds(updatedOutbounds)
|
||||
} else if err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue