瀏覽代碼

traker struct battery e temp from int to string

master
root 1 天之前
父節點
當前提交
6d7558f8d8
共有 3 個檔案被更改,包括 110 行新增21 行删除
  1. +7
    -1
      internal/app/server/events.go
  2. +95
    -18
      internal/pkg/apiclient/updatedb.go
  3. +8
    -2
      internal/pkg/model/trackers.go

+ 7
- 1
internal/app/server/events.go 查看文件

@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"log/slog"
"strconv"
"time"

"github.com/AFASystems/presence/internal/pkg/config"
@@ -51,7 +52,12 @@ func RunEventLoop(ctx context.Context, a *ServerApp) {
slog.Error("decoder event for untracked beacon", "id", id)
continue
}
if err := a.DB.Updates(&model.Tracker{ID: id, Battery: msg.Battery, Temperature: msg.Temperature}).Error; err != nil {
// MODIFICATO: Convertiamo esplicitamente uint32 e uint16 in formato stringa base 10 prima dell'update
batteryStr := strconv.FormatUint(uint64(msg.Battery), 10)
tempStr := strconv.FormatUint(uint64(msg.Temperature), 10)

if err := a.DB.Updates(&model.Tracker{ID: id, Battery: batteryStr, Temperature: tempStr}).Error; err != nil {
slog.Error("saving decoder event for beacon", "id", id, "err", err)
continue
}


+ 95
- 18
internal/pkg/apiclient/updatedb.go 查看文件

@@ -3,7 +3,7 @@ package apiclient
import (
"context"
"crypto/tls"
"fmt"
"errors"
"log/slog"
"net/http"
"reflect"
@@ -18,6 +18,8 @@ import (
)

func UpdateDB(db *gorm.DB, ctx context.Context, cfg *config.Config, writer *kafka.Writer, appState *appcontext.AppState) error {
slog.Info("UpdateDB: Avvio procedura di sincronizzazione database...")

tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
@@ -25,15 +27,25 @@ func UpdateDB(db *gorm.DB, ctx context.Context, cfg *config.Config, writer *kafk

token, err := GetToken(ctx, cfg, client)
if err != nil {
slog.Error("UpdateDB: Fallito recupero del Token di autenticazione", "error", err)
return err
}
slog.Info("UpdateDB: Token di autenticazione recuperato con successo")

if trackers, err := GetTrackers(token, client, cfg); err == nil {
// 1. Sincronizzazione TRACKERS
trackers, err := GetTrackers(token, client, cfg)
if err != nil {
slog.Error("UpdateDB: Errore durante la chiamata GetTrackers", "error", err)
} else {
slog.Info("UpdateDB: Tracker scaricati dall'API", "count", len(trackers))
syncTable(db, trackers)
slog.Info("UpdateDB: Tabella 'trackers' allineata su DB")

if err := controller.SendKafkaMessage(writer, &model.ApiUpdate{Method: "DELETE", MAC: "all"}, ctx); err != nil {
slog.Error("Error in sending delete all from lookup message", "error", err)
slog.Error("UpdateDB: Errore nell'invio del messaggio Kafka 'DELETE all' al lookup", "error", err)
}

kafkaMsgCount := 0
for _, v := range trackers {
apiUpdate := model.ApiUpdate{
Method: "POST",
@@ -42,59 +54,124 @@ func UpdateDB(db *gorm.DB, ctx context.Context, cfg *config.Config, writer *kafk
}

if err := controller.SendKafkaMessage(writer, &apiUpdate, ctx); err != nil {
msg := fmt.Sprintf("Error in sending POST kafka message: %v", err)
slog.Error(msg)
slog.Error("UpdateDB: Errore nell'invio del messaggio Kafka 'POST tracker'", "tracker_id", v.ID, "error", err)
} else {
kafkaMsgCount++
}
}
slog.Info("UpdateDB: Sincronizzazione messaggi Kafka per i tracker completata", "inviati", kafkaMsgCount)
}

if gateways, err := GetGateways(token, client, cfg); err == nil {
// 2. Sincronizzazione GATEWAYS
gateways, err := GetGateways(token, client, cfg)
if err != nil {
slog.Error("UpdateDB: Errore durante la chiamata GetGateways", "error", err)
} else {
slog.Info("UpdateDB: Gateway scaricati dall'API", "count", len(gateways))
syncTable(db, gateways)
slog.Info("UpdateDB: Tabella 'gateways' allineata su DB")
}

if floors, err := GetFloors(token, client, cfg); err == nil {
// 3. Sincronizzazione FLOORS
floors, err := GetFloors(token, client, cfg)
if err != nil {
slog.Error("UpdateDB: Errore durante la chiamata GetFloors", "error", err)
} else {
slog.Info("UpdateDB: Piani (floors) scaricati dall'API", "count", len(floors))
syncTable(db, floors)
slog.Info("UpdateDB: Tabella 'floors' allineata su DB")
}

if zones, err := GetZones(token, client, cfg); err == nil {
// 4. Sincronizzazione ZONES
zones, err := GetZones(token, client, cfg)
if err != nil {
slog.Error("UpdateDB: Errore durante la chiamata GetZones", "error", err)
} else {
slog.Info("UpdateDB: Zone scaricate dall'API", "count", len(zones))
syncTable(db, zones)
slog.Info("UpdateDB: Tabella 'zones' allineata su DB")
}

if trackerZones, err := GetTrackerZones(token, client, cfg); err == nil {
// 5. Sincronizzazione TRACKER ZONES
trackerZones, err := GetTrackerZones(token, client, cfg)
if err != nil {
slog.Error("UpdateDB: Errore durante la chiamata GetTrackerZones", "error", err)
} else {
slog.Info("UpdateDB: Tracker-Zones scaricate dall'API", "count", len(trackerZones))
syncTable(db, trackerZones)
slog.Info("UpdateDB: Tabella 'tracker_zones' allineata su DB")
}

if inferredPosition, err := InferPosition(token, client, cfg); err == nil {
// 6. Inferenza delle posizioni (Stime AI passate)
inferredPosition, err := InferPosition(token, client, cfg)
if err != nil {
slog.Error("UpdateDB: Errore durante la chiamata InferPosition", "error", err)
} else {
updateCount := 0
for _, v := range inferredPosition.Items {
mac := convertMac(v.Mac)
db.Model(&model.Tracker{}).Where("mac = ?", mac).Update("x", v.X).Update("y", v.Y)
res := db.Model(&model.Tracker{}).Where("mac = ?", mac).Updates(map[string]interface{}{"x": v.X, "y": v.Y})
if res.Error != nil {
slog.Error("UpdateDB: Errore aggiornamento coordinate stimate per tracker", "mac", mac, "error", res.Error)
} else if res.RowsAffected > 0 {
updateCount++
}
}
slog.Info("UpdateDB: Aggiornamento posizioni storiche completato", "tracker_aggiornati", updateCount)
}

// 7. Controllo e Inizializzazione SETTINGS
var settings appcontext.Settings
db.First(&settings)
if err := db.First(&settings).Error; err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
slog.Error("UpdateDB: Errore durante la lettura delle impostazioni", "error", err)
}
}

if settings.ID == 0 {
msg := "settings are empty"
slog.Info(msg)
db.Create(appState.GetSettings())
slog.Info("UpdateDB: Tabella settings vuota. Inizializzazione con i valori di default di AppState...")
if err := db.Create(appState.GetSettings()).Error; err != nil {
slog.Error("UpdateDB: Errore critico durante la creazione dei settings di default", "error", err)
} else {
slog.Info("UpdateDB: Settings di default salvati con successo")
}
} else {
slog.Info("UpdateDB: Settings già presenti nel database", "id", settings.ID)
}

slog.Info("UpdateDB: Procedura di sincronizzazione completata.")
return nil
}

func syncTable[T any](db *gorm.DB, data []T) {
if len(data) == 0 {
slog.Warn("syncTable: Nessun dato ricevuto dall'API, salto la sincronizzazione per questa tabella.")
return
}

var ids []string
for _, item := range data {
v := reflect.ValueOf(item).FieldByName("ID").String()
ids = append(ids, v)
if v != "" {
ids = append(ids, v)
}
}

if len(ids) == 0 {
slog.Error("syncTable: Impossibile procedere. Trovati 0 ID validi tramite reflection nella struttura dei dati.")
return
}

db.Transaction(func(tx *gorm.DB) error {
tx.Where("id NOT IN ?", ids).Delete(new(T))
err := db.Transaction(func(tx *gorm.DB) error {
// Elimina i record locali che non esistono più nel backend centrale
if err := tx.Where("id NOT IN ?", ids).Delete(new(T)).Error; err != nil {
return err
}
// Upsert dei dati aggiornati o nuovi
return tx.Clauses(clause.OnConflict{UpdateAll: true}).Create(&data).Error
})

if err != nil {
slog.Error("syncTable: Errore critico durante la transazione di sincronizzazione", "error", err)
}
}

+ 8
- 2
internal/pkg/model/trackers.go 查看文件

@@ -13,7 +13,13 @@ type Tracker struct {
Notes string `json:"notes"`
Floor string `json:"floor"`
Building string `json:"building"`
Battery uint32 `json:"battery,string"`
// MODIFICATO: Cambiato in string e rimosso ,string per accettare il testo nativo dell'API
Battery string `json:"battery" gorm:"type:text"`
BatteryThreshold uint32 `json:"batteryThreshold"`
Temperature uint16 `json:"temperature,string"`
// MODIFICATO: Cambiato in string e rimosso ,string
Temperature string `json:"temperature" gorm:"type:text"`
// NUOVI CAMPI: Aggiunti per mappare completamente il payload dell'API cloud
Acceleration string `json:"acceleration" gorm:"type:text"`
HeartRate string `json:"heartRate" gorm:"type:text"`
ButtonPress bool `json:"buttonPress" gorm:"type:boolean"`
}

Loading…
取消
儲存