1
0

command_status.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package libbox
  2. import (
  3. std_bufio "bufio"
  4. "encoding/binary"
  5. "net"
  6. "runtime"
  7. "time"
  8. "github.com/sagernet/sing-box/common/conntrack"
  9. "github.com/sagernet/sing-box/experimental/clashapi"
  10. E "github.com/sagernet/sing/common/exceptions"
  11. F "github.com/sagernet/sing/common/format"
  12. "github.com/sagernet/sing/common/memory"
  13. )
  14. const (
  15. eventTypeEmpty byte = iota
  16. eventTypeOpenURL
  17. )
  18. type StatusMessage struct {
  19. Memory int64
  20. Goroutines int32
  21. ConnectionsIn int32
  22. ConnectionsOut int32
  23. TrafficAvailable bool
  24. Uplink int64
  25. Downlink int64
  26. UplinkTotal int64
  27. DownlinkTotal int64
  28. }
  29. func (s *CommandServer) readStatus() StatusMessage {
  30. var message StatusMessage
  31. message.Memory = int64(memory.Inuse())
  32. message.Goroutines = int32(runtime.NumGoroutine())
  33. message.ConnectionsOut = int32(conntrack.Count())
  34. if s.service != nil {
  35. if clashServer := s.service.instance.Router().ClashServer(); clashServer != nil {
  36. message.TrafficAvailable = true
  37. trafficManager := clashServer.(*clashapi.Server).TrafficManager()
  38. message.Uplink, message.Downlink = trafficManager.Now()
  39. message.UplinkTotal, message.DownlinkTotal = trafficManager.Total()
  40. message.ConnectionsIn = int32(trafficManager.ConnectionsLen())
  41. }
  42. }
  43. return message
  44. }
  45. func (s *CommandServer) handleStatusConn(conn net.Conn) error {
  46. var isMainClient bool
  47. err := binary.Read(conn, binary.BigEndian, &isMainClient)
  48. if err != nil {
  49. return E.Cause(err, "read is main client")
  50. }
  51. var interval int64
  52. err = binary.Read(conn, binary.BigEndian, &interval)
  53. if err != nil {
  54. return E.Cause(err, "read interval")
  55. }
  56. ticker := time.NewTicker(time.Duration(interval))
  57. defer ticker.Stop()
  58. ctx := connKeepAlive(conn)
  59. writer := std_bufio.NewWriter(conn)
  60. if isMainClient {
  61. for {
  62. writer.WriteByte(eventTypeEmpty)
  63. err = binary.Write(conn, binary.BigEndian, s.readStatus())
  64. if err != nil {
  65. return err
  66. }
  67. writer.Flush()
  68. select {
  69. case <-ctx.Done():
  70. return ctx.Err()
  71. case <-ticker.C:
  72. case event := <-s.events:
  73. event.writeTo(writer)
  74. writer.Flush()
  75. }
  76. }
  77. } else {
  78. for {
  79. err = binary.Write(conn, binary.BigEndian, s.readStatus())
  80. if err != nil {
  81. return err
  82. }
  83. writer.Flush()
  84. select {
  85. case <-ctx.Done():
  86. return ctx.Err()
  87. case <-ticker.C:
  88. }
  89. }
  90. }
  91. }
  92. func (c *CommandClient) handleStatusConn(conn net.Conn) {
  93. reader := std_bufio.NewReader(conn)
  94. for {
  95. if c.options.IsMainClient {
  96. rawEvent, err := readEvent(reader)
  97. if err != nil {
  98. c.handler.Disconnected(err.Error())
  99. return
  100. }
  101. switch event := rawEvent.(type) {
  102. case *eventOpenURL:
  103. c.handler.OpenURL(event.URL)
  104. continue
  105. case nil:
  106. default:
  107. panic(F.ToString("unexpected event type: ", event))
  108. }
  109. }
  110. var message StatusMessage
  111. err := binary.Read(reader, binary.BigEndian, &message)
  112. if err != nil {
  113. c.handler.Disconnected(err.Error())
  114. return
  115. }
  116. c.handler.WriteStatus(&message)
  117. }
  118. }