Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

251 linhas
6.7 KiB

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