github.com/sagernet/sing-box@v1.9.0-rc.20/experimental/libbox/command_status.go (about)

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