From 6d7558f8d8f3913e233e7d476e18ed21f7d3781e Mon Sep 17 00:00:00 2001 From: root Date: Fri, 26 Jun 2026 18:30:11 +0200 Subject: [PATCH] traker struct battery e temp from int to string --- internal/app/server/events.go | 8 +- internal/pkg/apiclient/updatedb.go | 113 ++++++++++++++++++++++++----- internal/pkg/model/trackers.go | 10 ++- 3 files changed, 110 insertions(+), 21 deletions(-) diff --git a/internal/app/server/events.go b/internal/app/server/events.go index e5dc17b..ba12b0f 100644 --- a/internal/app/server/events.go +++ b/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 } diff --git a/internal/pkg/apiclient/updatedb.go b/internal/pkg/apiclient/updatedb.go index 7e55eb7..2be61df 100644 --- a/internal/pkg/apiclient/updatedb.go +++ b/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) + } } diff --git a/internal/pkg/model/trackers.go b/internal/pkg/model/trackers.go index 3ab54b1..863cfd3 100644 --- a/internal/pkg/model/trackers.go +++ b/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"` }