From 55c34e3fb0d544c38717efd6d0afdaf4a1ee733d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 3 Sep 2023 21:06:21 +0800 Subject: [PATCH] platform: Improve client --- experimental/libbox/command.go | 2 + experimental/libbox/command_client.go | 18 ++++- experimental/libbox/command_server.go | 6 ++ experimental/libbox/command_system_proxy.go | 82 +++++++++++++++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 experimental/libbox/command_system_proxy.go diff --git a/experimental/libbox/command.go b/experimental/libbox/command.go index 60da6ab2..0a757076 100644 --- a/experimental/libbox/command.go +++ b/experimental/libbox/command.go @@ -11,4 +11,6 @@ const ( CommandGroupExpand CommandClashMode CommandSetClashMode + CommandGetSystemProxyStatus + CommandSetSystemProxyEnabled ) diff --git a/experimental/libbox/command_client.go b/experimental/libbox/command_client.go index e74c606b..9701d949 100644 --- a/experimental/libbox/command_client.go +++ b/experimental/libbox/command_client.go @@ -5,6 +5,7 @@ import ( "net" "os" "path/filepath" + "time" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" @@ -53,9 +54,24 @@ func (c *CommandClient) directConnect() (net.Conn, error) { } } +func (c *CommandClient) directConnectWithRetry() (net.Conn, error) { + var ( + conn net.Conn + err error + ) + for i := 0; i < 10; i++ { + conn, err = c.directConnect() + if err == nil { + return conn, nil + } + time.Sleep(time.Duration(100+i*50) * time.Millisecond) + } + return nil, err +} + func (c *CommandClient) Connect() error { common.Close(c.conn) - conn, err := c.directConnect() + conn, err := c.directConnectWithRetry() if err != nil { return err } diff --git a/experimental/libbox/command_server.go b/experimental/libbox/command_server.go index 5e7214fd..19f98870 100644 --- a/experimental/libbox/command_server.go +++ b/experimental/libbox/command_server.go @@ -35,6 +35,8 @@ type CommandServer struct { type CommandServerHandler interface { ServiceReload() error + GetSystemProxyStatus() *SystemProxyStatus + SetSystemProxyEnabled(isEnabled bool) error } func NewCommandServer(handler CommandServerHandler, maxLines int32) *CommandServer { @@ -159,6 +161,10 @@ func (s *CommandServer) handleConnection(conn net.Conn) error { return s.handleModeConn(conn) case CommandSetClashMode: return s.handleSetClashMode(conn) + case CommandGetSystemProxyStatus: + return s.handleGetSystemProxyStatus(conn) + case CommandSetSystemProxyEnabled: + return s.handleSetSystemProxyEnabled(conn) default: return E.New("unknown command: ", command) } diff --git a/experimental/libbox/command_system_proxy.go b/experimental/libbox/command_system_proxy.go new file mode 100644 index 00000000..d72abf7b --- /dev/null +++ b/experimental/libbox/command_system_proxy.go @@ -0,0 +1,82 @@ +package libbox + +import ( + "encoding/binary" + "net" +) + +type SystemProxyStatus struct { + Available bool + Enabled bool +} + +func (c *CommandClient) GetSystemProxyStatus() (*SystemProxyStatus, error) { + conn, err := c.directConnectWithRetry() + if err != nil { + return nil, err + } + defer conn.Close() + err = binary.Write(conn, binary.BigEndian, uint8(CommandGetSystemProxyStatus)) + if err != nil { + return nil, err + } + var status SystemProxyStatus + err = binary.Read(conn, binary.BigEndian, &status.Available) + if err != nil { + return nil, err + } + if status.Available { + err = binary.Read(conn, binary.BigEndian, &status.Enabled) + if err != nil { + return nil, err + } + } + return &status, nil +} + +func (s *CommandServer) handleGetSystemProxyStatus(conn net.Conn) error { + defer conn.Close() + status := s.handler.GetSystemProxyStatus() + err := binary.Write(conn, binary.BigEndian, status.Available) + if err != nil { + return err + } + if status.Available { + err = binary.Write(conn, binary.BigEndian, status.Enabled) + if err != nil { + return err + } + } + return nil +} + +func (c *CommandClient) SetSystemProxyEnabled(isEnabled bool) error { + conn, err := c.directConnect() + if err != nil { + return err + } + defer conn.Close() + err = binary.Write(conn, binary.BigEndian, uint8(CommandSetSystemProxyEnabled)) + if err != nil { + return err + } + err = binary.Write(conn, binary.BigEndian, isEnabled) + if err != nil { + return err + } + return readError(conn) +} + +func (s *CommandServer) handleSetSystemProxyEnabled(conn net.Conn) error { + defer conn.Close() + var isEnabled bool + err := binary.Read(conn, binary.BigEndian, &isEnabled) + if err != nil { + return err + } + err = s.handler.SetSystemProxyEnabled(isEnabled) + if err != nil { + return writeError(conn, err) + } + return writeError(conn, nil) +}