evioEvents.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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. "sync"
  9. "time"
  10. "github.com/tidwall/evio"
  11. "go.uber.org/zap"
  12. )
  13. var connMap sync.Map // key - string UUID, value - evio.Conn
  14. type ConnectContext = xlog.ConnectContext
  15. func InitEvio() error {
  16. var events evio.Events
  17. events.Opened = EventsOpened
  18. events.Closed = EventsClosed
  19. events.Data = EventsData
  20. if err := evio.Serve(events, "tcp://0.0.0.0:9099"); err != nil {
  21. return err
  22. }
  23. return nil
  24. }
  25. func EventsOpened(c evio.Conn) (out []byte, opts evio.Options, action evio.Action) {
  26. connectContext := &ConnectContext{
  27. UUID: "",
  28. SN: "",
  29. XlogPackageParser: nil,
  30. DoneChan: make(chan string, 1), // 缓冲避免阻塞
  31. }
  32. connectContext.XlogPackageParser = xlog.NewXlogPackageParser(connectContext)
  33. connectContext.SendBuffer.Store([]byte(nil))
  34. c.SetContext(connectContext)
  35. // connMap.Store(c.RemoteAddr().String(), c) // 保存连接
  36. // xlogPackageParserMap.Store(c.RemoteAddr().String(), xlog.NewXlogPackageParser())
  37. opts = evio.Options{}
  38. action = evio.None
  39. return
  40. }
  41. func EventsClosed(c evio.Conn, err error) (action evio.Action) {
  42. if connectContext := c.Context().(*ConnectContext); connectContext != nil {
  43. uuid := connectContext.UUID
  44. connMap.Delete(uuid)
  45. logger.Std.Println("断开连接端口 UUID: ", uuid)
  46. }
  47. // xlogPackageParserMap.Delete(c.RemoteAddr().String())
  48. action = evio.None
  49. return
  50. }
  51. func EventsData(c evio.Conn, in []byte) (out []byte, action evio.Action) {
  52. connectContext, ok := c.Context().(*ConnectContext)
  53. if !ok || connectContext == nil {
  54. logger.Std.Println("EventsData Context invalid.")
  55. logger.Std.Println(connectContext)
  56. action = evio.None
  57. return
  58. }
  59. uuid := connectContext.UUID
  60. logger.Std.Println("接收数据 UUID: ", uuid)
  61. out = nil
  62. if in == nil {
  63. // 处理数据发送事件
  64. buffer := connectContext.SendBuffer.Swap([]byte(nil)).([]byte)
  65. if len(buffer) > 0 {
  66. out = buffer
  67. }
  68. } else {
  69. // 处理数据接收事件
  70. parser := connectContext.XlogPackageParser
  71. if !parser.Handshake {
  72. data, err := parser.ParseXlogHandshakePackage(in)
  73. if err != nil {
  74. zap.L().Error("握手失败", zap.String("err", err.Error()))
  75. } else {
  76. out, err = parser.CreateXlogHandshakePackage()
  77. if err != nil {
  78. zap.L().Error("握手失败", zap.String("err", err.Error()))
  79. } else {
  80. parser.Handshake = true
  81. connectContext.UUID = string(data.DevUuid[:])
  82. connMap.Store(string(data.DevUuid[:]), c) // 保存连接
  83. zap.L().Info("握手校验", zap.Binary("newIv", data.NewIv[:]))
  84. }
  85. }
  86. } else {
  87. parser.PreparserXlogPackage(in)
  88. }
  89. }
  90. action = evio.None
  91. return
  92. }
  93. func GetConnectList() []domain.XlogSiteInfo {
  94. infoList := make([]domain.XlogSiteInfo, 0)
  95. connMap.Range(func(key, value any) bool {
  96. conn := value.(evio.Conn)
  97. ctx := conn.Context().(*ConnectContext)
  98. infoList = append(infoList, domain.XlogSiteInfo{
  99. Sn: ctx.SN,
  100. Uuid: key.(string),
  101. })
  102. return true
  103. })
  104. return infoList
  105. }
  106. func SendXlogCmdDate(uuid string, data []byte) (string, error) {
  107. var err error
  108. if val, ok := connMap.Load(uuid); ok {
  109. c := val.(evio.Conn)
  110. connectContext, ok := c.Context().(*ConnectContext)
  111. if !ok || connectContext == nil {
  112. err = fmt.Errorf("send xlog cmd filed : Context missing, UUID: %s", uuid)
  113. return "", err
  114. }
  115. buffer, _ := connectContext.SendBuffer.Load().([]byte)
  116. if buffer != nil {
  117. err = fmt.Errorf("send xlog cmd filed : Data sending, UUID: %s", uuid)
  118. return "", err
  119. }
  120. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  121. defer cancel()
  122. // 创建一个带缓冲的 done channel
  123. done := make(chan string, 1)
  124. connectContext.DoneChan = done
  125. // 存储要发送的数据
  126. cmdPackage, err := connectContext.XlogPackageParser.CreateXlogCmdPackage(append([]byte(connectContext.UUID)[len(uuid)-8:], data...))
  127. if err != nil {
  128. return "", err
  129. }
  130. connectContext.SendBuffer.Store(cmdPackage)
  131. // 唤醒 evio,让它触发 Data 事件去真正写数据
  132. c.Wake()
  133. // 等待结果或超时
  134. select {
  135. case result := <-done:
  136. return result, nil
  137. case <-ctx.Done():
  138. return "", fmt.Errorf("send xlog cmd timeout, UUID: %s, err: %v", uuid, ctx.Err())
  139. }
  140. } else {
  141. err = fmt.Errorf("send xlog cmd filed : Connect missing, UUID: %s", uuid)
  142. }
  143. return "", err
  144. }