github.com/LagrangeDev/LagrangeGo@v0.0.0-20240512064304-ad4a85e10cb4/utils/binary/builder.go (about)

     1  package binary
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"io"
     7  	"math"
     8  	"net"
     9  	"runtime"
    10  	"strconv"
    11  	"unsafe"
    12  
    13  	ftea "github.com/fumiama/gofastTEA"
    14  
    15  	"github.com/LagrangeDev/LagrangeGo/utils"
    16  )
    17  
    18  type Builder struct {
    19  	buffer bytes.Buffer
    20  	key    ftea.TEA
    21  	usetea bool
    22  	hasput bool
    23  	hasset bool
    24  	io.Writer
    25  	io.ReaderFrom
    26  }
    27  
    28  // NewBuilder with finalizer of itself.
    29  //
    30  // Be sure to use all data before builder is GCed.
    31  func NewBuilder(key []byte) *Builder {
    32  	b := SelectBuilder(key)
    33  	if !b.hasset {
    34  		b.hasset = true
    35  		runtime.SetFinalizer(b, func(b any) {
    36  			b.(*Builder).put()
    37  		})
    38  	}
    39  	return b
    40  }
    41  
    42  func (b *Builder) init(key []byte) *Builder {
    43  	b.key = ftea.NewTeaCipher(key)
    44  	b.usetea = len(key) == 16
    45  	b.hasput = false
    46  	return b
    47  }
    48  
    49  func (b *Builder) put() {
    50  	PutBuilder(b)
    51  }
    52  
    53  func (b *Builder) Len() int {
    54  	return b.buffer.Len()
    55  }
    56  
    57  // ToReader GC 不安全, 确保在 Builder 被回收前使用
    58  func (b *Builder) ToReader() io.Reader {
    59  	return &b.buffer
    60  }
    61  
    62  // ToBytes return data with tea encryption if key is set
    63  //
    64  // GC 安全, 返回的数据在 Builder 被销毁之后仍能被正确读取,
    65  // 但是只能调用一次, 调用后 Builder 即失效
    66  func (b *Builder) ToBytes() []byte {
    67  	defer b.put()
    68  	if b.usetea {
    69  		return b.key.Encrypt(b.buffer.Bytes())
    70  	}
    71  	buf := make([]byte, b.Len())
    72  	copy(buf, b.buffer.Bytes())
    73  	return buf
    74  }
    75  
    76  // Pack TLV with tea encryption if key is set
    77  //
    78  // GC 安全, 返回的数据在 Builder 被销毁之后仍能被正确读取,
    79  // 但是只能调用一次, 调用后 Builder 即失效
    80  func (b *Builder) Pack(typ uint16) []byte {
    81  	defer b.put()
    82  
    83  	buf := make([]byte, b.Len()+2+2+16)
    84  
    85  	n := 0
    86  	if b.usetea {
    87  		n = b.key.EncryptTo(b.buffer.Bytes(), buf[2+2:])
    88  	} else {
    89  		n = copy(buf[2+2:], b.buffer.Bytes())
    90  	}
    91  
    92  	binary.BigEndian.PutUint16(buf[0:2], typ)         // type
    93  	binary.BigEndian.PutUint16(buf[2:2+2], uint16(n)) // length
    94  
    95  	return buf[:n+2+2]
    96  }
    97  
    98  func (b *Builder) WriteBool(v bool) *Builder {
    99  	if v {
   100  		b.WriteU8('1')
   101  	} else {
   102  		b.WriteU8('0')
   103  	}
   104  	return b
   105  }
   106  
   107  // WritePacketBytes prefix must not be empty
   108  func (b *Builder) WritePacketBytes(v []byte, prefix string, withPrefix bool) *Builder {
   109  	n := len(v)
   110  	if withPrefix {
   111  		plus, err := strconv.Atoi(prefix[1:])
   112  		if err != nil {
   113  			panic(err)
   114  		}
   115  		n += plus / 8
   116  	}
   117  	switch prefix {
   118  	case "u8":
   119  		b.WriteU8(uint8(n))
   120  	case "u16":
   121  		b.WriteU16(uint16(n))
   122  	case "u32":
   123  		b.WriteU32(uint32(n))
   124  	case "u64":
   125  		b.WriteU64(uint64(n))
   126  	default:
   127  		panic("invaild prefix")
   128  	}
   129  	b.WriteBytes(v)
   130  	return b
   131  }
   132  
   133  func (b *Builder) WritePacketString(s, prefix string, withPrefix bool) *Builder {
   134  	return b.WritePacketBytes(utils.S2B(s), prefix, withPrefix)
   135  }
   136  
   137  // Write for impl. io.Writer
   138  func (b *Builder) Write(p []byte) (n int, err error) {
   139  	return b.buffer.Write(p)
   140  }
   141  
   142  func (b *Builder) EncryptAndWrite(key []byte, data []byte) *Builder {
   143  	_, _ = b.Write(ftea.NewTeaCipher(key).Encrypt(data))
   144  	return b
   145  }
   146  
   147  // ReadFrom for impl. io.ReaderFrom
   148  func (b *Builder) ReadFrom(r io.Reader) (n int64, err error) {
   149  	return io.Copy(&b.buffer, r)
   150  }
   151  
   152  func (b *Builder) WriteLenBytes(v []byte) *Builder {
   153  	b.WriteU16(uint16(len(v)))
   154  	b.WriteBytes(v)
   155  	return b
   156  }
   157  
   158  func (b *Builder) WriteBytes(v []byte) *Builder {
   159  	_, _ = b.Write(v)
   160  	return b
   161  }
   162  
   163  func (b *Builder) WriteLenString(v string) *Builder {
   164  	return b.WriteLenBytes(utils.S2B(v))
   165  }
   166  
   167  func (b *Builder) WriteStruct(data ...any) *Builder {
   168  	for _, data := range data {
   169  		_ = binary.Write(&b.buffer, binary.BigEndian, data)
   170  	}
   171  	return b
   172  }
   173  
   174  func (b *Builder) WriteU8(v uint8) *Builder {
   175  	b.buffer.WriteByte(v)
   176  	return b
   177  }
   178  
   179  func writeint[T ~uint16 | ~uint32 | ~uint64](b *Builder, v T) *Builder {
   180  	buf := make([]byte, 8)
   181  	binary.BigEndian.PutUint64(buf, uint64(v))
   182  	b.buffer.Write(buf[8-unsafe.Sizeof(v):])
   183  	return b
   184  }
   185  
   186  func (b *Builder) WriteU16(v uint16) *Builder {
   187  	return writeint(b, v)
   188  }
   189  
   190  func (b *Builder) WriteU32(v uint32) *Builder {
   191  	return writeint(b, v)
   192  }
   193  
   194  func (b *Builder) WriteU64(v uint64) *Builder {
   195  	return writeint(b, v)
   196  }
   197  
   198  func (b *Builder) WriteI8(v int8) *Builder {
   199  	return b.WriteU8(byte(v))
   200  }
   201  
   202  func (b *Builder) WriteI16(v int16) *Builder {
   203  	return b.WriteU16(uint16(v))
   204  }
   205  
   206  func (b *Builder) WriteI32(v int32) *Builder {
   207  	return b.WriteU32(uint32(v))
   208  }
   209  
   210  func (b *Builder) WriteI64(v int64) *Builder {
   211  	return b.WriteU64(uint64(v))
   212  }
   213  
   214  func (b *Builder) WriteFloat(v float32) *Builder {
   215  	return b.WriteU32(math.Float32bits(v))
   216  }
   217  
   218  func (b *Builder) WriteDouble(v float64) *Builder {
   219  	return b.WriteU64(math.Float64bits(v))
   220  }
   221  
   222  func (b *Builder) WriteTLV(tlvs ...[]byte) *Builder {
   223  	b.WriteU16(uint16(len(tlvs)))
   224  	_, _ = io.Copy(b, (*net.Buffers)(&tlvs))
   225  	return b
   226  }