| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 | 
							- package libbox
 
- import (
 
- 	"bufio"
 
- 	"bytes"
 
- 	"compress/gzip"
 
- 	"encoding/binary"
 
- 	E "github.com/sagernet/sing/common/exceptions"
 
- 	"github.com/sagernet/sing/common/varbin"
 
- )
 
- func EncodeChunkedMessage(data []byte) []byte {
 
- 	var buffer bytes.Buffer
 
- 	binary.Write(&buffer, binary.BigEndian, uint16(len(data)))
 
- 	buffer.Write(data)
 
- 	return buffer.Bytes()
 
- }
 
- func DecodeLengthChunk(data []byte) int32 {
 
- 	return int32(binary.BigEndian.Uint16(data))
 
- }
 
- const (
 
- 	MessageTypeError = iota
 
- 	MessageTypeProfileList
 
- 	MessageTypeProfileContentRequest
 
- 	MessageTypeProfileContent
 
- )
 
- type ErrorMessage struct {
 
- 	Message string
 
- }
 
- func (e *ErrorMessage) Encode() []byte {
 
- 	var buffer bytes.Buffer
 
- 	buffer.WriteByte(MessageTypeError)
 
- 	varbin.Write(&buffer, binary.BigEndian, e.Message)
 
- 	return buffer.Bytes()
 
- }
 
- func DecodeErrorMessage(data []byte) (*ErrorMessage, error) {
 
- 	reader := bytes.NewReader(data)
 
- 	messageType, err := reader.ReadByte()
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	if messageType != MessageTypeError {
 
- 		return nil, E.New("invalid message")
 
- 	}
 
- 	var message ErrorMessage
 
- 	message.Message, err = varbin.ReadValue[string](reader, binary.BigEndian)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	return &message, nil
 
- }
 
- const (
 
- 	ProfileTypeLocal int32 = iota
 
- 	ProfileTypeiCloud
 
- 	ProfileTypeRemote
 
- )
 
- type ProfilePreview struct {
 
- 	ProfileID int64
 
- 	Name      string
 
- 	Type      int32
 
- }
 
- type ProfilePreviewIterator interface {
 
- 	Next() *ProfilePreview
 
- 	HasNext() bool
 
- }
 
- type ProfileEncoder struct {
 
- 	profiles []ProfilePreview
 
- }
 
- func (e *ProfileEncoder) Append(profile *ProfilePreview) {
 
- 	e.profiles = append(e.profiles, *profile)
 
- }
 
- func (e *ProfileEncoder) Encode() []byte {
 
- 	var buffer bytes.Buffer
 
- 	buffer.WriteByte(MessageTypeProfileList)
 
- 	binary.Write(&buffer, binary.BigEndian, uint16(len(e.profiles)))
 
- 	for _, preview := range e.profiles {
 
- 		binary.Write(&buffer, binary.BigEndian, preview.ProfileID)
 
- 		varbin.Write(&buffer, binary.BigEndian, preview.Name)
 
- 		binary.Write(&buffer, binary.BigEndian, preview.Type)
 
- 	}
 
- 	return buffer.Bytes()
 
- }
 
- type ProfileDecoder struct {
 
- 	profiles []*ProfilePreview
 
- }
 
- func (d *ProfileDecoder) Decode(data []byte) error {
 
- 	reader := bytes.NewReader(data)
 
- 	messageType, err := reader.ReadByte()
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	if messageType != MessageTypeProfileList {
 
- 		return E.New("invalid message")
 
- 	}
 
- 	var profileCount uint16
 
- 	err = binary.Read(reader, binary.BigEndian, &profileCount)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	for i := 0; i < int(profileCount); i++ {
 
- 		var profile ProfilePreview
 
- 		err = binary.Read(reader, binary.BigEndian, &profile.ProfileID)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 		profile.Name, err = varbin.ReadValue[string](reader, binary.BigEndian)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 		err = binary.Read(reader, binary.BigEndian, &profile.Type)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 		d.profiles = append(d.profiles, &profile)
 
- 	}
 
- 	return nil
 
- }
 
- func (d *ProfileDecoder) Iterator() ProfilePreviewIterator {
 
- 	return newIterator(d.profiles)
 
- }
 
