123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- package libbox
- import (
- std_bufio "bufio"
- "encoding/binary"
- "net"
- "runtime"
- "time"
- "github.com/sagernet/sing-box/common/conntrack"
- "github.com/sagernet/sing-box/experimental/clashapi"
- E "github.com/sagernet/sing/common/exceptions"
- F "github.com/sagernet/sing/common/format"
- "github.com/sagernet/sing/common/memory"
- )
- const (
- eventTypeEmpty byte = iota
- eventTypeOpenURL
- )
- type StatusMessage struct {
- Memory int64
- Goroutines int32
- ConnectionsIn int32
- ConnectionsOut int32
- TrafficAvailable bool
- Uplink int64
- Downlink int64
- UplinkTotal int64
- DownlinkTotal int64
- }
- func (s *CommandServer) readStatus() StatusMessage {
- var message StatusMessage
- message.Memory = int64(memory.Inuse())
- message.Goroutines = int32(runtime.NumGoroutine())
- message.ConnectionsOut = int32(conntrack.Count())
- if s.service != nil {
- if clashServer := s.service.instance.Router().ClashServer(); clashServer != nil {
- message.TrafficAvailable = true
- trafficManager := clashServer.(*clashapi.Server).TrafficManager()
- message.Uplink, message.Downlink = trafficManager.Now()
- message.UplinkTotal, message.DownlinkTotal = trafficManager.Total()
- message.ConnectionsIn = int32(trafficManager.ConnectionsLen())
- }
- }
- return message
- }
- func (s *CommandServer) handleStatusConn(conn net.Conn) error {
- var isMainClient bool
- err := binary.Read(conn, binary.BigEndian, &isMainClient)
- if err != nil {
- return E.Cause(err, "read is main client")
- }
- var interval int64
- err = binary.Read(conn, binary.BigEndian, &interval)
- if err != nil {
- return E.Cause(err, "read interval")
- }
- ticker := time.NewTicker(time.Duration(interval))
- defer ticker.Stop()
- ctx := connKeepAlive(conn)
- writer := std_bufio.NewWriter(conn)
- if isMainClient {
- for {
- writer.WriteByte(eventTypeEmpty)
- err = binary.Write(conn, binary.BigEndian, s.readStatus())
- if err != nil {
- return err
- }
- writer.Flush()
- select {
- case <-ctx.Done():
- return ctx.Err()
- case <-ticker.C:
- case event := <-s.events:
- event.writeTo(writer)
- writer.Flush()
- }
- }
- } else {
- for {
- err = binary.Write(conn, binary.BigEndian, s.readStatus())
- if err != nil {
- return err
- }
- writer.Flush()
- select {
- case <-ctx.Done():
- return ctx.Err()
- case <-ticker.C:
- }
- }
- }
- }
- func (c *CommandClient) handleStatusConn(conn net.Conn) {
- reader := std_bufio.NewReader(conn)
- for {
- if c.options.IsMainClient {
- rawEvent, err := readEvent(reader)
- if err != nil {
- c.handler.Disconnected(err.Error())
- return
- }
- switch event := rawEvent.(type) {
- case *eventOpenURL:
- c.handler.OpenURL(event.URL)
- continue
- case nil:
- default:
- panic(F.ToString("unexpected event type: ", event))
- }
- }
- var message StatusMessage
- err := binary.Read(reader, binary.BigEndian, &message)
- if err != nil {
- c.handler.Disconnected(err.Error())
- return
- }
- c.handler.WriteStatus(&message)
- }
- }
|