|
- package appcontext
-
- import (
- "fmt"
- "log/slog"
- "os"
- "sync"
- "time"
-
- "github.com/AFASystems/presence/internal/pkg/kafkaclient"
- "github.com/mitchellh/mapstructure"
- )
-
- // AppState provides centralized access to application state
- type AppState struct {
- beacons BeaconsList
- settings Settings
- beaconEvents BeaconEventList
- beaconsLookup BeaconsLookup
- locationHealth LocationHealth
- decoderHealth DecoderHealth
- bridgeHealth BridgeHealth
- startTime time.Time
- }
-
- func getEnv(key, def string) string {
- if v := os.Getenv(key); v != "" {
- return v
- }
- return def
- }
-
- // NewAppState creates a new application context AppState with default values
- func NewAppState() *AppState {
- return &AppState{
- startTime: time.Now(),
- beacons: BeaconsList{
- Beacons: make(map[string]Beacon),
- },
- settings: Settings{
- ID: 1,
- CurrentAlgorithm: getEnv("ALGORITHM", "filter"),
- LocationConfidence: 4,
- LastSeenThreshold: 15,
- BeaconMetricSize: 30,
- HASendInterval: 5,
- HASendChangesOnly: false,
- RSSIEnforceThreshold: false,
- RSSIMinThreshold: 100,
- },
- beaconEvents: BeaconEventList{
- Beacons: make(map[string]BeaconEvent),
- },
- beaconsLookup: BeaconsLookup{
- Lookup: make(map[string]string),
- },
- locationHealth: LocationHealth{
- BaseHealth: BaseHealth{
- Lock: sync.RWMutex{},
- Uptime: 0,
- ActiveReaders: []string{},
- ActiveWriters: []string{},
- ActiveBeacons: []string{},
- },
- },
- decoderHealth: DecoderHealth{
- BaseHealth: BaseHealth{
- Lock: sync.RWMutex{},
- Uptime: 0,
- ActiveReaders: []string{},
- ActiveWriters: []string{},
- ActiveBeacons: []string{},
- },
- },
- bridgeHealth: BridgeHealth{
- BaseHealth: BaseHealth{
- Lock: sync.RWMutex{},
- Uptime: 0,
- ActiveReaders: []string{},
- ActiveWriters: []string{},
- ActiveBeacons: []string{},
- },
- },
- }
- }
-
- func (m *AppState) GetLocationHealth(k *kafkaclient.KafkaManager) *LocationHealth {
- m.locationHealth.GetUptime(m.startTime)
- m.locationHealth.GetActiveReaders(k)
- m.locationHealth.GetActiveWriters(k)
- m.locationHealth.GetActiveBeacons(m)
- return &m.locationHealth
- }
-
- func (m *AppState) GetDecoderHealth(k *kafkaclient.KafkaManager) *DecoderHealth {
- m.decoderHealth.GetUptime(m.startTime)
- m.decoderHealth.GetActiveReaders(k)
- m.decoderHealth.GetActiveWriters(k)
- m.decoderHealth.GetActiveBeacons(m)
- return &m.decoderHealth
- }
-
- func (m *AppState) GetBridgeHealth(k *kafkaclient.KafkaManager) *BridgeHealth {
- m.bridgeHealth.GetUptime(m.startTime)
- m.bridgeHealth.GetActiveReaders(k)
- m.bridgeHealth.GetActiveWriters(k)
- m.bridgeHealth.GetActiveBeacons(m)
- return &m.bridgeHealth
- }
-
- // GetBeacons returns thread-safe access to beacons list
- func (m *AppState) GetBeacons() *BeaconsList {
- m.beacons.Lock.RLock()
- defer m.beacons.Lock.RUnlock()
- return &m.beacons
- }
-
- // GetSettings returns thread-safe access to settings
- func (m *AppState) GetSettings() *Settings {
- return &m.settings
- }
-
- // GetBeaconEvents returns thread-safe access to beacon events
- func (m *AppState) GetBeaconEvents() *BeaconEventList {
- m.beaconEvents.Lock.RLock()
- defer m.beaconEvents.Lock.RUnlock()
- return &m.beaconEvents
- }
-
- // AddBeaconToLookup adds a beacon ID to the lookup map
- func (m *AppState) AddBeaconToLookup(id, value string) {
- m.beaconsLookup.Lock.Lock()
- m.beaconsLookup.Lookup[id] = value
- m.beaconsLookup.Lock.Unlock()
- }
-
- // RemoveBeaconFromLookup removes a beacon ID from the lookup map
- func (m *AppState) RemoveBeaconFromLookup(id string) {
- m.beaconsLookup.Lock.Lock()
- delete(m.beaconsLookup.Lookup, id)
- m.beaconsLookup.Lock.Unlock()
- }
-
- func (m *AppState) CleanLookup() {
- m.beaconsLookup.Lock.Lock()
- clear(m.beaconsLookup.Lookup)
- m.beaconsLookup.Lock.Unlock()
- }
-
- // BeaconExists checks if a beacon exists in the lookup
- func (m *AppState) BeaconExists(id string) (string, bool) {
- m.beaconsLookup.Lock.RLock()
- defer m.beaconsLookup.Lock.RUnlock()
- val, exists := m.beaconsLookup.Lookup[id]
- return val, exists
- }
-
- // GetBeacon returns a beacon by ID (thread-safe)
- func (m *AppState) GetBeacon(id string) (Beacon, bool) {
- m.beacons.Lock.RLock()
- defer m.beacons.Lock.RUnlock()
-
- beacon, exists := m.beacons.Beacons[id]
- return beacon, exists
- }
-
- // UpdateBeacon updates a beacon in the list (thread-safe)
- func (m *AppState) UpdateBeacon(id string, beacon Beacon) {
- m.beacons.Lock.Lock()
- defer m.beacons.Lock.Unlock()
-
- m.beacons.Beacons[id] = beacon
- }
-
- // GetBeaconEvent returns a beacon event by ID (thread-safe)
- func (m *AppState) GetBeaconEvent(id string) (BeaconEvent, bool) {
- m.beaconEvents.Lock.RLock()
- defer m.beaconEvents.Lock.RUnlock()
-
- event, exists := m.beaconEvents.Beacons[id]
- return event, exists
- }
-
- // UpdateBeaconEvent updates a beacon event in the list (thread-safe)
- func (m *AppState) UpdateBeaconEvent(id string, event BeaconEvent) {
- m.beaconEvents.Lock.Lock()
- defer m.beaconEvents.Lock.Unlock()
-
- m.beaconEvents.Beacons[id] = event
- }
-
- // GetAllBeacons returns a copy of all beacons
- func (m *AppState) GetAllBeacons() map[string]Beacon {
- m.beacons.Lock.RLock()
- defer m.beacons.Lock.RUnlock()
-
- beacons := make(map[string]Beacon)
- for id, beacon := range m.beacons.Beacons {
- beacons[id] = beacon
- }
- return beacons
- }
-
- // GetBeaconCount returns the number of tracked beacons
- func (m *AppState) GetBeaconCount() int {
- m.beacons.Lock.RLock()
- defer m.beacons.Lock.RUnlock()
-
- return len(m.beacons.Beacons)
- }
-
- // GetSettingsValue returns current settings as a value
- func (m *AppState) GetSettingsValue() Settings {
- return m.settings
- }
-
- // UpdateSettings updates the system settings (thread-safe)
- func (m *AppState) UpdateSettings(settings map[string]any) {
- if err := mapstructure.Decode(settings, &m.settings); err != nil {
- msg := fmt.Sprintf("Error in persisting settings: %v", err)
- slog.Error(msg)
- }
- }
|