github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/experimental/libbox/command_clash_mode.go (about)

     1  package libbox
     2  
     3  import (
     4  	"encoding/binary"
     5  	"io"
     6  	"net"
     7  	"time"
     8  
     9  	"github.com/inazumav/sing-box/adapter"
    10  	"github.com/inazumav/sing-box/experimental/clashapi"
    11  	E "github.com/sagernet/sing/common/exceptions"
    12  	"github.com/sagernet/sing/common/rw"
    13  )
    14  
    15  func (c *CommandClient) SetClashMode(newMode string) error {
    16  	conn, err := c.directConnect()
    17  	if err != nil {
    18  		return err
    19  	}
    20  	defer conn.Close()
    21  	err = binary.Write(conn, binary.BigEndian, uint8(CommandSetClashMode))
    22  	if err != nil {
    23  		return err
    24  	}
    25  	err = rw.WriteVString(conn, newMode)
    26  	if err != nil {
    27  		return err
    28  	}
    29  	return readError(conn)
    30  }
    31  
    32  func (s *CommandServer) handleSetClashMode(conn net.Conn) error {
    33  	defer conn.Close()
    34  	newMode, err := rw.ReadVString(conn)
    35  	if err != nil {
    36  		return err
    37  	}
    38  	service := s.service
    39  	if service == nil {
    40  		return writeError(conn, E.New("service not ready"))
    41  	}
    42  	clashServer := service.instance.Router().ClashServer()
    43  	if clashServer == nil {
    44  		return writeError(conn, E.New("Clash API disabled"))
    45  	}
    46  	clashServer.(*clashapi.Server).SetMode(newMode)
    47  	return writeError(conn, nil)
    48  }
    49  
    50  func (c *CommandClient) handleModeConn(conn net.Conn) {
    51  	defer conn.Close()
    52  
    53  	for {
    54  		newMode, err := rw.ReadVString(conn)
    55  		if err != nil {
    56  			c.handler.Disconnected(err.Error())
    57  			return
    58  		}
    59  		c.handler.UpdateClashMode(newMode)
    60  	}
    61  }
    62  
    63  func (s *CommandServer) handleModeConn(conn net.Conn) error {
    64  	defer conn.Close()
    65  	ctx := connKeepAlive(conn)
    66  	for s.service == nil {
    67  		select {
    68  		case <-time.After(time.Second):
    69  			continue
    70  		case <-ctx.Done():
    71  			return ctx.Err()
    72  		}
    73  	}
    74  	clashServer := s.service.instance.Router().ClashServer()
    75  	if clashServer == nil {
    76  		defer conn.Close()
    77  		return binary.Write(conn, binary.BigEndian, uint16(0))
    78  	}
    79  	err := writeClashModeList(conn, clashServer)
    80  	if err != nil {
    81  		return err
    82  	}
    83  	for {
    84  		select {
    85  		case <-s.modeUpdate:
    86  			err = rw.WriteVString(conn, clashServer.Mode())
    87  			if err != nil {
    88  				return err
    89  			}
    90  		case <-ctx.Done():
    91  			return ctx.Err()
    92  		}
    93  	}
    94  }
    95  
    96  func readClashModeList(reader io.Reader) (modeList []string, currentMode string, err error) {
    97  	var modeListLength uint16
    98  	err = binary.Read(reader, binary.BigEndian, &modeListLength)
    99  	if err != nil {
   100  		return
   101  	}
   102  	if modeListLength == 0 {
   103  		return
   104  	}
   105  	modeList = make([]string, modeListLength)
   106  	for i := 0; i < int(modeListLength); i++ {
   107  		modeList[i], err = rw.ReadVString(reader)
   108  		if err != nil {
   109  			return
   110  		}
   111  	}
   112  	currentMode, err = rw.ReadVString(reader)
   113  	return
   114  }
   115  
   116  func writeClashModeList(writer io.Writer, clashServer adapter.ClashServer) error {
   117  	modeList := clashServer.ModeList()
   118  	err := binary.Write(writer, binary.BigEndian, uint16(len(modeList)))
   119  	if err != nil {
   120  		return err
   121  	}
   122  	if len(modeList) > 0 {
   123  		for _, mode := range modeList {
   124  			err = rw.WriteVString(writer, mode)
   125  			if err != nil {
   126  				return err
   127  			}
   128  		}
   129  		err = rw.WriteVString(writer, clashServer.Mode())
   130  		if err != nil {
   131  			return err
   132  		}
   133  	}
   134  	return nil
   135  }