| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- package conn
- import (
- "encoding/binary"
- "errors"
- "fmt"
- "log"
- "slices"
- "git.me9.top/git/tinymq/config"
- "git.me9.top/git/tinymq/util"
- "git.me9.top/git/tinymq/util/pool"
- )
- // 验证包编码,其中输出的数据需要回收
- func AuthPackageEncode(proto string, version uint8, channel string, auth []byte, compress bool) (buf []byte) {
- protoLen := len(proto)
- protoLenMax := 0xFF
- if protoLen > protoLenMax {
- proto = proto[0:protoLenMax]
- protoLen = protoLenMax
- }
- channelLen := len(channel)
- channelLenMax := 0xFFFF
- if channelLen > channelLenMax {
- channel = channel[0:channelLenMax]
- channelLen = channelLenMax
- }
- // id(65502)+proto(string)+version(uint8)+option(byte)+channel(string)+auth([]byte)
- dlen := 2 + 1 + protoLen + 1 + 1 + 2 + channelLen + len(auth)
- buf = pool.Get(dlen)
- index := 0
- binary.BigEndian.PutUint16(buf[index:index+2], config.ID_AUTH)
- index += 2
- buf[index] = byte(protoLen)
- index++
- copy(buf[index:index+protoLen], []byte(proto))
- index += protoLen
- buf[index] = version
- index++
- if compress {
- buf[index] = 0x01
- } else {
- buf[index] = 0
- }
- index++
- binary.BigEndian.PutUint16(buf[index:index+2], uint16(channelLen))
- index += 2
- copy(buf[index:index+channelLen], []byte(channel))
- index += channelLen
- copy(buf[index:], auth)
- return
- }
- // 验证包解码
- // id(65502)+proto(string)+version(uint8)+option(byte)+channel(string)+auth([]byte)
- func AuthPackageDecode(msg []byte, recycle bool) (proto string, version uint8, compress bool, channel string, auth []byte, err error) {
- if recycle {
- defer pool.Put(msg)
- }
- msgLen := len(msg)
- if msgLen < 9 {
- err = errors.New("wrong message length")
- return
- }
- index := 0
- id := binary.BigEndian.Uint16(msg[index : index+2])
- if id != config.ID_AUTH {
- err = fmt.Errorf("wrong message id: %d", id)
- return
- }
- index += 2
- protoLen := int(msg[index])
- if protoLen < 2 {
- err = errors.New("wrong proto length")
- return
- }
- index++
- proto = string(msg[index : index+protoLen])
- index += protoLen
- version = msg[index]
- index++
- compress = (msg[index] & 0x01) != 0
- index++
- channelLen := int(binary.BigEndian.Uint16(msg[index : index+2]))
- if channelLen < 2 {
- err = errors.New("wrong channel length")
- return
- }
- index += 2
- channel = string(msg[index : index+channelLen])
- index += channelLen
- if recycle {
- auth = slices.Clone(msg[index:])
- } else {
- auth = msg[index:]
- }
- return
- }
- // 请求包
- func RequestPackageEncode(id uint16, cmd string, data []byte, compress bool, cf *config.Config) (buf []byte) {
- // 为了区分请求还是响应包,命令字符串不能超过127个字节
- cmdLenMax := 0x7F
- cmdLen := len(cmd)
- if cmdLen > cmdLenMax {
- cmd = cmd[0:cmdLenMax]
- cmdLen = cmdLenMax
- }
- dlen := len(data)
- if compress && dlen > 0 {
- compressedData, ok, _ := util.CompressData(data)
- // id(uint16)+cmdLen(byte)+len(cmd)+option(byte)+len(data)
- ddlen := 2 + 1 + cmdLen + 1 + len(compressedData)
- buf = pool.Get(ddlen)
- index := 0
- binary.BigEndian.PutUint16(buf[index:index+2], id)
- index += 2
- buf[index] = byte(cmdLen)
- index++
- copy(buf[index:index+cmdLen], cmd)
- index += cmdLen
- if ok {
- buf[index] = 0x01
- if cf.PrintMsg {
- log.Println("[CompressData]", len(data), "->", len(compressedData))
- }
- } else {
- buf[index] = 0
- }
- index++
- copy(buf[index:], compressedData)
- } else {
- ddlen := 2 + 1 + cmdLen + dlen
- buf = pool.Get(ddlen)
- index := 0
- binary.BigEndian.PutUint16(buf[index:index+2], id)
- index += 2
- buf[index] = byte(cmdLen)
- index++
- copy(buf[index:index+cmdLen], cmd)
- index += cmdLen
- copy(buf[index:], data)
- }
- return
- }
- // 响应数据包
- // 网络格式:[id, stateCode, data]
- func ResponsePackageEncode(id uint16, state uint8, data []byte, compress bool, cf *config.Config) (buf []byte) {
- dlen := len(data)
- if compress && dlen > 0 {
- compressedData, ok, _ := util.CompressData(data)
- ddlen := 2 + 1 + 1 + len(compressedData)
- buf = pool.Get(ddlen)
- index := 0
- binary.BigEndian.PutUint16(buf[index:index+2], id)
- index += 2
- buf[index] = state | 0x80
- index++
- if ok {
- buf[index] = 0x001
- if cf.PrintMsg {
- log.Println("[CompressData]", len(data), "->", len(compressedData))
- }
- } else {
- buf[index] = 0
- }
- index++
- copy(buf[index:], compressedData)
- } else {
- ddlen := 2 + 1 + len(data)
- buf = pool.Get(ddlen)
- index := 0
- binary.BigEndian.PutUint16(buf[index:index+2], id)
- index += 2
- buf[index] = state | 0x80
- index++
- copy(buf[index:], data)
- }
- return
- }
- func PingPackageEncode(id uint16) (buf []byte) {
- buf = pool.Get(2)
- index := 0
- binary.BigEndian.PutUint16(buf[index:index+2], id)
- return
- }
- // 解析收到的数据包
- func PackageDecode(msg []byte, recycle bool, compress bool, cf *config.Config) (msgType MsgType, id uint16, cmd string, state uint8, data []byte, err error) {
- if recycle {
- defer pool.Put(msg)
- }
- msgLen := len(msg)
- id = binary.BigEndian.Uint16(msg[0:2])
- // ping信息
- if msgLen == 2 {
- msgType = PingMsg
- return
- }
- if id > config.ID_MAX {
- err = fmt.Errorf("wrong message id: %d", id)
- return
- }
- cmdx := msg[2]
- if (cmdx & 0x80) == 0 {
- // 请求包
- msgType = RequestMsg
- cmdLen := int(cmdx)
- cmd = string(msg[3 : cmdLen+3])
- data = msg[cmdLen+3:]
- } else {
- // 响应数据包
- msgType = ResponseMsg
- state = cmdx & 0x7F
- data = msg[3:]
- }
- dataLen := len(data)
- if compress && dataLen > 1 {
- var ok bool
- data, ok, err = util.UncompressData(data)
- if !ok && recycle {
- data = slices.Clone(data)
- }
- if ok && cf.PrintMsg {
- log.Println("[UncompressData]", dataLen, "->", len(data))
- }
- } else if recycle && dataLen > 0 {
- data = slices.Clone(data)
- }
- return
- }
|