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 }