Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

296 строки
8.0 KiB

  1. package appcontext
  2. import (
  3. "fmt"
  4. "maps"
  5. "strings"
  6. "time"
  7. "github.com/AFASystems/presence/internal/pkg/model"
  8. "github.com/mitchellh/mapstructure"
  9. "github.com/segmentio/kafka-go"
  10. )
  11. // AppState provides centralized access to application state
  12. type AppState struct {
  13. beacons model.BeaconsList
  14. httpResults model.HTTPResultList
  15. settings model.Settings
  16. beaconEvents model.BeaconEventList
  17. beaconsLookup map[string]string
  18. latestList model.LatestBeaconsList
  19. kafkaReadersList model.KafkaReadersList
  20. kafkaWritersList model.KafkaWritersList
  21. }
  22. // NewAppState creates a new application context AppState with default values
  23. func NewAppState() *AppState {
  24. return &AppState{
  25. beacons: model.BeaconsList{
  26. Beacons: make(map[string]model.Beacon),
  27. },
  28. httpResults: model.HTTPResultList{
  29. Results: make(map[string]model.HTTPResult),
  30. },
  31. settings: model.Settings{
  32. ID: 1,
  33. CurrentAlgorithm: "filter", // possible values filter or AI
  34. LocationConfidence: 4,
  35. LastSeenThreshold: 15,
  36. BeaconMetricSize: 30,
  37. HASendInterval: 5,
  38. HASendChangesOnly: false,
  39. RSSIEnforceThreshold: false,
  40. RSSIMinThreshold: 100,
  41. },
  42. beaconEvents: model.BeaconEventList{
  43. Beacons: make(map[string]model.BeaconEvent),
  44. },
  45. beaconsLookup: make(map[string]string),
  46. latestList: model.LatestBeaconsList{
  47. LatestList: make(map[string]model.Beacon),
  48. },
  49. kafkaReadersList: model.KafkaReadersList{
  50. KafkaReaders: make([]*kafka.Reader, 0),
  51. },
  52. kafkaWritersList: model.KafkaWritersList{
  53. KafkaWriters: make([]*kafka.Writer, 0),
  54. },
  55. }
  56. }
  57. func (m *AppState) AddKafkaWriter(kafkaUrl, topic string) *kafka.Writer {
  58. kafkaWriter := &kafka.Writer{
  59. Addr: kafka.TCP(kafkaUrl),
  60. Topic: topic,
  61. Balancer: &kafka.LeastBytes{},
  62. Async: false,
  63. RequiredAcks: kafka.RequireAll,
  64. BatchSize: 100,
  65. BatchTimeout: 10 * time.Millisecond,
  66. }
  67. m.kafkaWritersList.KafkaWritersLock.Lock()
  68. m.kafkaWritersList.KafkaWriters = append(m.kafkaWritersList.KafkaWriters, kafkaWriter)
  69. m.kafkaWritersList.KafkaWritersLock.Unlock()
  70. return kafkaWriter
  71. }
  72. func (m *AppState) CleanKafkaWriters() {
  73. fmt.Println("shutdown of kafka readers starts")
  74. for _, r := range m.kafkaWritersList.KafkaWriters {
  75. if err := r.Close(); err != nil {
  76. fmt.Printf("Error in closing kafka writer %v", err)
  77. }
  78. }
  79. fmt.Println("Kafka writers graceful shutdown complete")
  80. }
  81. func (m *AppState) AddKafkaReader(kafkaUrl, topic, groupID string) *kafka.Reader {
  82. brokers := strings.Split(kafkaUrl, ",")
  83. kafkaReader := kafka.NewReader(kafka.ReaderConfig{
  84. Brokers: brokers,
  85. GroupID: groupID,
  86. Topic: topic,
  87. MinBytes: 1,
  88. MaxBytes: 10e6,
  89. })
  90. m.kafkaReadersList.KafkaReadersLock.Lock()
  91. m.kafkaReadersList.KafkaReaders = append(m.kafkaReadersList.KafkaReaders, kafkaReader)
  92. m.kafkaReadersList.KafkaReadersLock.Unlock()
  93. return kafkaReader
  94. }
  95. func (m *AppState) CleanKafkaReaders() {
  96. for _, r := range m.kafkaReadersList.KafkaReaders {
  97. if err := r.Close(); err != nil {
  98. fmt.Printf("Error in closing kafka reader %v", err)
  99. }
  100. }
  101. fmt.Println("Kafka readers graceful shutdown complete")
  102. }
  103. // GetBeacons returns thread-safe access to beacons list
  104. func (m *AppState) GetBeacons() *model.BeaconsList {
  105. return &m.beacons
  106. }
  107. // GetSettings returns thread-safe access to settings
  108. func (m *AppState) GetSettings() *model.Settings {
  109. return &m.settings
  110. }
  111. // GetBeaconEvents returns thread-safe access to beacon events
  112. func (m *AppState) GetBeaconEvents() *model.BeaconEventList {
  113. return &m.beaconEvents
  114. }
  115. // GetBeaconsLookup returns thread-safe access to beacon lookup map
  116. func (m *AppState) GetBeaconsLookup() map[string]string {
  117. return m.beaconsLookup
  118. }
  119. // GetLatestList returns thread-safe access to latest beacons list
  120. func (m *AppState) GetLatestList() *model.LatestBeaconsList {
  121. return &m.latestList
  122. }
  123. // AddBeaconToLookup adds a beacon ID to the lookup map
  124. func (m *AppState) AddBeaconToLookup(id, value string) {
  125. m.beaconsLookup[id] = value
  126. }
  127. // RemoveBeaconFromLookup removes a beacon ID from the lookup map
  128. func (m *AppState) RemoveBeaconFromLookup(id string) {
  129. delete(m.beaconsLookup, id)
  130. }
  131. func (m *AppState) CleanLookup() {
  132. clear(m.beaconsLookup)
  133. }
  134. func (m *AppState) RemoveBeacon(id string) {
  135. m.beacons.Lock.Lock()
  136. delete(m.beacons.Beacons, id)
  137. m.beacons.Lock.Unlock()
  138. }
  139. func (m *AppState) RemoveHTTPResult(id string) {
  140. m.httpResults.Lock.Lock()
  141. delete(m.httpResults.Results, id)
  142. m.httpResults.Lock.Unlock()
  143. }
  144. // BeaconExists checks if a beacon exists in the lookup
  145. func (m *AppState) BeaconExists(id string) (string, bool) {
  146. val, exists := m.beaconsLookup[id]
  147. return val, exists
  148. }
  149. // GetBeacon returns a beacon by ID (thread-safe)
  150. func (m *AppState) GetBeacon(id string) (model.Beacon, bool) {
  151. m.beacons.Lock.RLock()
  152. defer m.beacons.Lock.RUnlock()
  153. beacon, exists := m.beacons.Beacons[id]
  154. return beacon, exists
  155. }
  156. // GetHTTPResult returns a beacon from HTTP results by ID (thread-safe)
  157. func (m *AppState) GetHTTPResult(id string) (model.HTTPResult, bool) {
  158. m.httpResults.Lock.RLock()
  159. defer m.httpResults.Lock.RUnlock()
  160. beacon, exists := m.httpResults.Results[id]
  161. return beacon, exists
  162. }
  163. // UpdateHTTPResult updates a beacon in the list (thread-safe)
  164. func (m *AppState) UpdateHTTPResult(id string, beacon model.HTTPResult) {
  165. m.httpResults.Lock.Lock()
  166. defer m.httpResults.Lock.Unlock()
  167. m.httpResults.Results[id] = beacon
  168. }
  169. // UpdateBeacon updates a beacon in the list (thread-safe)
  170. func (m *AppState) UpdateBeacon(id string, beacon model.Beacon) {
  171. m.beacons.Lock.Lock()
  172. defer m.beacons.Lock.Unlock()
  173. m.beacons.Beacons[id] = beacon
  174. }
  175. // GetBeaconEvent returns a beacon event by ID (thread-safe)
  176. func (m *AppState) GetBeaconEvent(id string) (model.BeaconEvent, bool) {
  177. m.beaconEvents.Lock.RLock()
  178. defer m.beaconEvents.Lock.RUnlock()
  179. event, exists := m.beaconEvents.Beacons[id]
  180. return event, exists
  181. }
  182. // UpdateBeaconEvent updates a beacon event in the list (thread-safe)
  183. func (m *AppState) UpdateBeaconEvent(id string, event model.BeaconEvent) {
  184. m.beaconEvents.Lock.Lock()
  185. defer m.beaconEvents.Lock.Unlock()
  186. m.beaconEvents.Beacons[id] = event
  187. }
  188. // GetLatestBeacon returns the latest beacon by ID (thread-safe)
  189. func (m *AppState) GetLatestBeacon(id string) (model.Beacon, bool) {
  190. m.latestList.Lock.RLock()
  191. defer m.latestList.Lock.RUnlock()
  192. beacon, exists := m.latestList.LatestList[id]
  193. return beacon, exists
  194. }
  195. // UpdateLatestBeacon updates the latest beacon in the list (thread-safe)
  196. func (m *AppState) UpdateLatestBeacon(id string, beacon model.Beacon) {
  197. m.latestList.Lock.Lock()
  198. defer m.latestList.Lock.Unlock()
  199. m.latestList.LatestList[id] = beacon
  200. }
  201. // GetAllBeacons returns a copy of all beacons
  202. func (m *AppState) GetAllBeacons() map[string]model.Beacon {
  203. m.beacons.Lock.RLock()
  204. defer m.beacons.Lock.RUnlock()
  205. beacons := make(map[string]model.Beacon)
  206. for id, beacon := range m.beacons.Beacons {
  207. beacons[id] = beacon
  208. }
  209. return beacons
  210. }
  211. // GetAllHttpResults returns a copy of all beacons
  212. func (m *AppState) GetAllHttpResults() map[string]model.HTTPResult {
  213. m.httpResults.Lock.RLock()
  214. defer m.httpResults.Lock.RUnlock()
  215. beacons := make(map[string]model.HTTPResult)
  216. for id, beacon := range m.httpResults.Results {
  217. beacons[id] = beacon
  218. }
  219. return beacons
  220. }
  221. // GetAllLatestBeacons returns a copy of all latest beacons
  222. func (m *AppState) GetAllLatestBeacons() map[string]model.Beacon {
  223. m.latestList.Lock.RLock()
  224. defer m.latestList.Lock.RUnlock()
  225. beacons := make(map[string]model.Beacon)
  226. maps.Copy(beacons, m.latestList.LatestList)
  227. return beacons
  228. }
  229. // GetBeaconCount returns the number of tracked beacons
  230. func (m *AppState) GetBeaconCount() int {
  231. m.beacons.Lock.RLock()
  232. defer m.beacons.Lock.RUnlock()
  233. return len(m.beacons.Beacons)
  234. }
  235. // GetSettingsValue returns current settings as a value
  236. func (m *AppState) GetSettingsValue() model.Settings {
  237. return m.settings
  238. }
  239. // UpdateSettings updates the system settings (thread-safe)
  240. func (m *AppState) UpdateSettings(settings map[string]any) {
  241. if err := mapstructure.Decode(settings, &m.settings); err != nil {
  242. fmt.Printf("Error in persisting settings: %v\n", err)
  243. }
  244. }