- type ProfileContentRequest struct {
 
- 	ProfileID int64
 
- }
 
- func (r *ProfileContentRequest) Encode() []byte {
 
- 	var buffer bytes.Buffer
 
- 	buffer.WriteByte(MessageTypeProfileContentRequest)
 
- 	binary.Write(&buffer, binary.BigEndian, r.ProfileID)
 
- 	return buffer.Bytes()
 
- }
 
- func DecodeProfileContentRequest(data []byte) (*ProfileContentRequest, error) {
 
- 	reader := bytes.NewReader(data)
 
- 	messageType, err := reader.ReadByte()
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	if messageType != MessageTypeProfileContentRequest {
 
- 		return nil, E.New("invalid message")
 
- 	}
 
- 	var request ProfileContentRequest
 
- 	err = binary.Read(reader, binary.BigEndian, &request.ProfileID)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	return &request, nil
 
- }
 
- type ProfileContent struct {
 
- 	Name               string
 
- 	Type               int32
 
- 	Config             string
 
- 	RemotePath         string
 
- 	AutoUpdate         bool
 
- 	AutoUpdateInterval int32
 
- 	LastUpdated        int64
 
- }
 
- func (c *ProfileContent) Encode() []byte {
 
- 	buffer := new(bytes.Buffer)
 
- 	buffer.WriteByte(MessageTypeProfileContent)
 
- 	buffer.WriteByte(1)
 
- 	gWriter := gzip.NewWriter(buffer)
 
- 	writer := bufio.NewWriter(gWriter)
 
- 	varbin.Write(writer, binary.BigEndian, c.Name)
 
- 	binary.Write(writer, binary.BigEndian, c.Type)
 
- 	varbin.Write(writer, binary.BigEndian, c.Config)
 
- 	if c.Type != ProfileTypeLocal {
 
- 		varbin.Write(writer, binary.BigEndian, c.RemotePath)
 
- 	}
 
- 	if c.Type == ProfileTypeRemote {
 
- 		binary.Write(writer, binary.BigEndian, c.AutoUpdate)
 
- 		binary.Write(writer, binary.BigEndian, c.AutoUpdateInterval)
 
- 		binary.Write(writer, binary.BigEndian, c.LastUpdated)
 
- 	}
 
- 	writer.Flush()
 
- 	gWriter.Flush()
 
- 	gWriter.Close()
 
- 	return buffer.Bytes()
 
- }
 
- func DecodeProfileContent(data []byte) (*ProfileContent, error) {
 
- 	reader := bytes.NewReader(data)
 
- 	messageType, err := reader.ReadByte()
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	if messageType != MessageTypeProfileContent {
 
- 		return nil, E.New("invalid message")
 
- 	}
 
- 	version, err := reader.ReadByte()
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	gReader, err := gzip.NewReader(reader)
 
- 	if err != nil {
 
- 		return nil, E.Cause(err, "unsupported profile")
 
- 	}
 
- 	bReader := varbin.StubReader(gReader)
 
- 	var content ProfileContent
 
- 	content.Name, err = varbin.ReadValue[string](bReader, binary.BigEndian)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	err = binary.Read(bReader, binary.BigEndian, &content.Type)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	content.Config, err = varbin.ReadValue[string](bReader, binary.BigEndian)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	if content.Type != ProfileTypeLocal {
 
- 		content.RemotePath, err = varbin.ReadValue[string](bReader, binary.BigEndian)
 
- 		if err != nil {
 
- 			return nil, err
 
- 		}
 
- 	}
 
- 	if content.Type == ProfileTypeRemote || (version == 0 && content.Type != ProfileTypeLocal) {
 
- 		err = binary.Read(bReader, binary.BigEndian, &content.AutoUpdate)
 
- 		if err != nil {
 
- 			return nil, err
 
- 		}
 
- 		if version >= 1 {
 
- 			err = binary.Read(bReader, binary.BigEndian, &content.AutoUpdateInterval)
 
- 			if err != nil {
 
- 				return nil, err
 
- 			}
 
- 		}
 
- 		err = binary.Read(bReader, binary.BigEndian, &content.LastUpdated)
 
- 		if err != nil {
 
- 			return nil, err
 
- 		}
 
- 	}
 
- 	return &content, nil
 
- }
 
 
  |