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

226 строки
5.7 KiB

  1. package main
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "os/signal"
  7. "sync"
  8. "syscall"
  9. "time"
  10. "github.com/AFASystems/presence/internal/pkg/common/appcontext"
  11. "github.com/AFASystems/presence/internal/pkg/common/utils"
  12. "github.com/AFASystems/presence/internal/pkg/config"
  13. "github.com/AFASystems/presence/internal/pkg/kafkaclient"
  14. "github.com/AFASystems/presence/internal/pkg/model"
  15. "github.com/segmentio/kafka-go"
  16. )
  17. var wg sync.WaitGroup
  18. func main() {
  19. // Load global context to init beacons and latest list
  20. appState := appcontext.NewAppState()
  21. cfg := config.Load()
  22. // Define context
  23. ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
  24. defer stop()
  25. rawReader := appState.AddKafkaReader(cfg.KafkaURL, "rawbeacons", "gid-raw-loc")
  26. apiReader := appState.AddKafkaReader(cfg.KafkaURL, "apibeacons", "gid-api-loc")
  27. writer := appState.AddKafkaWriter(cfg.KafkaURL, "locevents")
  28. fmt.Println("Locations algorithm initialized, subscribed to Kafka topics")
  29. locTicker := time.NewTicker(1 * time.Second)
  30. defer locTicker.Stop()
  31. chRaw := make(chan model.BeaconAdvertisement, 2000)
  32. chApi := make(chan model.ApiUpdate, 2000)
  33. wg.Add(2)
  34. go kafkaclient.Consume(rawReader, chRaw, ctx, &wg)
  35. go kafkaclient.Consume(apiReader, chApi, ctx, &wg)
  36. eventLoop:
  37. for {
  38. select {
  39. case <-ctx.Done():
  40. break eventLoop
  41. case <-locTicker.C:
  42. getLikelyLocations(appState, writer)
  43. case msg := <-chRaw:
  44. assignBeaconToList(msg, appState)
  45. case msg := <-chApi:
  46. switch msg.Method {
  47. case "POST":
  48. id := msg.Beacon.ID
  49. fmt.Println("Beacon added to lookup: ", id)
  50. appState.AddBeaconToLookup(id)
  51. case "DELETE":
  52. id := msg.Beacon.ID
  53. appState.RemoveBeaconFromLookup(id)
  54. fmt.Println("Beacon removed from lookup: ", id)
  55. }
  56. }
  57. }
  58. fmt.Println("broken out of the main event loop")
  59. wg.Wait()
  60. fmt.Println("All go routines have stopped, Beggining to close Kafka connections")
  61. appState.CleanKafkaReaders()
  62. appState.CleanKafkaWriters()
  63. }
  64. func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) {
  65. beacons := appState.GetAllBeacons()
  66. settings := appState.GetSettingsValue()
  67. for _, beacon := range beacons {
  68. // Shrinking the model because other properties have nothing to do with the location
  69. r := model.HTTPLocation{
  70. Method: "Standard",
  71. Distance: 999,
  72. ID: beacon.ID,
  73. Location: "",
  74. LastSeen: 999,
  75. }
  76. mSize := len(beacon.BeaconMetrics)
  77. if (int64(time.Now().Unix()) - (beacon.BeaconMetrics[mSize-1].Timestamp)) > settings.LastSeenThreshold {
  78. fmt.Println("Beacon is too old")
  79. continue
  80. }
  81. locList := make(map[string]float64)
  82. seenW := 1.5
  83. rssiW := 0.75
  84. for _, metric := range beacon.BeaconMetrics {
  85. res := seenW + (rssiW * (1.0 - (float64(metric.RSSI) / -100.0)))
  86. locList[metric.Location] += res
  87. }
  88. bestLocName := ""
  89. maxScore := 0.0
  90. for locName, score := range locList {
  91. if score > maxScore {
  92. maxScore = score
  93. bestLocName = locName
  94. }
  95. }
  96. if bestLocName == beacon.PreviousLocation {
  97. beacon.LocationConfidence++
  98. } else {
  99. beacon.LocationConfidence = 0
  100. }
  101. r.Distance = beacon.BeaconMetrics[mSize-1].Distance
  102. r.Location = bestLocName
  103. r.LastSeen = beacon.BeaconMetrics[mSize-1].Timestamp
  104. if beacon.LocationConfidence == settings.LocationConfidence && beacon.PreviousConfidentLocation != bestLocName {
  105. beacon.LocationConfidence = 0
  106. // Why do I need this if I am sending entire structure anyways? who knows
  107. fmt.Println("this is called")
  108. js, err := json.Marshal(model.LocationChange{
  109. Method: "LocationChange",
  110. BeaconRef: beacon,
  111. Name: beacon.Name,
  112. PreviousLocation: beacon.PreviousConfidentLocation,
  113. NewLocation: bestLocName,
  114. Timestamp: time.Now().Unix(),
  115. })
  116. if err != nil {
  117. fmt.Println("This error happens: ", err)
  118. beacon.PreviousConfidentLocation = bestLocName
  119. beacon.PreviousLocation = bestLocName
  120. appState.UpdateBeacon(beacon.ID, beacon)
  121. continue
  122. }
  123. msg := kafka.Message{
  124. Value: js,
  125. }
  126. err = writer.WriteMessages(context.Background(), msg)
  127. if err != nil {
  128. fmt.Println("Error in sending Kafka message")
  129. }
  130. }
  131. beacon.PreviousLocation = bestLocName
  132. appState.UpdateBeacon(beacon.ID, beacon)
  133. js, err := json.Marshal(r)
  134. if err != nil {
  135. fmt.Println("Error in marshaling location: ", err)
  136. continue
  137. }
  138. msg := kafka.Message{
  139. Value: js,
  140. }
  141. err = writer.WriteMessages(context.Background(), msg)
  142. if err != nil {
  143. fmt.Println("Error in sending Kafka message: ", err)
  144. }
  145. }
  146. }
  147. func assignBeaconToList(adv model.BeaconAdvertisement, appState *appcontext.AppState) {
  148. id := adv.MAC
  149. ok := appState.BeaconExists(id)
  150. now := time.Now().Unix()
  151. if !ok {
  152. appState.UpdateLatestBeacon(id, model.Beacon{ID: id, BeaconType: adv.BeaconType, LastSeen: now, IncomingJSON: adv, BeaconLocation: adv.Hostname, Distance: utils.CalculateDistance(adv)})
  153. return
  154. }
  155. settings := appState.GetSettingsValue()
  156. if settings.RSSIEnforceThreshold && (int64(adv.RSSI) < settings.RSSIMinThreshold) {
  157. fmt.Println("Settings returns")
  158. return
  159. }
  160. beacon, ok := appState.GetBeacon(id)
  161. if !ok {
  162. beacon = model.Beacon{
  163. ID: id,
  164. }
  165. }
  166. beacon.IncomingJSON = adv
  167. beacon.LastSeen = now
  168. if beacon.BeaconMetrics == nil {
  169. beacon.BeaconMetrics = make([]model.BeaconMetric, 0, settings.BeaconMetricSize)
  170. }
  171. metric := model.BeaconMetric{
  172. Distance: utils.CalculateDistance(adv),
  173. Timestamp: now,
  174. RSSI: int64(adv.RSSI),
  175. Location: adv.Hostname,
  176. }
  177. if len(beacon.BeaconMetrics) >= settings.BeaconMetricSize {
  178. copy(beacon.BeaconMetrics, beacon.BeaconMetrics[1:])
  179. beacon.BeaconMetrics[settings.BeaconMetricSize-1] = metric
  180. } else {
  181. beacon.BeaconMetrics = append(beacon.BeaconMetrics, metric)
  182. }
  183. appState.UpdateBeacon(id, beacon)
  184. }