Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

200 строки
5.0 KiB

  1. package main
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "log/slog"
  7. "os/signal"
  8. "sync"
  9. "syscall"
  10. "time"
  11. "github.com/AFASystems/presence/internal/pkg/common/appcontext"
  12. "github.com/AFASystems/presence/internal/pkg/common/utils"
  13. "github.com/AFASystems/presence/internal/pkg/config"
  14. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  15. "github.com/AFASystems/presence/internal/pkg/logger"
  16. "github.com/AFASystems/presence/internal/pkg/model"
  17. "github.com/segmentio/kafka-go"
  18. )
  19. var wg sync.WaitGroup
  20. func main() {
  21. // Load global context to init beacons and latest list
  22. appState := appcontext.NewAppState()
  23. cfg := config.Load()
  24. kafkaManager := kafkaclient.InitKafkaManager()
  25. // Set logger -> terminal and log file
  26. slog.SetDefault(logger.CreateLogger("location.log"))
  27. // Define context
  28. ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
  29. defer stop()
  30. readerTopics := []string{"rawbeacons", "settings"}
  31. kafkaManager.PopulateKafkaManager(cfg.KafkaURL, "location", readerTopics)
  32. writerTopics := []string{"locevents"}
  33. kafkaManager.PopulateKafkaManager(cfg.KafkaURL, "", writerTopics)
  34. slog.Info("Locations algorithm initialized, subscribed to Kafka topics")
  35. locTicker := time.NewTicker(1 * time.Second)
  36. defer locTicker.Stop()
  37. chRaw := make(chan model.BeaconAdvertisement, 2000)
  38. chSettings := make(chan map[string]any, 5)
  39. wg.Add(3)
  40. go kafkaclient.Consume(kafkaManager.GetReader("rawbeacons"), chRaw, ctx, &wg)
  41. go kafkaclient.Consume(kafkaManager.GetReader("settings"), chSettings, ctx, &wg)
  42. eventLoop:
  43. for {
  44. select {
  45. case <-ctx.Done():
  46. break eventLoop
  47. case <-locTicker.C:
  48. settings := appState.GetSettings()
  49. fmt.Printf("Settings: %+v\n", settings)
  50. switch settings.CurrentAlgorithm {
  51. case "filter":
  52. getLikelyLocations(appState, kafkaManager.GetWriter("locevents"))
  53. case "ai":
  54. fmt.Println("AI algorithm selected")
  55. }
  56. case msg := <-chRaw:
  57. assignBeaconToList(msg, appState)
  58. case msg := <-chSettings:
  59. fmt.Printf("settings msg: %+v\n", msg)
  60. appState.UpdateSettings(msg)
  61. }
  62. }
  63. slog.Info("broken out of the main event loop")
  64. wg.Wait()
  65. slog.Info("All go routines have stopped, Beggining to close Kafka connections")
  66. kafkaManager.CleanKafkaReaders()
  67. kafkaManager.CleanKafkaWriters()
  68. }
  69. func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) {
  70. beacons := appState.GetAllBeacons()
  71. settings := appState.GetSettingsValue()
  72. for _, beacon := range beacons {
  73. // Shrinking the model because other properties have nothing to do with the location
  74. r := model.HTTPLocation{
  75. Method: "Standard",
  76. Distance: 999,
  77. ID: beacon.ID,
  78. Location: "",
  79. LastSeen: 999,
  80. }
  81. mSize := len(beacon.BeaconMetrics)
  82. if (int64(time.Now().Unix()) - (beacon.BeaconMetrics[mSize-1].Timestamp)) > settings.LastSeenThreshold {
  83. slog.Warn("beacon is too old")
  84. continue
  85. }
  86. locList := make(map[string]float64)
  87. seenW := 1.5
  88. rssiW := 0.75
  89. for _, metric := range beacon.BeaconMetrics {
  90. res := seenW + (rssiW * (1.0 - (float64(metric.RSSI) / -100.0)))
  91. locList[metric.Location] += res
  92. }
  93. bestLocName := ""
  94. maxScore := 0.0
  95. for locName, score := range locList {
  96. if score > maxScore {
  97. maxScore = score
  98. bestLocName = locName
  99. }
  100. }
  101. if bestLocName == beacon.PreviousLocation {
  102. beacon.LocationConfidence++
  103. } else {
  104. beacon.LocationConfidence = 0
  105. }
  106. r.Distance = beacon.BeaconMetrics[mSize-1].Distance
  107. r.Location = bestLocName
  108. r.LastSeen = beacon.BeaconMetrics[mSize-1].Timestamp
  109. if beacon.LocationConfidence == settings.LocationConfidence && beacon.PreviousConfidentLocation != bestLocName {
  110. beacon.LocationConfidence = 0
  111. }
  112. beacon.PreviousLocation = bestLocName
  113. appState.UpdateBeacon(beacon.ID, beacon)
  114. js, err := json.Marshal(r)
  115. if err != nil {
  116. eMsg := fmt.Sprintf("Error in marshaling location: %v", err)
  117. slog.Error(eMsg)
  118. continue
  119. }
  120. msg := kafka.Message{
  121. Value: js,
  122. }
  123. err = writer.WriteMessages(context.Background(), msg)
  124. if err != nil {
  125. eMsg := fmt.Sprintf("Error in sending Kafka message: %v", err)
  126. slog.Error(eMsg)
  127. }
  128. }
  129. }
  130. func assignBeaconToList(adv model.BeaconAdvertisement, appState *appcontext.AppState) {
  131. id := adv.ID
  132. now := time.Now().Unix()
  133. settings := appState.GetSettingsValue()
  134. if settings.RSSIEnforceThreshold && (int64(adv.RSSI) < settings.RSSIMinThreshold) {
  135. slog.Info("Settings returns")
  136. return
  137. }
  138. beacon, ok := appState.GetBeacon(id)
  139. if !ok {
  140. beacon = model.Beacon{
  141. ID: id,
  142. }
  143. }
  144. beacon.IncomingJSON = adv
  145. beacon.LastSeen = now
  146. if beacon.BeaconMetrics == nil {
  147. beacon.BeaconMetrics = make([]model.BeaconMetric, 0, settings.BeaconMetricSize)
  148. }
  149. metric := model.BeaconMetric{
  150. Distance: utils.CalculateDistance(adv),
  151. Timestamp: now,
  152. RSSI: int64(adv.RSSI),
  153. Location: adv.Hostname,
  154. }
  155. if len(beacon.BeaconMetrics) >= settings.BeaconMetricSize {
  156. copy(beacon.BeaconMetrics, beacon.BeaconMetrics[1:])
  157. beacon.BeaconMetrics[settings.BeaconMetricSize-1] = metric
  158. } else {
  159. beacon.BeaconMetrics = append(beacon.BeaconMetrics, metric)
  160. }
  161. appState.UpdateBeacon(id, beacon)
  162. }