Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 

179 rader
4.5 KiB

  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "log/slog"
  8. "slices"
  9. "strings"
  10. "time"
  11. "github.com/AFASystems/presence/internal/pkg/model"
  12. "github.com/google/uuid"
  13. "github.com/segmentio/kafka-go"
  14. "gorm.io/gorm"
  15. )
  16. // KafkaWriter defines the interface for writing Kafka messages (allows mocking in tests)
  17. type KafkaWriter interface {
  18. WriteMessages(ctx context.Context, msgs ...kafka.Message) error
  19. }
  20. func findTracker(msg model.HTTPLocation, db *gorm.DB) (model.Tracker, error) {
  21. var tracker model.Tracker
  22. if msg.MAC != "" {
  23. if err := db.Where("mac = ?", msg.MAC).Find(&tracker).Error; err != nil {
  24. return model.Tracker{}, err
  25. }
  26. return tracker, nil
  27. }
  28. if msg.ID != "" {
  29. if err := db.Where("id = ?", msg.ID).Find(&tracker).Error; err != nil {
  30. return model.Tracker{}, err
  31. }
  32. return tracker, nil
  33. }
  34. return model.Tracker{}, errors.New("both ID and MAC are not provided")
  35. }
  36. func findZones(trackerID string, db *gorm.DB) ([]string, error) {
  37. var zones []model.TrackerZones
  38. if err := db.Select("zoneList").Where("tracker = ?", trackerID).Find(&zones).Error; err != nil {
  39. return nil, err
  40. }
  41. var allowedZones []string
  42. for _, z := range zones {
  43. allowedZones = append(allowedZones, z.ZoneList...)
  44. }
  45. return allowedZones, nil
  46. }
  47. func LocationToBeaconService(msg model.HTTPLocation, db *gorm.DB, writer KafkaWriter, ctx context.Context) {
  48. tracker, err := findTracker(msg, db)
  49. if err != nil {
  50. msg := fmt.Sprintf("Error in finding tracker: %v", err)
  51. slog.Error(msg)
  52. return
  53. }
  54. allowedZones, err := findZones(tracker.ID, db)
  55. if err != nil {
  56. msg := fmt.Sprintf("Error in finding zones: %v", err)
  57. slog.Error(msg)
  58. return
  59. }
  60. var gw model.Gateway
  61. mac := formatMac(msg.Location)
  62. if err := db.Select("*").Where("mac = ?", mac).First(&gw).Error; err != nil {
  63. msg := fmt.Sprintf("Gateway not found for MAC: %s", mac)
  64. slog.Error(msg)
  65. return
  66. }
  67. if err := db.Create(&model.Tracks{UUID: msg.ID, Timestamp: time.Now(), Gateway: gw.ID, GatewayMac: gw.MAC, Tracker: msg.ID, Floor: gw.Floor, Building: gw.Building, TrackerMac: tracker.MAC, Signal: msg.RSSI}).Error; err != nil {
  68. msg := fmt.Sprintf("Error in saving distance for beacon: %v", err)
  69. slog.Error(msg)
  70. return
  71. }
  72. err = db.Where("id = ?", msg.ID).Updates(model.Tracker{Position: gw.ID, X: gw.X, Y: gw.Y}).Error
  73. if err != nil {
  74. msg := fmt.Sprintf("Error in updating tracker: %v", err)
  75. slog.Error(msg)
  76. return
  77. }
  78. sendAlert(gw.ID, msg.ID, writer, ctx, allowedZones, db)
  79. }
  80. func LocationToBeaconServiceAI(msg model.HTTPLocation, db *gorm.DB, writer KafkaWriter, ctx context.Context) {
  81. tracker, err := findTracker(msg, db)
  82. if err != nil {
  83. msg := fmt.Sprintf("Error in finding tracker: %v", err)
  84. slog.Error(msg)
  85. return
  86. }
  87. allowedZones, err := findZones(tracker.ID, db)
  88. if err != nil {
  89. msg := fmt.Sprintf("Error in finding zones: %v", err)
  90. slog.Error(msg)
  91. return
  92. }
  93. var gw model.Gateway
  94. if err := db.Order(fmt.Sprintf("POW(x - %f, 2) + POW(y - %f, 2)", msg.X, msg.Y)).First(&gw).Error; err != nil {
  95. msg := fmt.Sprintf("Error in finding gateway: %v", err)
  96. slog.Error(msg)
  97. return
  98. }
  99. if err := db.Create(&model.Tracks{UUID: tracker.ID, Timestamp: time.Now(), Gateway: gw.ID, GatewayMac: gw.MAC, Tracker: tracker.ID, Floor: gw.Floor, Building: gw.Building, TrackerMac: tracker.MAC}).Error; err != nil {
  100. msg := fmt.Sprintf("Error in saving distance for beacon: %v", err)
  101. slog.Error(msg)
  102. return
  103. }
  104. err = db.Where("id = ?", tracker.ID).Updates(model.Tracker{Position: gw.ID, X: msg.X, Y: msg.Y}).Error
  105. if err != nil {
  106. msg := fmt.Sprintf("Error in updating tracker: %v", err)
  107. slog.Error(msg)
  108. return
  109. }
  110. sendAlert(gw.ID, tracker.ID, writer, ctx, allowedZones, db)
  111. }
  112. func sendAlert(gwId, trackerId string, writer KafkaWriter, ctx context.Context, allowedZones []string, db *gorm.DB) {
  113. if len(allowedZones) != 0 && !slices.Contains(allowedZones, gwId) {
  114. alert := model.Alert{
  115. ID: uuid.New().String(),
  116. TrackerID: trackerId,
  117. Type: "Restricted zone",
  118. Value: gwId,
  119. }
  120. if err := InsertAlert(alert, db, ctx); err != nil {
  121. msg := fmt.Sprintf("Error in inserting alert: %v", err)
  122. slog.Error(msg)
  123. return
  124. }
  125. eMsg, err := json.Marshal(alert)
  126. if err != nil {
  127. msg := "Error in marshaling"
  128. slog.Error(msg)
  129. return
  130. } else {
  131. msg := kafka.Message{
  132. Value: eMsg,
  133. }
  134. writer.WriteMessages(ctx, msg)
  135. }
  136. }
  137. }
  138. func formatMac(MAC string) string {
  139. var res strings.Builder
  140. for i := 0; i < len(MAC); i += 2 {
  141. if i > 0 {
  142. res.WriteByte(':')
  143. }
  144. end := min(i+2, len(MAC))
  145. res.WriteString(MAC[i:end])
  146. }
  147. return res.String()
  148. }