util.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. package conn
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "fmt"
  6. "log"
  7. "slices"
  8. "git.me9.top/git/tinymq/config"
  9. "git.me9.top/git/tinymq/util"
  10. "git.me9.top/git/tinymq/util/pool"
  11. )
  12. // 验证包编码,其中输出的数据需要回收
  13. func AuthPackageEncode(proto string, version uint8, channel string, auth []byte, compress bool) (buf []byte) {
  14. protoLen := len(proto)
  15. protoLenMax := 0xFF
  16. if protoLen > protoLenMax {
  17. proto = proto[0:protoLenMax]
  18. protoLen = protoLenMax
  19. }
  20. channelLen := len(channel)
  21. channelLenMax := 0xFFFF
  22. if channelLen > channelLenMax {
  23. channel = channel[0:channelLenMax]
  24. channelLen = channelLenMax
  25. }
  26. // id(65502)+proto(string)+version(uint8)+option(byte)+channel(string)+auth([]byte)
  27. dlen := 2 + 1 + protoLen + 1 + 1 + 2 + channelLen + len(auth)
  28. buf = pool.Get(dlen)
  29. index := 0
  30. binary.BigEndian.PutUint16(buf[index:index+2], config.ID_AUTH)
  31. index += 2
  32. buf[index] = byte(protoLen)
  33. index++
  34. copy(buf[index:index+protoLen], []byte(proto))
  35. index += protoLen
  36. buf[index] = version
  37. index++
  38. if compress {
  39. buf[index] = 0x01
  40. } else {
  41. buf[index] = 0
  42. }
  43. index++
  44. binary.BigEndian.PutUint16(buf[index:index+2], uint16(channelLen))
  45. index += 2
  46. copy(buf[index:index+channelLen], []byte(channel))
  47. index += channelLen
  48. copy(buf[index:], auth)
  49. return
  50. }
  51. // 验证包解码
  52. // id(65502)+proto(string)+version(uint8)+option(byte)+channel(string)+auth([]byte)
  53. func AuthPackageDecode(msg []byte, recycle bool) (proto string, version uint8, compress bool, channel string, auth []byte, err error) {
  54. if recycle {
  55. defer pool.Put(msg)
  56. }
  57. msgLen := len(msg)
  58. if msgLen < 9 {
  59. err = errors.New("wrong message length")
  60. return
  61. }
  62. index := 0
  63. id := binary.BigEndian.Uint16(msg[index : index+2])
  64. if id != config.ID_AUTH {
  65. err = fmt.Errorf("wrong message id: %d", id)
  66. return
  67. }
  68. index += 2
  69. protoLen := int(msg[index])
  70. if protoLen < 2 {
  71. err = errors.New("wrong proto length")
  72. return
  73. }
  74. index++
  75. proto = string(msg[index : index+protoLen])
  76. index += protoLen
  77. version = msg[index]
  78. index++
  79. compress = (msg[index] & 0x01) != 0
  80. index++
  81. channelLen := int(binary.BigEndian.Uint16(msg[index : index+2]))
  82. if channelLen < 2 {
  83. err = errors.New("wrong channel length")
  84. return
  85. }
  86. index += 2
  87. channel = string(msg[index : index+channelLen])
  88. index += channelLen
  89. if recycle {
  90. auth = slices.Clone(msg[index:])
  91. } else {
  92. auth = msg[index:]
  93. }
  94. return
  95. }
  96. // 请求包
  97. func RequestPackageEncode(id uint16, cmd string, data []byte, compress bool, cf *config.Config) (buf []byte) {
  98. // 为了区分请求还是响应包,命令字符串不能超过127个字节
  99. cmdLenMax := 0x7F
  100. cmdLen := len(cmd)
  101. if cmdLen > cmdLenMax {
  102. cmd = cmd[0:cmdLenMax]
  103. cmdLen = cmdLenMax
  104. }
  105. dlen := len(data)
  106. if compress && dlen > 0 {
  107. compressedData, ok, _ := util.CompressData(data)
  108. // id(uint16)+cmdLen(byte)+len(cmd)+option(byte)+len(data)
  109. ddlen := 2 + 1 + cmdLen + 1 + len(compressedData)
  110. buf = pool.Get(ddlen)
  111. index := 0
  112. binary.BigEndian.PutUint16(buf[index:index+2], id)
  113. index += 2
  114. buf[index] = byte(cmdLen)
  115. index++
  116. copy(buf[index:index+cmdLen], cmd)
  117. index += cmdLen
  118. if ok {
  119. buf[index] = 0x01
  120. if cf.PrintMsg {
  121. log.Println("[CompressData]", len(data), "->", len(compressedData))
  122. }
  123. } else {
  124. buf[index] = 0
  125. }
  126. index++
  127. copy(buf[index:], compressedData)
  128. } else {
  129. ddlen := 2 + 1 + cmdLen + dlen
  130. buf = pool.Get(ddlen)
  131. index := 0
  132. binary.BigEndian.PutUint16(buf[index:index+2], id)
  133. index += 2
  134. buf[index] = byte(cmdLen)
  135. index++
  136. copy(buf[index:index+cmdLen], cmd)
  137. index += cmdLen
  138. copy(buf[index:], data)
  139. }
  140. return
  141. }
  142. // 响应数据包
  143. // 网络格式:[id, stateCode, data]
  144. func ResponsePackageEncode(id uint16, state uint8, data []byte, compress bool, cf *config.Config) (buf []byte) {
  145. dlen := len(data)
  146. if compress && dlen > 0 {
  147. compressedData, ok, _ := util.CompressData(data)
  148. ddlen := 2 + 1 + 1 + len(compressedData)
  149. buf = pool.Get(ddlen)
  150. index := 0
  151. binary.BigEndian.PutUint16(buf[index:index+2], id)
  152. index += 2
  153. buf[index] = state | 0x80
  154. index++
  155. if ok {
  156. buf[index] = 0x001
  157. if cf.PrintMsg {
  158. log.Println("[CompressData]", len(data), "->", len(compressedData))
  159. }
  160. } else {
  161. buf[index] = 0
  162. }
  163. index++
  164. copy(buf[index:], compressedData)
  165. } else {
  166. ddlen := 2 + 1 + len(data)
  167. buf = pool.Get(ddlen)
  168. index := 0
  169. binary.BigEndian.PutUint16(buf[index:index+2], id)
  170. index += 2
  171. buf[index] = state | 0x80
  172. index++
  173. copy(buf[index:], data)
  174. }
  175. return
  176. }
  177. func PingPackageEncode(id uint16) (buf []byte) {
  178. buf = pool.Get(2)
  179. index := 0
  180. binary.BigEndian.PutUint16(buf[index:index+2], id)
  181. return
  182. }
  183. // 解析收到的数据包
  184. func PackageDecode(msg []byte, recycle bool, compress bool, cf *config.Config) (msgType MsgType, id uint16, cmd string, state uint8, data []byte, err error) {
  185. if recycle {
  186. defer pool.Put(msg)
  187. }
  188. msgLen := len(msg)
  189. id = binary.BigEndian.Uint16(msg[0:2])
  190. // ping信息
  191. if msgLen == 2 {
  192. msgType = PingMsg
  193. return
  194. }
  195. if id > config.ID_MAX {
  196. err = fmt.Errorf("wrong message id: %d", id)
  197. return
  198. }
  199. cmdx := msg[2]
  200. if (cmdx & 0x80) == 0 {
  201. // 请求包
  202. msgType = RequestMsg
  203. cmdLen := int(cmdx)
  204. cmd = string(msg[3 : cmdLen+3])
  205. data = msg[cmdLen+3:]
  206. } else {
  207. // 响应数据包
  208. msgType = ResponseMsg
  209. state = cmdx & 0x7F
  210. data = msg[3:]
  211. }
  212. dataLen := len(data)
  213. if compress && dataLen > 1 {
  214. var ok bool
  215. data, ok, err = util.UncompressData(data)
  216. if !ok && recycle {
  217. data = slices.Clone(data)
  218. }
  219. if ok && cf.PrintMsg {
  220. log.Println("[UncompressData]", dataLen, "->", len(data))
  221. }
  222. } else if recycle && dataLen > 0 {
  223. data = slices.Clone(data)
  224. }
  225. return
  226. }