| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- // Package websocket provides WebSocket hub for real-time updates and notifications.
- package websocket
- import (
- "github.com/mhsanaei/3x-ui/v2/logger"
- "github.com/mhsanaei/3x-ui/v2/web/global"
- )
- // GetHub returns the global WebSocket hub instance.
- func GetHub() *Hub {
- webServer := global.GetWebServer()
- if webServer == nil {
- return nil
- }
- hub := webServer.GetWSHub()
- if hub == nil {
- return nil
- }
- wsHub, ok := hub.(*Hub)
- if !ok {
- logger.Warning("WebSocket hub type assertion failed")
- return nil
- }
- return wsHub
- }
- // HasClients returns true if any WebSocket client is connected.
- // Use this to skip expensive work (DB queries, serialization) when no browser is open.
- func HasClients() bool {
- hub := GetHub()
- return hub != nil && hub.GetClientCount() > 0
- }
- // BroadcastStatus broadcasts server status update to all connected clients.
- func BroadcastStatus(status any) {
- if hub := GetHub(); hub != nil {
- hub.Broadcast(MessageTypeStatus, status)
- }
- }
- // BroadcastTraffic broadcasts traffic statistics update to all connected clients.
- func BroadcastTraffic(traffic any) {
- if hub := GetHub(); hub != nil {
- hub.Broadcast(MessageTypeTraffic, traffic)
- }
- }
- // BroadcastClientStats broadcasts absolute per-client traffic counters for the
- // clients that had activity in the latest collection window. Use this instead
- // of re-broadcasting the full inbound list — it scales to 10k+ clients because
- // the payload only includes active rows (typically a fraction of total).
- func BroadcastClientStats(stats any) {
- if hub := GetHub(); hub != nil {
- hub.Broadcast(MessageTypeClientStats, stats)
- }
- }
- // BroadcastInbounds broadcasts inbounds list update to all connected clients.
- func BroadcastInbounds(inbounds any) {
- if hub := GetHub(); hub != nil {
- hub.Broadcast(MessageTypeInbounds, inbounds)
- }
- }
- // BroadcastOutbounds broadcasts outbounds list update to all connected clients.
- func BroadcastOutbounds(outbounds any) {
- if hub := GetHub(); hub != nil {
- hub.Broadcast(MessageTypeOutbounds, outbounds)
- }
- }
- // BroadcastNotification broadcasts a system notification to all connected clients.
- func BroadcastNotification(title, message, level string) {
- hub := GetHub()
- if hub == nil {
- return
- }
- hub.Broadcast(MessageTypeNotification, map[string]string{
- "title": title,
- "message": message,
- "level": level,
- })
- }
- // BroadcastXrayState broadcasts Xray state change to all connected clients.
- func BroadcastXrayState(state string, errorMsg string) {
- hub := GetHub()
- if hub == nil {
- return
- }
- hub.Broadcast(MessageTypeXrayState, map[string]string{
- "state": state,
- "errorMsg": errorMsg,
- })
- }
- // BroadcastInvalidate sends a lightweight signal telling clients to re-fetch
- // the named data type via REST. Use this when the caller already knows the
- // payload is too large to push directly (e.g., 10k+ clients) to skip the
- // JSON-marshal cost on the hot path.
- func BroadcastInvalidate(dataType MessageType) {
- if hub := GetHub(); hub != nil {
- hub.broadcastInvalidate(dataType)
- }
- }
|