| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 | 
							- package libbox
 
- import (
 
- 	"encoding/binary"
 
- 	"io"
 
- 	"net"
 
- 	"time"
 
- 	"github.com/sagernet/sing-box/adapter"
 
- 	"github.com/sagernet/sing-box/experimental/clashapi"
 
- 	E "github.com/sagernet/sing/common/exceptions"
 
- 	"github.com/sagernet/sing/common/rw"
 
- )
 
- func (c *CommandClient) SetClashMode(newMode string) error {
 
- 	conn, err := c.directConnect()
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	defer conn.Close()
 
- 	err = binary.Write(conn, binary.BigEndian, uint8(CommandSetClashMode))
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	err = rw.WriteVString(conn, newMode)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	return readError(conn)
 
- }
 
- func (s *CommandServer) handleSetClashMode(conn net.Conn) error {
 
- 	defer conn.Close()
 
- 	newMode, err := rw.ReadVString(conn)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	service := s.service
 
- 	if service == nil {
 
- 		return writeError(conn, E.New("service not ready"))
 
- 	}
 
- 	clashServer := service.instance.Router().ClashServer()
 
- 	if clashServer == nil {
 
- 		return writeError(conn, E.New("Clash API disabled"))
 
- 	}
 
- 	clashServer.(*clashapi.Server).SetMode(newMode)
 
- 	return writeError(conn, nil)
 
- }
 
- func (c *CommandClient) handleModeConn(conn net.Conn) {
 
- 	defer conn.Close()
 
- 	for {
 
- 		newMode, err := rw.ReadVString(conn)
 
- 		if err != nil {
 
- 			c.handler.Disconnected(err.Error())
 
- 			return
 
- 		}
 
- 		c.handler.UpdateClashMode(newMode)
 
- 	}
 
- }
 
- func (s *CommandServer) handleModeConn(conn net.Conn) error {
 
- 	defer conn.Close()
 
- 	ctx := connKeepAlive(conn)
 
- 	for s.service == nil {
 
- 		select {
 
- 		case <-time.After(time.Second):
 
- 			continue
 
- 		case <-ctx.Done():
 
- 			return ctx.Err()
 
- 		}
 
- 	}
 
- 	clashServer := s.service.instance.Router().ClashServer()
 
- 	if clashServer == nil {
 
- 		defer conn.Close()
 
- 		return binary.Write(conn, binary.BigEndian, uint16(0))
 
- 	}
 
- 	err := writeClashModeList(conn, clashServer)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	for {
 
- 		select {
 
- 		case <-s.modeUpdate:
 
- 			err = rw.WriteVString(conn, clashServer.Mode())
 
- 			if err != nil {
 
- 				return err
 
- 			}
 
- 		case <-ctx.Done():
 
- 			return ctx.Err()
 
- 		}
 
- 	}
 
- }
 
- func readClashModeList(reader io.Reader) (modeList []string, currentMode string, err error) {
 
- 	var modeListLength uint16
 
- 	err = binary.Read(reader, binary.BigEndian, &modeListLength)
 
- 	if err != nil {
 
- 		return
 
- 	}
 
- 	if modeListLength == 0 {
 
- 		return
 
- 	}
 
- 	modeList = make([]string, modeListLength)
 
- 	for i := 0; i < int(modeListLength); i++ {
 
- 		modeList[i], err = rw.ReadVString(reader)
 
- 		if err != nil {
 
- 			return
 
- 		}
 
- 	}
 
- 	currentMode, err = rw.ReadVString(reader)
 
- 	return
 
- }
 
- func writeClashModeList(writer io.Writer, clashServer adapter.ClashServer) error {
 
- 	modeList := clashServer.ModeList()
 
- 	err := binary.Write(writer, binary.BigEndian, uint16(len(modeList)))
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	if len(modeList) > 0 {
 
- 		for _, mode := range modeList {
 
- 			err = rw.WriteVString(writer, mode)
 
- 			if err != nil {
 
- 				return err
 
- 			}
 
- 		}
 
- 		err = rw.WriteVString(writer, clashServer.Mode())
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 	}
 
- 	return nil
 
- }
 
 
  |