|
- package service
-
- import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "log/slog"
- "slices"
- "strings"
- "time"
-
- "github.com/AFASystems/presence/internal/pkg/kafkaclient"
- "github.com/AFASystems/presence/internal/pkg/model"
- "github.com/google/uuid"
- "github.com/segmentio/kafka-go"
- "gorm.io/gorm"
- )
-
- func findTracker(msg model.HTTPLocation, db *gorm.DB) (model.Tracker, error) {
- var tracker model.Tracker
- if msg.MAC != "" {
- if err := db.Where("mac = ?", strings.ToUpper(strings.ReplaceAll(msg.MAC, ":", ""))).Find(&tracker).Error; err != nil {
- return model.Tracker{}, err
- }
-
- return tracker, nil
- }
-
- if msg.ID != "" {
- if err := db.Where("id = ?", msg.ID).Find(&tracker).Error; err != nil {
- return model.Tracker{}, err
- }
-
- return tracker, nil
- }
-
- return model.Tracker{}, errors.New("both ID and MAC are not provided")
- }
-
- func findZones(trackerID string, db *gorm.DB) ([]string, error) {
- var zones []model.TrackerZones
- if err := db.Select("zoneList").Where("tracker = ?", trackerID).Find(&zones).Error; err != nil {
- return nil, err
- }
-
- var allowedZones []string
- for _, z := range zones {
- allowedZones = append(allowedZones, z.ZoneList...)
- }
-
- return allowedZones, nil
- }
-
- func LocationToBeaconService(msg model.HTTPLocation, db *gorm.DB, writer *kafka.Writer, ctx context.Context) {
- tracker, err := findTracker(msg, db)
- if err != nil {
- msg := fmt.Sprintf("Error in finding tracker: %v", err)
- slog.Error(msg)
- return
- }
-
- allowedZones, err := findZones(tracker.ID, db)
- if err != nil {
- msg := fmt.Sprintf("Error in finding zones: %v", err)
- slog.Error(msg)
- return
- }
-
- var gw model.Gateway
- mac := formatMac(msg.Location)
- if err := db.Select("*").Where("mac = ?", mac).First(&gw).Error; err != nil {
- msg := fmt.Sprintf("Gateway not found for MAC: %s", mac)
- slog.Error(msg)
- return
- }
-
- 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 {
- msg := fmt.Sprintf("Error in saving distance for beacon: %v", err)
- slog.Error(msg)
- return
- }
-
- err = db.Where("id = ?", msg.ID).Updates(model.Tracker{Position: gw.ID, X: gw.X, Y: gw.Y}).Error
- if err != nil {
- msg := fmt.Sprintf("Error in updating tracker: %v", err)
- slog.Error(msg)
- return
- }
-
- sendRestrictedZoneAlert(gw.ID, msg.ID, writer, ctx, allowedZones, db)
- }
-
- func LocationToBeaconServiceAI(msg model.HTTPLocation, db *gorm.DB, writer *kafka.Writer, ctx context.Context) {
- tracker, err := findTracker(msg, db)
- if err != nil {
- msg := fmt.Sprintf("Error in finding tracker: %v", err)
- slog.Error(msg)
- return
- }
-
- allowedZones, err := findZones(tracker.ID, db)
- if err != nil {
- msg := fmt.Sprintf("Error in finding zones: %v", err)
- slog.Error(msg)
- return
- }
-
- var gw model.Gateway
- if err := db.Order(fmt.Sprintf("POW(x - %f, 2) + POW(y - %f, 2)", msg.X, msg.Y)).First(&gw).Error; err != nil {
- msg := fmt.Sprintf("Error in finding gateway: %v", err)
- slog.Error(msg)
- return
- }
-
- 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 {
- msg := fmt.Sprintf("Error in saving distance for beacon: %v", err)
- slog.Error(msg)
- return
- }
-
- err = db.Where("id = ?", tracker.ID).Updates(model.Tracker{Position: gw.ID, X: msg.X, Y: msg.Y}).Error
- if err != nil {
- msg := fmt.Sprintf("Error in updating tracker: %v", err)
- slog.Error(msg)
- return
- }
-
- sendRestrictedZoneAlert(gw.ID, tracker.ID, writer, ctx, allowedZones, db)
- }
-
- func SendAlert(trackerId, alertType string, writer *kafka.Writer, ctx context.Context, db *gorm.DB) {
- var existingAlert model.Alert
- result := db.Select("status").Where("tracker_id = ? AND type = ?", trackerId, alertType).Order("timestamp DESC").First(&existingAlert)
-
- if result.Error == gorm.ErrRecordNotFound || existingAlert.Status == "resolved" {
- alert := model.Alert{
- ID: uuid.New().String(),
- TrackerID: trackerId,
- Type: alertType,
- Status: "new",
- Timestamp: time.Now(),
- }
-
- if err := InsertAlert(alert, db, ctx); err != nil {
- msg := fmt.Sprintf("Error in inserting alert: %v", err)
- slog.Error(msg)
- return
- }
-
- eMsg, err := json.Marshal(alert)
- if err != nil {
- msg := "Error in marshaling"
- slog.Error(msg)
- return
- } else {
- msg := kafka.Message{
- Value: eMsg,
- }
- if err := kafkaclient.Write(ctx, writer, msg); err != nil {
- msg := fmt.Sprintf("Error in writing message: %v", err)
- slog.Error(msg)
- return
- }
- }
- return
- } else {
- return
- }
- }
-
- func sendRestrictedZoneAlert(gwId, trackerId string, writer *kafka.Writer, ctx context.Context, allowedZones []string, db *gorm.DB) {
- if len(allowedZones) != 0 && !slices.Contains(allowedZones, gwId) {
- SendAlert(trackerId, "Restricted zone", writer, ctx, db)
- }
- }
-
- func formatMac(MAC string) string {
- var res strings.Builder
- for i := 0; i < len(MAC); i += 2 {
- if i > 0 {
- res.WriteByte(':')
- }
-
- end := min(i+2, len(MAC))
-
- res.WriteString(MAC[i:end])
- }
-
- return res.String()
- }
|