command_status.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. package libbox
  2. import (
  3. "encoding/binary"
  4. "net"
  5. "runtime"
  6. "time"
  7. "github.com/sagernet/sing-box/common/conntrack"
  8. "github.com/sagernet/sing-box/experimental/clashapi"
  9. E "github.com/sagernet/sing/common/exceptions"
  10. "github.com/sagernet/sing/common/memory"
  11. )
  12. type StatusMessage struct {
  13. Memory int64
  14. Goroutines int32
  15. ConnectionsIn int32
  16. ConnectionsOut int32
  17. TrafficAvailable bool
  18. Uplink int64
  19. Downlink int64
  20. UplinkTotal int64
  21. DownlinkTotal int64
  22. }
  23. func (s *CommandServer) readStatus() StatusMessage {
  24. var message StatusMessage
  25. message.Memory = int64(memory.Inuse())
  26. message.Goroutines = int32(runtime.NumGoroutine())
  27. message.ConnectionsOut = int32(conntrack.Count())
  28. if s.service != nil {
  29. if clashServer := s.service.instance.Router().ClashServer(); clashServer != nil {
  30. message.TrafficAvailable = true
  31. trafficManager := clashServer.(*clashapi.Server).TrafficManager()
  32. message.UplinkTotal, message.DownlinkTotal = trafficManager.Total()
  33. message.ConnectionsIn = int32(trafficManager.ConnectionsLen())
  34. }
  35. }
  36. return message
  37. }
  38. func (s *CommandServer) handleStatusConn(conn net.Conn) error {
  39. var interval int64
  40. err := binary.Read(conn, binary.BigEndian, &interval)
  41. if err != nil {
  42. return E.Cause(err, "read interval")
  43. }
  44. ticker := time.NewTicker(time.Duration(interval))
  45. defer ticker.Stop()
  46. ctx := connKeepAlive(conn)
  47. var (
  48. status StatusMessage
  49. uploadTotal int64
  50. downloadTotal int64
  51. )
  52. for {
  53. status = s.readStatus()
  54. upload := status.UplinkTotal - uploadTotal
  55. download := status.DownlinkTotal - downloadTotal
  56. uploadTotal = status.UplinkTotal
  57. downloadTotal = status.DownlinkTotal
  58. status.Uplink = upload
  59. status.Downlink = download
  60. err = binary.Write(conn, binary.BigEndian, status)
  61. if err != nil {
  62. return err
  63. }
  64. select {
  65. case <-ctx.Done():
  66. return ctx.Err()
  67. case <-ticker.C:
  68. }
  69. }
  70. }
  71. func (c *CommandClient) handleStatusConn(conn net.Conn) {
  72. for {
  73. var message StatusMessage
  74. err := binary.Read(conn, binary.BigEndian, &message)
  75. if err != nil {
  76. c.handler.Disconnected(err.Error())
  77. return
  78. }
  79. c.handler.WriteStatus(&message)
  80. }
  81. }