sing-box/experimental/libbox/command_log.go

147 lines
3 KiB
Go
Raw Normal View History

2023-03-01 02:37:47 +00:00
package libbox
import (
2024-06-18 09:49:06 +00:00
"bufio"
2023-03-01 02:37:47 +00:00
"context"
"io"
"net"
2024-06-18 09:49:06 +00:00
"time"
"github.com/sagernet/sing/common/binary"
E "github.com/sagernet/sing/common/exceptions"
2023-03-01 02:37:47 +00:00
)
func (s *CommandServer) WriteMessage(message string) {
s.subscriber.Emit(message)
s.access.Lock()
s.savedLines.PushBack(message)
2023-07-02 08:45:30 +00:00
if s.savedLines.Len() > s.maxLines {
2023-03-01 02:37:47 +00:00
s.savedLines.Remove(s.savedLines.Front())
}
s.access.Unlock()
}
2024-06-18 09:49:06 +00:00
func writeLog(writer *bufio.Writer, messages []string) error {
2023-10-02 14:27:48 +00:00
err := binary.Write(writer, binary.BigEndian, uint8(0))
if err != nil {
return err
}
2024-06-18 09:49:06 +00:00
err = binary.WriteData(writer, binary.BigEndian, messages)
2023-03-01 02:37:47 +00:00
if err != nil {
return err
}
2024-06-18 09:49:06 +00:00
return writer.Flush()
2023-03-01 02:37:47 +00:00
}
2024-06-18 09:49:06 +00:00
func writeClearLog(writer *bufio.Writer) error {
err := binary.Write(writer, binary.BigEndian, uint8(1))
if err != nil {
return err
}
return writer.Flush()
2023-10-02 14:27:48 +00:00
}
2023-03-01 02:37:47 +00:00
func (s *CommandServer) handleLogConn(conn net.Conn) error {
2024-06-18 09:49:06 +00:00
var (
interval int64
timer *time.Timer
)
err := binary.Read(conn, binary.BigEndian, &interval)
if err != nil {
return E.Cause(err, "read interval")
}
timer = time.NewTimer(time.Duration(interval))
if !timer.Stop() {
<-timer.C
}
2023-03-01 02:37:47 +00:00
var savedLines []string
s.access.Lock()
savedLines = make([]string, 0, s.savedLines.Len())
for element := s.savedLines.Front(); element != nil; element = element.Next() {
savedLines = append(savedLines, element.Value)
}
s.access.Unlock()
subscription, done, err := s.observer.Subscribe()
if err != nil {
return err
}
defer s.observer.UnSubscribe(subscription)
2024-06-18 09:49:06 +00:00
writer := bufio.NewWriter(conn)
if len(savedLines) > 0 {
err = writeLog(writer, savedLines)
2023-03-01 02:37:47 +00:00
if err != nil {
return err
}
}
ctx := connKeepAlive(conn)
2024-06-18 09:49:06 +00:00
var logLines []string
2023-03-01 02:37:47 +00:00
for {
select {
case <-ctx.Done():
2023-04-10 00:48:58 +00:00
return ctx.Err()
2023-10-02 14:27:48 +00:00
case <-s.logReset:
2024-06-18 09:49:06 +00:00
err = writeClearLog(writer)
2023-10-02 14:27:48 +00:00
if err != nil {
return err
}
2023-03-01 02:37:47 +00:00
case <-done:
return nil
2024-06-18 09:49:06 +00:00
case logLine := <-subscription:
logLines = logLines[:0]
logLines = append(logLines, logLine)
timer.Reset(time.Duration(interval))
loopLogs:
for {
select {
case logLine = <-subscription:
logLines = append(logLines, logLine)
case <-timer.C:
break loopLogs
}
}
err = writeLog(writer, logLines)
if err != nil {
return err
}
2023-03-01 02:37:47 +00:00
}
}
}
func (c *CommandClient) handleLogConn(conn net.Conn) {
2024-06-18 09:49:06 +00:00
reader := bufio.NewReader(conn)
2023-03-01 02:37:47 +00:00
for {
2023-10-02 14:27:48 +00:00
var messageType uint8
2024-06-18 09:49:06 +00:00
err := binary.Read(reader, binary.BigEndian, &messageType)
2023-03-01 02:37:47 +00:00
if err != nil {
c.handler.Disconnected(err.Error())
return
}
2024-06-18 09:49:06 +00:00
var messages []string
2023-10-02 14:27:48 +00:00
switch messageType {
case 0:
2024-06-18 09:49:06 +00:00
err = binary.ReadData(reader, binary.BigEndian, &messages)
2023-10-02 14:27:48 +00:00
if err != nil {
c.handler.Disconnected(err.Error())
return
}
2024-06-18 09:49:06 +00:00
c.handler.WriteLogs(newIterator(messages))
2023-10-02 14:27:48 +00:00
case 1:
2024-06-18 09:49:06 +00:00
c.handler.ClearLogs()
2023-10-02 14:27:48 +00:00
}
2023-03-01 02:37:47 +00:00
}
}
func connKeepAlive(reader io.Reader) context.Context {
ctx, cancel := context.WithCancelCause(context.Background())
go func() {
for {
2024-06-18 09:49:06 +00:00
_, err := reader.Read(make([]byte, 1))
2023-03-01 02:37:47 +00:00
if err != nil {
cancel(err)
return
}
}
}()
return ctx
}