1
0

notifier.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // Package websocket provides WebSocket hub for real-time updates and notifications.
  2. package websocket
  3. import (
  4. "github.com/mhsanaei/3x-ui/v2/logger"
  5. "github.com/mhsanaei/3x-ui/v2/web/global"
  6. )
  7. // GetHub returns the global WebSocket hub instance.
  8. func GetHub() *Hub {
  9. webServer := global.GetWebServer()
  10. if webServer == nil {
  11. return nil
  12. }
  13. hub := webServer.GetWSHub()
  14. if hub == nil {
  15. return nil
  16. }
  17. wsHub, ok := hub.(*Hub)
  18. if !ok {
  19. logger.Warning("WebSocket hub type assertion failed")
  20. return nil
  21. }
  22. return wsHub
  23. }
  24. // HasClients returns true if any WebSocket client is connected.
  25. // Use this to skip expensive work (DB queries, serialization) when no browser is open.
  26. func HasClients() bool {
  27. hub := GetHub()
  28. return hub != nil && hub.GetClientCount() > 0
  29. }
  30. // BroadcastStatus broadcasts server status update to all connected clients.
  31. func BroadcastStatus(status any) {
  32. if hub := GetHub(); hub != nil {
  33. hub.Broadcast(MessageTypeStatus, status)
  34. }
  35. }
  36. // BroadcastTraffic broadcasts traffic statistics update to all connected clients.
  37. func BroadcastTraffic(traffic any) {
  38. if hub := GetHub(); hub != nil {
  39. hub.Broadcast(MessageTypeTraffic, traffic)
  40. }
  41. }
  42. // BroadcastClientStats broadcasts absolute per-client traffic counters for the
  43. // clients that had activity in the latest collection window. Use this instead
  44. // of re-broadcasting the full inbound list — it scales to 10k+ clients because
  45. // the payload only includes active rows (typically a fraction of total).
  46. func BroadcastClientStats(stats any) {
  47. if hub := GetHub(); hub != nil {
  48. hub.Broadcast(MessageTypeClientStats, stats)
  49. }
  50. }
  51. // BroadcastInbounds broadcasts inbounds list update to all connected clients.
  52. func BroadcastInbounds(inbounds any) {
  53. if hub := GetHub(); hub != nil {
  54. hub.Broadcast(MessageTypeInbounds, inbounds)
  55. }
  56. }
  57. // BroadcastNodes broadcasts the fresh node list to all connected clients.
  58. // Pushed by NodeHeartbeatJob at the end of each 10s tick so the Nodes page
  59. // reflects status / latency / cpu / mem updates without polling.
  60. func BroadcastNodes(nodes any) {
  61. if hub := GetHub(); hub != nil {
  62. hub.Broadcast(MessageTypeNodes, nodes)
  63. }
  64. }
  65. // BroadcastOutbounds broadcasts outbounds list update to all connected clients.
  66. func BroadcastOutbounds(outbounds any) {
  67. if hub := GetHub(); hub != nil {
  68. hub.Broadcast(MessageTypeOutbounds, outbounds)
  69. }
  70. }
  71. // BroadcastNotification broadcasts a system notification to all connected clients.
  72. func BroadcastNotification(title, message, level string) {
  73. hub := GetHub()
  74. if hub == nil {
  75. return
  76. }
  77. hub.Broadcast(MessageTypeNotification, map[string]string{
  78. "title": title,
  79. "message": message,
  80. "level": level,
  81. })
  82. }
  83. // BroadcastXrayState broadcasts Xray state change to all connected clients.
  84. func BroadcastXrayState(state string, errorMsg string) {
  85. hub := GetHub()
  86. if hub == nil {
  87. return
  88. }
  89. hub.Broadcast(MessageTypeXrayState, map[string]string{
  90. "state": state,
  91. "errorMsg": errorMsg,
  92. })
  93. }
  94. // BroadcastInvalidate sends a lightweight signal telling clients to re-fetch
  95. // the named data type via REST. Use this when the caller already knows the
  96. // payload is too large to push directly (e.g., 10k+ clients) to skip the
  97. // JSON-marshal cost on the hot path.
  98. func BroadcastInvalidate(dataType MessageType) {
  99. if hub := GetHub(); hub != nil {
  100. hub.broadcastInvalidate(dataType)
  101. }
  102. }