sing-box/experimental/libbox/command_status.go

128 lines
2.9 KiB
Go
Raw Normal View History

2023-03-01 02:37:47 +00:00
package libbox
import (
2024-10-30 14:48:10 +00:00
std_bufio "bufio"
2023-03-01 02:37:47 +00:00
"encoding/binary"
"net"
"runtime"
"time"
2023-09-20 06:12:08 +00:00
"github.com/sagernet/sing-box/common/conntrack"
2023-07-16 06:08:45 +00:00
"github.com/sagernet/sing-box/experimental/clashapi"
2023-03-01 02:37:47 +00:00
E "github.com/sagernet/sing/common/exceptions"
2024-10-30 14:48:10 +00:00
F "github.com/sagernet/sing/common/format"
2023-09-20 06:12:08 +00:00
"github.com/sagernet/sing/common/memory"
2023-03-01 02:37:47 +00:00
)
2024-10-30 14:48:10 +00:00
const (
eventTypeEmpty byte = iota
eventTypeOpenURL
)
2023-03-01 02:37:47 +00:00
type StatusMessage struct {
2023-07-16 06:08:45 +00:00
Memory int64
Goroutines int32
ConnectionsIn int32
ConnectionsOut int32
TrafficAvailable bool
Uplink int64
Downlink int64
UplinkTotal int64
DownlinkTotal int64
2023-03-01 02:37:47 +00:00
}
2023-07-16 06:08:45 +00:00
func (s *CommandServer) readStatus() StatusMessage {
2023-03-01 02:37:47 +00:00
var message StatusMessage
2023-09-20 06:12:08 +00:00
message.Memory = int64(memory.Inuse())
2023-03-01 02:37:47 +00:00
message.Goroutines = int32(runtime.NumGoroutine())
2023-07-16 06:08:45 +00:00
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()
2024-06-11 13:16:33 +00:00
message.ConnectionsIn = int32(trafficManager.ConnectionsLen())
2023-07-16 06:08:45 +00:00
}
}
2023-03-01 02:37:47 +00:00
return message
}
func (s *CommandServer) handleStatusConn(conn net.Conn) error {
2024-10-30 14:48:10 +00:00
var isMainClient bool
err := binary.Read(conn, binary.BigEndian, &isMainClient)
if err != nil {
return E.Cause(err, "read is main client")
}
2023-03-01 02:37:47 +00:00
var interval int64
2024-10-30 14:48:10 +00:00
err = binary.Read(conn, binary.BigEndian, &interval)
2023-03-01 02:37:47 +00:00
if err != nil {
return E.Cause(err, "read interval")
}
ticker := time.NewTicker(time.Duration(interval))
defer ticker.Stop()
ctx := connKeepAlive(conn)
2024-10-30 14:48:10 +00:00
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()
}
2023-03-01 02:37:47 +00:00
}
2024-10-30 14:48:10 +00:00
} 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:
}
2023-03-01 02:37:47 +00:00
}
}
}
func (c *CommandClient) handleStatusConn(conn net.Conn) {
2024-10-30 14:48:10 +00:00
reader := std_bufio.NewReader(conn)
2023-03-01 02:37:47 +00:00
for {
2024-10-30 14:48:10 +00:00
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))
}
}
2023-03-01 02:37:47 +00:00
var message StatusMessage
2024-10-30 14:48:10 +00:00
err := binary.Read(reader, binary.BigEndian, &message)
2023-03-01 02:37:47 +00:00
if err != nil {
c.handler.Disconnected(err.Error())
return
}
c.handler.WriteStatus(&message)
}
}