Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

226 lignes
5.7 KiB

  1. package main
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "log"
  8. "log/slog"
  9. "os"
  10. "os/signal"
  11. "sync"
  12. "syscall"
  13. "time"
  14. "github.com/AFASystems/presence/internal/pkg/common/appcontext"
  15. "github.com/AFASystems/presence/internal/pkg/common/utils"
  16. "github.com/AFASystems/presence/internal/pkg/config"
  17. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  18. "github.com/AFASystems/presence/internal/pkg/model"
  19. "github.com/segmentio/kafka-go"
  20. )
  21. var wg sync.WaitGroup
  22. func main() {
  23. // Load global context to init beacons and latest list
  24. appState := appcontext.NewAppState()
  25. cfg := config.Load()
  26. // Create log file
  27. logFile, err := os.OpenFile("server.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  28. if err != nil {
  29. log.Fatalf("Failed to open log file: %v\n", err)
  30. }
  31. // shell and log file multiwriter
  32. w := io.MultiWriter(os.Stderr, logFile)
  33. logger := slog.New(slog.NewJSONHandler(w, nil))
  34. slog.SetDefault(logger)
  35. // Define context
  36. ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
  37. defer stop()
  38. rawReader := appState.AddKafkaReader(cfg.KafkaURL, "rawbeacons", "gid-raw-loc")
  39. settingsReader := appState.AddKafkaReader(cfg.KafkaURL, "settings", "gid-settings-loc")
  40. writer := appState.AddKafkaWriter(cfg.KafkaURL, "locevents")
  41. slog.Info("Locations algorithm initialized, subscribed to Kafka topics")
  42. locTicker := time.NewTicker(1 * time.Second)
  43. defer locTicker.Stop()
  44. chRaw := make(chan model.BeaconAdvertisement, 2000)
  45. chSettings := make(chan model.SettingsVal, 5)
  46. wg.Add(3)
  47. go kafkaclient.Consume(rawReader, chRaw, ctx, &wg)
  48. go kafkaclient.Consume(settingsReader, chSettings, ctx, &wg)
  49. eventLoop:
  50. for {
  51. select {
  52. case <-ctx.Done():
  53. break eventLoop
  54. case <-locTicker.C:
  55. getLikelyLocations(appState, writer)
  56. case msg := <-chRaw:
  57. assignBeaconToList(msg, appState)
  58. case msg := <-chSettings:
  59. appState.UpdateSettings(msg)
  60. }
  61. }
  62. slog.Info("broken out of the main event loop")
  63. wg.Wait()
  64. slog.Info("All go routines have stopped, Beggining to close Kafka connections")
  65. appState.CleanKafkaReaders()
  66. appState.CleanKafkaWriters()
  67. }
  68. func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) {
  69. beacons := appState.GetAllBeacons()
  70. settings := appState.GetSettingsValue()
  71. for _, beacon := range beacons {
  72. fmt.Println("id: ", beacon.ID)
  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. // js, err := json.Marshal(model.LocationChange{
  112. // Method: "LocationChange",
  113. // BeaconRef: beacon,
  114. // Name: beacon.Name,
  115. // PreviousLocation: beacon.PreviousConfidentLocation,
  116. // NewLocation: bestLocName,
  117. // Timestamp: time.Now().Unix(),
  118. // })
  119. // if err != nil {
  120. // eMsg := fmt.Sprintf("Error in marshaling: %v", err)
  121. // slog.Error(eMsg)
  122. // beacon.PreviousConfidentLocation = bestLocName
  123. // beacon.PreviousLocation = bestLocName
  124. // appState.UpdateBeacon(beacon.ID, beacon)
  125. // continue
  126. // }
  127. // msg := kafka.Message{
  128. // Value: js,
  129. // }
  130. // err = writer.WriteMessages(context.Background(), msg)
  131. // if err != nil {
  132. // fmt.Println("Error in sending Kafka message")
  133. // }
  134. }
  135. beacon.PreviousLocation = bestLocName
  136. appState.UpdateBeacon(beacon.ID, beacon)
  137. js, err := json.Marshal(r)
  138. if err != nil {
  139. eMsg := fmt.Sprintf("Error in marshaling location: %v", err)
  140. slog.Error(eMsg)
  141. continue
  142. }
  143. msg := kafka.Message{
  144. Value: js,
  145. }
  146. err = writer.WriteMessages(context.Background(), msg)
  147. if err != nil {
  148. eMsg := fmt.Sprintf("Error in sending Kafka message: %v", err)
  149. slog.Error(eMsg)
  150. }
  151. }
  152. }
  153. func assignBeaconToList(adv model.BeaconAdvertisement, appState *appcontext.AppState) {
  154. id := adv.ID
  155. now := time.Now().Unix()
  156. settings := appState.GetSettingsValue()
  157. if settings.RSSIEnforceThreshold && (int64(adv.RSSI) < settings.RSSIMinThreshold) {
  158. slog.Info("Settings returns")
  159. return
  160. }
  161. beacon, ok := appState.GetBeacon(id)
  162. if !ok {
  163. beacon = model.Beacon{
  164. ID: id,
  165. }
  166. }
  167. beacon.IncomingJSON = adv
  168. beacon.LastSeen = now
  169. if beacon.BeaconMetrics == nil {
  170. beacon.BeaconMetrics = make([]model.BeaconMetric, 0, settings.BeaconMetricSize)
  171. }
  172. metric := model.BeaconMetric{
  173. Distance: utils.CalculateDistance(adv),
  174. Timestamp: now,
  175. RSSI: int64(adv.RSSI),
  176. Location: adv.Hostname,
  177. }
  178. if len(beacon.BeaconMetrics) >= settings.BeaconMetricSize {
  179. copy(beacon.BeaconMetrics, beacon.BeaconMetrics[1:])
  180. beacon.BeaconMetrics[settings.BeaconMetricSize-1] = metric
  181. } else {
  182. beacon.BeaconMetrics = append(beacon.BeaconMetrics, metric)
  183. }
  184. appState.UpdateBeacon(id, beacon)
  185. }