Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 

272 рядки
7.2 KiB

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