evioEvents.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. package networkEvents
  2. import (
  3. "context"
  4. "fmt"
  5. "fwh-toolbox-server/domain"
  6. "fwh-toolbox-server/logger"
  7. "fwh-toolbox-server/utils/xlog"
  8. "regexp"
  9. "sync"
  10. "time"
  11. "github.com/google/uuid"
  12. "github.com/tidwall/evio"
  13. "go.uber.org/zap"
  14. )
  15. var connMap sync.Map // key - string UUID, value - evio.Conn
  16. type ConnectContext = xlog.ConnectContext
  17. func InitEvio() error {
  18. var events evio.Events
  19. events.Opened = EventsOpened
  20. events.Closed = EventsClosed
  21. events.Data = EventsData
  22. if err := evio.Serve(events, "tcp://0.0.0.0:9099"); err != nil {
  23. return err
  24. }
  25. return nil
  26. }
  27. func EventsOpened(c evio.Conn) (out []byte, opts evio.Options, action evio.Action) {
  28. logger.Std.Println("EventsOpened ", c.RemoteAddr().String())
  29. newUUID := uuid.New().String()
  30. connectContext := &ConnectContext{
  31. UUID: newUUID,
  32. SN: "",
  33. Version: "xlog v1.0",
  34. XlogPackageParser: nil,
  35. DoneChan: make(chan string, 1), // 缓冲避免阻塞
  36. ChanIsRunning: false,
  37. }
  38. connectContext.XlogPackageParser = xlog.NewXlogPackageParser(connectContext)
  39. connectContext.SendBuffer.Store([]byte(nil))
  40. c.SetContext(connectContext)
  41. connMap.Store(newUUID, c) // 预保存连接(兼容xlog 1.0)
  42. // connMap.Store(c.RemoteAddr().String(), c) // 保存连接
  43. // xlogPackageParserMap.Store(c.RemoteAddr().String(), xlog.NewXlogPackageParser())
  44. opts = evio.Options{}
  45. action = evio.None
  46. return
  47. }
  48. func EventsClosed(c evio.Conn, err error) (action evio.Action) {
  49. if connectContext := c.Context().(*ConnectContext); connectContext != nil {
  50. uuid := connectContext.UUID
  51. connMap.Delete(uuid)
  52. logger.Std.Println("断开连接端口 UUID: ", uuid)
  53. }
  54. // xlogPackageParserMap.Delete(c.RemoteAddr().String())
  55. action = evio.None
  56. return
  57. }
  58. func EventsData(c evio.Conn, in []byte) (out []byte, action evio.Action) {
  59. connectContext, ok := c.Context().(*ConnectContext)
  60. if !ok || connectContext == nil {
  61. logger.Std.Println("EventsData Context invalid.")
  62. logger.Std.Println(connectContext)
  63. action = evio.None
  64. return
  65. }
  66. // logger.Std.Println("接收数据 UUID: ", connectContext.UUID)
  67. // logger.Std.Println("接收数据: ", in)
  68. out = nil
  69. if in == nil {
  70. // 处理数据发送事件
  71. buffer := connectContext.SendBuffer.Swap([]byte(nil)).([]byte)
  72. if len(buffer) > 0 {
  73. out = buffer
  74. }
  75. } else {
  76. // 处理数据接收事件
  77. parser := connectContext.XlogPackageParser
  78. if !parser.Handshake {
  79. // 先判断协议版本,是否是xlog1.0
  80. ok, err := parser.ParseXlogCheckVersionIsOld(in)
  81. if err != nil {
  82. zap.L().Error("版本判断失败", zap.String("err", err.Error()))
  83. } else {
  84. if ok {
  85. parser.Handshake = true
  86. parser.PreparserXlog10Package(in)
  87. } else {
  88. data, err := parser.ParseXlogHandshakePackage(in)
  89. if err != nil {
  90. zap.L().Error("握手失败", zap.String("err", err.Error()))
  91. } else {
  92. out, err = parser.CreateXlogHandshakePackage()
  93. if err != nil {
  94. zap.L().Error("握手失败", zap.String("err", err.Error()))
  95. } else {
  96. parser.Handshake = true
  97. parser.IsOldProtocol = false
  98. connMap.Delete(connectContext.UUID) // 删除预保存的连接,使用xlog v2.0的UUID
  99. connectContext.UUID = string(data.DevUuid[:]) // 覆盖UUID
  100. connectContext.Version = "xlog v2.0"
  101. connMap.Store(connectContext.UUID, c) // 保存xlog v2.0的连接
  102. zap.L().Info("握手校验", zap.Binary("newIv", data.NewIv[:]))
  103. }
  104. }
  105. }
  106. }
  107. } else if parser.IsOldProtocol {
  108. parser.PreparserXlog10Package(in)
  109. } else {
  110. parser.PreparserXlogPackage(in)
  111. }
  112. }
  113. action = evio.None
  114. return
  115. }
  116. func GetConnectList() []domain.XlogSiteInfo {
  117. infoList := make([]domain.XlogSiteInfo, 0)
  118. connMap.Range(func(key, value any) bool {
  119. conn := value.(evio.Conn)
  120. ctx := conn.Context().(*ConnectContext)
  121. infoList = append(infoList, domain.XlogSiteInfo{
  122. Sn: ctx.SN,
  123. Uuid: key.(string),
  124. Version: ctx.Version,
  125. })
  126. return true
  127. })
  128. return infoList
  129. }
  130. func SendXlogCmdDate(uuid string, data []byte) (string, error) {
  131. var err error
  132. if val, ok := connMap.Load(uuid); ok {
  133. c := val.(evio.Conn)
  134. connectContext, ok := c.Context().(*ConnectContext)
  135. if !ok || connectContext == nil {
  136. err = fmt.Errorf("send xlog cmd filed : Context missing, UUID: %s", uuid)
  137. return "", err
  138. }
  139. // 判断连接是否在传输结果
  140. if connectContext.ChanIsRunning {
  141. return "命令正在执行中,请稍后...", nil
  142. }
  143. connectContext.ChanIsRunning = true
  144. defer func() {
  145. connectContext.ChanIsRunning = false
  146. }()
  147. buffer, _ := connectContext.SendBuffer.Load().([]byte)
  148. if buffer != nil {
  149. err = fmt.Errorf("send xlog cmd filed : Data sending, UUID: %s", uuid)
  150. return "", err
  151. }
  152. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  153. defer cancel()
  154. // 创建一个带缓冲的 done channel
  155. done := make(chan string, 1)
  156. connectContext.DoneChan = done
  157. // 存储要发送的数据
  158. var cmdPackage []byte
  159. if connectContext.XlogPackageParser.IsOldProtocol {
  160. cmdPackage, err = connectContext.XlogPackageParser.CreateXlog10CmdPackage(data)
  161. } else {
  162. cmdPackage, err = connectContext.XlogPackageParser.CreateXlogCmdPackage(append([]byte(connectContext.UUID)[len(uuid)-8:], data...))
  163. }
  164. if err != nil {
  165. return "", err
  166. }
  167. connectContext.SendBuffer.Store(cmdPackage)
  168. // 唤醒 evio,让它触发 Data 事件去真正写数据
  169. c.Wake()
  170. // 等待结果或超时
  171. select {
  172. case result := <-done:
  173. if connectContext.XlogPackageParser.IsOldProtocol && len(connectContext.SN) == 0 {
  174. re := regexp.MustCompile(`"AGATE_SN"\s*:\s*"([^"]*)"`)
  175. match := re.FindStringSubmatch(result)
  176. if len(match) > 1 {
  177. fmt.Println("AGATE_SN:", match[1])
  178. connectContext.SN = match[1]
  179. }
  180. }
  181. return result, nil
  182. case <-ctx.Done():
  183. return "", fmt.Errorf("send xlog cmd timeout, UUID: %s, err: %v", uuid, ctx.Err())
  184. }
  185. } else {
  186. err = fmt.Errorf("send xlog cmd filed : Connect missing, UUID: %s", uuid)
  187. }
  188. return "", err
  189. }