mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-12-27 17:15:39 +08:00
128 lines
2.9 KiB
Go
128 lines
2.9 KiB
Go
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(writer, 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(writer, 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)
|
|
}
|
|
}
|