您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

256 行
6.4 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. health Health
  18. startTime time.Time
  19. mu sync.RWMutex
  20. }
  21. func getEnv(key, def string) string {
  22. if v := os.Getenv(key); v != "" {
  23. return v
  24. }
  25. return def
  26. }
  27. // NewAppState creates a new application context AppState with default values
  28. func NewAppState() *AppState {
  29. return &AppState{
  30. startTime: time.Now(),
  31. beacons: BeaconsList{
  32. Beacons: make(map[string]Beacon),
  33. },
  34. settings: Settings{
  35. ID: 1,
  36. CurrentAlgorithm: getEnv("ALGORITHM", "filter"),
  37. LocationConfidence: 4,
  38. LastSeenThreshold: 15,
  39. BeaconMetricSize: 30,
  40. HASendInterval: 5,
  41. HASendChangesOnly: false,
  42. RSSIEnforceThreshold: false,
  43. RSSIMinThreshold: 100,
  44. },
  45. beaconEvents: BeaconEventList{
  46. Beacons: make(map[string]BeaconEvent),
  47. },
  48. beaconsLookup: BeaconsLookup{
  49. Lookup: make(map[string]string),
  50. },
  51. health: Health{
  52. Location: LocationHealth{
  53. BaseHealth: BaseHealth{
  54. Uptime: 0,
  55. ActiveReaders: []string{},
  56. ActiveWriters: []string{},
  57. ActiveBeacons: []string{},
  58. },
  59. },
  60. Decoder: DecoderHealth{
  61. BaseHealth: BaseHealth{
  62. Uptime: 0,
  63. ActiveReaders: []string{},
  64. ActiveWriters: []string{},
  65. ActiveBeacons: []string{},
  66. },
  67. },
  68. Bridge: BridgeHealth{
  69. BaseHealth: BaseHealth{
  70. Uptime: 0,
  71. ActiveReaders: []string{},
  72. ActiveWriters: []string{},
  73. ActiveBeacons: []string{},
  74. },
  75. },
  76. Kafka: ServiceStatus{Status: "unknown"},
  77. Database: ServiceStatus{Status: "unknown"},
  78. },
  79. }
  80. }
  81. func (m *AppState) GetHealth() Health {
  82. m.mu.RLock()
  83. defer m.mu.RUnlock()
  84. return m.health
  85. }
  86. func (m *AppState) UpdateLocationHealth(h LocationHealth) {
  87. m.mu.Lock()
  88. m.health.Location = h
  89. m.mu.Unlock()
  90. }
  91. func (m *AppState) UpdateDecoderHealth(h DecoderHealth) {
  92. m.mu.Lock()
  93. m.health.Decoder = h
  94. m.mu.Unlock()
  95. }
  96. func (m *AppState) UpdateBridgeHealth(h BridgeHealth) {
  97. m.mu.Lock()
  98. m.health.Bridge = h
  99. m.mu.Unlock()
  100. }
  101. // UpdateServerHealth updates Kafka and database status (called by server after checking broker and DB).
  102. func (m *AppState) UpdateServerHealth(kafka, database ServiceStatus) {
  103. m.mu.Lock()
  104. m.health.Kafka = kafka
  105. m.health.Database = database
  106. m.mu.Unlock()
  107. }
  108. func (m *AppState) GetLocationHealth(k *kafkaclient.KafkaManager) ([]byte, error) {
  109. m.health.Location.GetUptime(m.startTime)
  110. m.health.Location.GetActiveReaders(k)
  111. m.health.Location.GetActiveWriters(k)
  112. m.health.Location.GetActiveBeacons(m)
  113. return m.health.Location.Marshal()
  114. }
  115. func (m *AppState) GetDecoderHealth(k *kafkaclient.KafkaManager) ([]byte, error) {
  116. m.health.Decoder.GetUptime(m.startTime)
  117. m.health.Decoder.GetActiveReaders(k)
  118. m.health.Decoder.GetActiveWriters(k)
  119. m.health.Decoder.GetActiveBeacons(m)
  120. return m.health.Decoder.Marshal()
  121. }
  122. func (m *AppState) GetBridgeHealth(k *kafkaclient.KafkaManager) ([]byte, error) {
  123. m.health.Bridge.GetUptime(m.startTime)
  124. m.health.Bridge.GetActiveReaders(k)
  125. m.health.Bridge.GetActiveWriters(k)
  126. m.health.Bridge.GetActiveBeacons(m)
  127. return m.health.Bridge.Marshal()
  128. }
  129. // GetBeacons returns thread-safe access to beacons list
  130. func (m *AppState) GetBeacons() *BeaconsList {
  131. m.beacons.Lock.RLock()
  132. defer m.beacons.Lock.RUnlock()
  133. return &m.beacons
  134. }
  135. // GetSettings returns thread-safe access to settings
  136. func (m *AppState) GetSettings() *Settings {
  137. return &m.settings
  138. }
  139. // GetBeaconEvents returns thread-safe access to beacon events
  140. func (m *AppState) GetBeaconEvents() *BeaconEventList {
  141. m.beaconEvents.Lock.RLock()
  142. defer m.beaconEvents.Lock.RUnlock()
  143. return &m.beaconEvents
  144. }
  145. // AddBeaconToLookup adds a beacon ID to the lookup map
  146. func (m *AppState) AddBeaconToLookup(id, value string) {
  147. m.beaconsLookup.Lock.Lock()
  148. m.beaconsLookup.Lookup[id] = value
  149. m.beaconsLookup.Lock.Unlock()
  150. }
  151. // RemoveBeaconFromLookup removes a beacon ID from the lookup map
  152. func (m *AppState) RemoveBeaconFromLookup(id string) {
  153. m.beaconsLookup.Lock.Lock()
  154. delete(m.beaconsLookup.Lookup, id)
  155. m.beaconsLookup.Lock.Unlock()
  156. }
  157. func (m *AppState) CleanLookup() {
  158. m.beaconsLookup.Lock.Lock()
  159. clear(m.beaconsLookup.Lookup)
  160. m.beaconsLookup.Lock.Unlock()
  161. }
  162. // BeaconExists checks if a beacon exists in the lookup
  163. func (m *AppState) BeaconExists(id string) (string, bool) {
  164. m.beaconsLookup.Lock.RLock()
  165. defer m.beaconsLookup.Lock.RUnlock()
  166. val, exists := m.beaconsLookup.Lookup[id]
  167. return val, exists
  168. }
  169. // GetBeacon returns a beacon by ID (thread-safe)
  170. func (m *AppState) GetBeacon(id string) (Beacon, bool) {
  171. m.beacons.Lock.RLock()
  172. defer m.beacons.Lock.RUnlock()
  173. beacon, exists := m.beacons.Beacons[id]
  174. return beacon, exists
  175. }
  176. // UpdateBeacon updates a beacon in the list (thread-safe)
  177. func (m *AppState) UpdateBeacon(id string, beacon Beacon) {
  178. m.beacons.Lock.Lock()
  179. defer m.beacons.Lock.Unlock()
  180. m.beacons.Beacons[id] = beacon
  181. }
  182. // GetBeaconEvent returns a beacon event by ID (thread-safe)
  183. func (m *AppState) GetBeaconEvent(id string) (BeaconEvent, bool) {
  184. m.beaconEvents.Lock.RLock()
  185. defer m.beaconEvents.Lock.RUnlock()
  186. event, exists := m.beaconEvents.Beacons[id]
  187. return event, exists
  188. }
  189. // UpdateBeaconEvent updates a beacon event in the list (thread-safe)
  190. func (m *AppState) UpdateBeaconEvent(id string, event BeaconEvent) {
  191. m.beaconEvents.Lock.Lock()
  192. defer m.beaconEvents.Lock.Unlock()
  193. m.beaconEvents.Beacons[id] = event
  194. }
  195. // GetAllBeacons returns a copy of all beacons
  196. func (m *AppState) GetAllBeacons() map[string]Beacon {
  197. m.beacons.Lock.RLock()
  198. defer m.beacons.Lock.RUnlock()
  199. beacons := make(map[string]Beacon)
  200. for id, beacon := range m.beacons.Beacons {
  201. beacons[id] = beacon
  202. }
  203. return beacons
  204. }
  205. // GetBeaconCount returns the number of tracked beacons
  206. func (m *AppState) GetBeaconCount() int {
  207. m.beacons.Lock.RLock()
  208. defer m.beacons.Lock.RUnlock()
  209. return len(m.beacons.Beacons)
  210. }
  211. // GetSettingsValue returns current settings as a value
  212. func (m *AppState) GetSettingsValue() Settings {
  213. return m.settings
  214. }
  215. // UpdateSettings updates the system settings (thread-safe)
  216. func (m *AppState) UpdateSettings(settings map[string]any) {
  217. if err := mapstructure.Decode(settings, &m.settings); err != nil {
  218. msg := fmt.Sprintf("Error in persisting settings: %v", err)
  219. slog.Error(msg)
  220. }
  221. }