mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-07 18:57:14 +00:00
1aa81428b8
The Speed column showed "--" for AmneziaWG (and MTProto, which has the identical gap) even while cumulative traffic totals were correct. XrayTrafficJob drives live speed by querying xray-core's own stats API and broadcasting the delta over websocket -- but AmneziaWG/MTProto never run inside xray-core's own runtime inbounds, so they're invisible to that API. Their own jobs already compute the same per-poll delta shape (that's what keeps cumulative totals correct) but never broadcast it. Reusing the existing "traffics"/"clientTraffics" broadcast would have two real bugs: the frontend's existing scope/replace logic would let each side clobber the other's speed on its next unrelated tick, and the websocket hub's per-message-type throttle is keyed only by message type, not caller -- since both sidecar jobs run on identical "@every 10s" grids registered milliseconds apart, one would silently lose almost every broadcast if both protocols were ever configured together. Fixed with a small unthrottled broadcast path (both sidecar jobs are already self-rate-limited by their own cron cadence) and protocol- namespaced wire keys, tracked in their own frontend state and merged into the existing inboundSpeed/clientSpeed only at read time -- so every existing consumer needs zero changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
44 lines
2.2 KiB
Go
44 lines
2.2 KiB
Go
package job
|
|
|
|
import (
|
|
"github.com/mhsanaei/3x-ui/v3/internal/web/websocket"
|
|
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
|
)
|
|
|
|
// sidecarTrafficPayload builds the websocket broadcast map for one poll of a
|
|
// sidecar protocol's traffic delta. "Sidecar" means a protocol that never
|
|
// runs inside xray-core's own inbounds -- AmneziaWG's kernel tunnel and
|
|
// MTProto's mtg process are the only two today (both explicitly skipped from
|
|
// claiming an xray-core tag in GenXrayInboundConfig). XrayTrafficJob's own 5s
|
|
// broadcast (xray_traffic_job.go) carries "traffics"/"clientTraffics" for
|
|
// xray-native inbounds/clients and never mentions sidecar tags, so reusing
|
|
// those keys would let each side's broadcast clobber the other's speed on
|
|
// its very next, unrelated tick. protocol namespaces the keys instead:
|
|
// "amneziawg" produces "amneziawgTraffics"/"amneziawgClientTraffics",
|
|
// "mtproto" produces "mtprotoTraffics"/"mtprotoClientTraffics" -- distinct
|
|
// pairs per protocol, so the frontend tracks each independently and never
|
|
// has to reconcile two protocols within one map (see useInbounds.ts /
|
|
// useClients.ts).
|
|
func sidecarTrafficPayload(protocol string, traffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) map[string]any {
|
|
return map[string]any{
|
|
protocol + "Traffics": traffics,
|
|
protocol + "ClientTraffics": clientTraffics,
|
|
}
|
|
}
|
|
|
|
// broadcastSidecarTraffic pushes this poll's live-speed snapshot for a
|
|
// sidecar protocol ("amneziawg" or "mtproto") over the websocket, so its
|
|
// inbound/client rows show a live Speed value the same way xray-native rows
|
|
// already do. Call this every tick -- even with empty slices -- so a peer
|
|
// that just went idle clears to no-speed on the frontend instead of sticking
|
|
// at its last nonzero reading; only the AddTraffic/RefreshLocalOnlineClients
|
|
// calls around it are conditioned on non-empty data, since cumulative-totals
|
|
// accounting doesn't need this signal. Uses BroadcastSidecarTraffic (not
|
|
// BroadcastTraffic) -- see its doc comment for why.
|
|
func broadcastSidecarTraffic(protocol string, traffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) {
|
|
if !websocket.HasClients() {
|
|
return
|
|
}
|
|
websocket.BroadcastSidecarTraffic(sidecarTrafficPayload(protocol, traffics, clientTraffics))
|
|
}
|