电调模型.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. package models
  2. import (
  3. "fmt"
  4. "sync"
  5. "time"
  6. )
  7. // DiandiaoModel 表示电调的 JSON 结构
  8. type DiandiaoModel struct {
  9. CMDType int `json:"CMDType"` //0:设备状态1设备数据控制
  10. CtrlType int `json:"CtrlType"`
  11. EqpmtStatus int `json:"EqpmtStatus"` //设备状态值
  12. EqpmtStdName string `json:"EqpmtStdName"` //设备标准名称
  13. EqpmtStrID string `json:"EqpmtStrID"`
  14. IsReset int `json:"IsReset"`
  15. LineID int `json:"LineID"` //线路号
  16. OpeMark int `json:"OpeMark"`
  17. FValue int `json:"fValue"` //浮点数值
  18. NValueType int `json:"nValueType"`
  19. EqpmtTypeID int `json:"EqpmtTypeID"`
  20. }
  21. // ... existing code ...
  22. // generateModelKey 生成电调模型唯一键
  23. func (em *DiandiaoModel) GenerateModelKey() string {
  24. //return fmt.Sprintf("%d:%d:%d", em.LineID, em.StationID, em.ViewID)
  25. return fmt.Sprintf("%d", em.LineID)
  26. }
  27. // 单图元电调模型
  28. type EViewMapModel struct {
  29. Models []DiandiaoModel // key: modelKey, value: 设备列表
  30. ModelKey string // 唯一键
  31. LastBatchUpdate time.Time // 最后总包更新时间
  32. LastDeviceUpdate time.Time // 单设备更新时间
  33. }
  34. // ElectricModelManager 电调模型管理器
  35. type ElectricModelManager struct {
  36. Models map[string]EViewMapModel // key: modelKey, value: 单图元电调模型
  37. Mutex sync.RWMutex // 读写锁保护并发访问
  38. once sync.Once // 确保初始化只执行一次
  39. // 用于跟踪客户端连接和上次发送的数据
  40. ClientData map[string]map[string]string // clientID -> (eqpmtStrID -> value)
  41. ClientLastFullData time.Time // 上次发送全量数据的时间
  42. ClientLastAccess map[string]time.Time // clientID -> 最后访问时间
  43. }
  44. // 使用 sync.Once 确保线程安全的单例实例创建
  45. var (
  46. instance *ElectricModelManager
  47. once sync.Once
  48. )
  49. // GetInstance 获取 ElectricModelManager 的单例实例
  50. func GetInstance() *ElectricModelManager {
  51. once.Do(func() {
  52. instance = &ElectricModelManager{
  53. Models: make(map[string]EViewMapModel),
  54. ClientData: make(map[string]map[string]string),
  55. ClientLastAccess: make(map[string]time.Time),
  56. }
  57. })
  58. // 定期清理长时间未访问的客户端数据
  59. go instance.cleanupInactiveClients()
  60. return instance
  61. }
  62. // UpdateBatchData 更新总包数据
  63. func (em *ElectricModelManager) UpdateBatchData(models []DiandiaoModel) {
  64. em.once.Do(func() {
  65. em.Models = make(map[string]EViewMapModel)
  66. })
  67. // 创建新的映射而不是直接清空,提高并发安全性
  68. newModels := make(map[string]EViewMapModel)
  69. for _, model := range models {
  70. key := model.GenerateModelKey()
  71. if viewMapModel, exists := newModels[key]; exists {
  72. viewMapModel.Models = append(viewMapModel.Models, model)
  73. viewMapModel.LastBatchUpdate = time.Now()
  74. newModels[key] = viewMapModel
  75. } else {
  76. newModels[key] = EViewMapModel{
  77. Models: []DiandiaoModel{model},
  78. ModelKey: key,
  79. LastBatchUpdate: time.Now(),
  80. LastDeviceUpdate: time.Time{},
  81. }
  82. }
  83. }
  84. // 原子性地替换整个映射
  85. em.Mutex.Lock()
  86. em.Models = newModels
  87. em.Mutex.Unlock()
  88. }
  89. // GetModelByKey 根据Key获取EViewMapModel
  90. func (em *ElectricModelManager) GetModelByKey(key string) (EViewMapModel, bool) {
  91. em.Mutex.RLock()
  92. defer em.Mutex.RUnlock()
  93. model, exists := em.Models[key]
  94. if !exists {
  95. // 返回空值和false表示未找到
  96. return EViewMapModel{}, false
  97. }
  98. // 返回拷贝以避免外部修改影响内部状态
  99. modelsCopy := make([]DiandiaoModel, len(model.Models))
  100. copy(modelsCopy, model.Models)
  101. return EViewMapModel{
  102. Models: modelsCopy,
  103. ModelKey: model.ModelKey,
  104. LastBatchUpdate: model.LastBatchUpdate,
  105. LastDeviceUpdate: model.LastDeviceUpdate,
  106. }, true
  107. }
  108. // UpdateSingleDevice 更新单设备数据
  109. func (em *ElectricModelManager) UpdateSingleDevice(model DiandiaoModel) {
  110. key := model.GenerateModelKey()
  111. em.Mutex.Lock()
  112. defer em.Mutex.Unlock()
  113. if viewMapModel, exists := em.Models[key]; exists {
  114. // 查找是否已存在该设备
  115. found := false
  116. for i, existingModel := range viewMapModel.Models {
  117. if existingModel.EqpmtStrID == model.EqpmtStrID {
  118. viewMapModel.Models[i] = model
  119. found = true
  120. break
  121. }
  122. }
  123. // 如果未找到该设备,则添加新设备
  124. if !found {
  125. viewMapModel.Models = append(viewMapModel.Models, model)
  126. }
  127. viewMapModel.LastDeviceUpdate = time.Now()
  128. em.Models[key] = viewMapModel
  129. } else {
  130. // 如果不存在该图元,则创建新的
  131. em.Models[key] = EViewMapModel{
  132. Models: []DiandiaoModel{model},
  133. ModelKey: key,
  134. LastBatchUpdate: time.Time{},
  135. LastDeviceUpdate: time.Now(),
  136. }
  137. }
  138. }
  139. // RegisterClient 注册客户端连接
  140. func (em *ElectricModelManager) RegisterClient(clientID string) {
  141. em.Mutex.Lock()
  142. defer em.Mutex.Unlock()
  143. em.ClientLastAccess[clientID] = time.Now()
  144. if _, exists := em.ClientData[clientID]; !exists {
  145. em.ClientData[clientID] = make(map[string]string)
  146. }
  147. }
  148. // ShouldSendFullData 判断是否应该发送全量数据
  149. func (em *ElectricModelManager) ShouldSendFullData(intervalSeconds int) bool {
  150. em.Mutex.RLock()
  151. defer em.Mutex.RUnlock()
  152. return time.Since(em.ClientLastFullData) >= time.Duration(intervalSeconds)*time.Second
  153. }
  154. // UpdateFullDataTimestamp 更新全量数据发送时间戳
  155. func (em *ElectricModelManager) UpdateFullDataTimestamp() {
  156. em.Mutex.Lock()
  157. defer em.Mutex.Unlock()
  158. em.ClientLastFullData = time.Now()
  159. }
  160. // CompareWithClientData 比较当前数据与客户端数据的差异
  161. func (em *ElectricModelManager) CompareWithClientData(clientID string, currentData map[string]string) map[string]string {
  162. em.Mutex.RLock()
  163. defer em.Mutex.RUnlock()
  164. clientData, exists := em.ClientData[clientID]
  165. if !exists {
  166. // 客户端尚未注册或无历史数据,返回全部当前数据
  167. return currentData
  168. }
  169. changedData := make(map[string]string)
  170. for id, value := range currentData {
  171. if clientValue, ok := clientData[id]; !ok || clientValue != value {
  172. changedData[id] = value
  173. }
  174. }
  175. return changedData
  176. }
  177. // UpdateClientData 更新客户端数据记录
  178. func (em *ElectricModelManager) UpdateClientData(clientID string, data map[string]string) {
  179. em.Mutex.Lock()
  180. defer em.Mutex.Unlock()
  181. em.ClientData[clientID] = data
  182. em.ClientLastAccess[clientID] = time.Now()
  183. }
  184. // cleanupInactiveClients 定期清理长时间未访问的客户端数据
  185. func (em *ElectricModelManager) cleanupInactiveClients() {
  186. ticker := time.NewTicker(1 * time.Minute)
  187. defer ticker.Stop()
  188. for {
  189. select {
  190. case <-ticker.C:
  191. em.Mutex.Lock()
  192. now := time.Now()
  193. for clientID, lastAccess := range em.ClientLastAccess {
  194. // 如果客户端超过5分钟未访问,则清理其数据
  195. if now.Sub(lastAccess) > 5*time.Minute {
  196. delete(em.ClientData, clientID)
  197. delete(em.ClientLastAccess, clientID)
  198. }
  199. }
  200. em.Mutex.Unlock()
  201. }
  202. }
  203. }