Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

224 Zeilen
5.7 KiB

  1. package appcontext
  2. import (
  3. "fmt"
  4. "log/slog"
  5. "os"
  6. "sync"
  7. "time"
  8. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  9. "github.com/mitchellh/mapstructure"
  10. )
  11. // AppState provides centralized access to application state
  12. type AppState struct {
  13. beacons BeaconsList
  14. settings Settings
  15. beaconEvents BeaconEventList
  16. beaconsLookup BeaconsLookup
  17. locationHealth LocationHealth
  18. decoderHealth DecoderHealth
  19. bridgeHealth BridgeHealth
  20. startTime time.Time
  21. }
  22. func getEnv(key, def string) string {
  23. if v := os.Getenv(key); v != "" {
  24. return v
  25. }
  26. return def
  27. }
  28. // NewAppState creates a new application context AppState with default values
  29. func NewAppState() *AppState {
  30. return &AppState{
  31. startTime: time.Now(),
  32. beacons: BeaconsList{
  33. Beacons: make(map[string]Beacon),
  34. },
  35. settings: Settings{
  36. ID: 1,
  37. CurrentAlgorithm: getEnv("ALGORITHM", "filter"),
  38. LocationConfidence: 4,
  39. LastSeenThreshold: 15,
  40. BeaconMetricSize: 30,
  41. HASendInterval: 5,
  42. HASendChangesOnly: false,
  43. RSSIEnforceThreshold: false,
  44. RSSIMinThreshold: 100,
  45. },
  46. beaconEvents: BeaconEventList{
  47. Beacons: make(map[string]BeaconEvent),
  48. },
  49. beaconsLookup: BeaconsLookup{
  50. Lookup: make(map[string]string),
  51. },
  52. locationHealth: LocationHealth{
  53. BaseHealth: BaseHealth{
  54. Lock: sync.RWMutex{},
  55. Uptime: 0,
  56. ActiveReaders: []string{},
  57. ActiveWriters: []string{},
  58. ActiveBeacons: []string{},
  59. },
  60. },
  61. decoderHealth: DecoderHealth{
  62. BaseHealth: BaseHealth{
  63. Lock: sync.RWMutex{},
  64. Uptime: 0,
  65. ActiveReaders: []string{},
  66. ActiveWriters: []string{},
  67. ActiveBeacons: []string{},
  68. },
  69. },
  70. bridgeHealth: BridgeHealth{
  71. BaseHealth: BaseHealth{
  72. Lock: sync.RWMutex{},
  73. Uptime: 0,
  74. ActiveReaders: []string{},
  75. ActiveWriters: []string{},
  76. ActiveBeacons: []string{},
  77. },
  78. },
  79. }
  80. }
  81. func (m *AppState) GetLocationHealth(k *kafkaclient.KafkaManager) *LocationHealth {
  82. m.locationHealth.GetUptime(m.startTime)
  83. m.locationHealth.GetActiveReaders(k)
  84. m.locationHealth.GetActiveWriters(k)
  85. m.locationHealth.GetActiveBeacons(m)
  86. return &m.locationHealth
  87. }
  88. func (m *AppState) GetDecoderHealth(k *kafkaclient.KafkaManager) *DecoderHealth {
  89. m.decoderHealth.GetUptime(m.startTime)
  90. m.decoderHealth.GetActiveReaders(k)
  91. m.decoderHealth.GetActiveWriters(k)
  92. m.decoderHealth.GetActiveBeacons(m)
  93. return &m.decoderHealth
  94. }
  95. func (m *AppState) GetBridgeHealth(k *kafkaclient.KafkaManager) *BridgeHealth {
  96. m.bridgeHealth.GetUptime(m.startTime)
  97. m.bridgeHealth.GetActiveReaders(k)
  98. m.bridgeHealth.GetActiveWriters(k)
  99. m.bridgeHealth.GetActiveBeacons(m)
  100. return &m.bridgeHealth
  101. }
  102. // GetBeacons returns thread-safe access to beacons list
  103. func (m *AppState) GetBeacons() *BeaconsList {
  104. m.beacons.Lock.RLock()
  105. defer m.beacons.Lock.RUnlock()
  106. return &m.beacons
  107. }
  108. // GetSettings returns thread-safe access to settings
  109. func (m *AppState) GetSettings() *Settings {
  110. return &m.settings
  111. }
  112. // GetBeaconEvents returns thread-safe access to beacon events
  113. func (m *AppState) GetBeaconEvents() *BeaconEventList {
  114. m.beaconEvents.Lock.RLock()
  115. defer m.beaconEvents.Lock.RUnlock()
  116. return &m.beaconEvents
  117. }
  118. // AddBeaconToLookup adds a beacon ID to the lookup map
  119. func (m *AppState) AddBeaconToLookup(id, value string) {
  120. m.beaconsLookup.Lock.Lock()
  121. m.beaconsLookup.Lookup[id] = value
  122. m.beaconsLookup.Lock.Unlock()
  123. }
  124. // RemoveBeaconFromLookup removes a beacon ID from the lookup map
  125. func (m *AppState) RemoveBeaconFromLookup(id string) {
  126. m.beaconsLookup.Lock.Lock()
  127. delete(m.beaconsLookup.Lookup, id)
  128. m.beaconsLookup.Lock.Unlock()
  129. }
  130. func (m *AppState) CleanLookup() {
  131. m.beaconsLookup.Lock.Lock()
  132. clear(m.beaconsLookup.Lookup)
  133. m.beaconsLookup.Lock.Unlock()
  134. }
  135. // BeaconExists checks if a beacon exists in the lookup
  136. func (m *AppState) BeaconExists(id string) (string, bool) {
  137. m.beaconsLookup.Lock.RLock()
  138. defer m.beaconsLookup.Lock.RUnlock()
  139. val, exists := m.beaconsLookup.Lookup[id]
  140. return val, exists
  141. }
  142. // GetBeacon returns a beacon by ID (thread-safe)
  143. func (m *AppState) GetBeacon(id string) (Beacon, bool) {
  144. m.beacons.Lock.RLock()
  145. defer m.beacons.Lock.RUnlock()
  146. beacon, exists := m.beacons.Beacons[id]
  147. return beacon, exists
  148. }
  149. // UpdateBeacon updates a beacon in the list (thread-safe)
  150. func (m *AppState) UpdateBeacon(id string, beacon Beacon) {
  151. m.beacons.Lock.Lock()
  152. defer m.beacons.Lock.Unlock()
  153. m.beacons.Beacons[id] = beacon
  154. }
  155. // GetBeaconEvent returns a beacon event by ID (thread-safe)
  156. func (m *AppState) GetBeaconEvent(id string) (BeaconEvent, bool) {
  157. m.beaconEvents.Lock.RLock()
  158. defer m.beaconEvents.Lock.RUnlock()
  159. event, exists := m.beaconEvents.Beacons[id]
  160. return event, exists
  161. }
  162. // UpdateBeaconEvent updates a beacon event in the list (thread-safe)
  163. func (m *AppState) UpdateBeaconEvent(id string, event BeaconEvent) {
  164. m.beaconEvents.Lock.Lock()
  165. defer m.beaconEvents.Lock.Unlock()
  166. m.beaconEvents.Beacons[id] = event
  167. }
  168. // GetAllBeacons returns a copy of all beacons
  169. func (m *AppState) GetAllBeacons() map[string]Beacon {
  170. m.beacons.Lock.RLock()
  171. defer m.beacons.Lock.RUnlock()
  172. beacons := make(map[string]Beacon)
  173. for id, beacon := range m.beacons.Beacons {
  174. beacons[id] = beacon
  175. }
  176. return beacons
  177. }
  178. // GetBeaconCount returns the number of tracked beacons
  179. func (m *AppState) GetBeaconCount() int {
  180. m.beacons.Lock.RLock()
  181. defer m.beacons.Lock.RUnlock()
  182. return len(m.beacons.Beacons)
  183. }
  184. // GetSettingsValue returns current settings as a value
  185. func (m *AppState) GetSettingsValue() Settings {
  186. return m.settings
  187. }
  188. // UpdateSettings updates the system settings (thread-safe)
  189. func (m *AppState) UpdateSettings(settings map[string]any) {
  190. if err := mapstructure.Decode(settings, &m.settings); err != nil {
  191. msg := fmt.Sprintf("Error in persisting settings: %v", err)
  192. slog.Error(msg)
  193. }
  194. }