| @@ -40,14 +40,15 @@ func mqtthandler(writer *kafka.Writer, topic string, message []byte, appState *a | |||||
| if reading.Type == "Gateway" { | if reading.Type == "Gateway" { | ||||
| continue | continue | ||||
| } | } | ||||
| val, ok := appState.BeaconExists(reading.MAC) | |||||
| // fmt.Printf("reading: %+v\n", reading) | // fmt.Printf("reading: %+v\n", reading) | ||||
| if !appState.BeaconExists(reading.MAC) { | |||||
| if !ok { | |||||
| continue | continue | ||||
| } | } | ||||
| fmt.Printf("Tracking beacon: %s\n", reading.MAC) | |||||
| adv := model.BeaconAdvertisement{ | adv := model.BeaconAdvertisement{ | ||||
| ID: val, | |||||
| Hostname: hostname, | Hostname: hostname, | ||||
| MAC: reading.MAC, | MAC: reading.MAC, | ||||
| RSSI: int64(reading.RSSI), | RSSI: int64(reading.RSSI), | ||||
| @@ -63,6 +64,7 @@ func mqtthandler(writer *kafka.Writer, topic string, message []byte, appState *a | |||||
| msg := kafka.Message{ | msg := kafka.Message{ | ||||
| Value: encodedMsg, | Value: encodedMsg, | ||||
| } | } | ||||
| err = writer.WriteMessages(context.Background(), msg) | err = writer.WriteMessages(context.Background(), msg) | ||||
| if err != nil { | if err != nil { | ||||
| fmt.Println("Error in writing to Kafka: ", err) | fmt.Println("Error in writing to Kafka: ", err) | ||||
| @@ -167,12 +169,17 @@ eventloop: | |||||
| case msg := <-chApi: | case msg := <-chApi: | ||||
| switch msg.Method { | switch msg.Method { | ||||
| case "POST": | case "POST": | ||||
| id := msg.Beacon.ID | |||||
| appState.AddBeaconToLookup(id) | |||||
| id := msg.ID | |||||
| appState.AddBeaconToLookup(msg.MAC, id) | |||||
| lMsg := fmt.Sprintf("Beacon added to lookup: %s", id) | lMsg := fmt.Sprintf("Beacon added to lookup: %s", id) | ||||
| slog.Info(lMsg) | slog.Info(lMsg) | ||||
| case "DELETE": | case "DELETE": | ||||
| id := msg.Beacon.ID | |||||
| id := msg.MAC | |||||
| if id == "all" { | |||||
| appState.CleanLookup() | |||||
| fmt.Println("cleaned up lookup map") | |||||
| continue | |||||
| } | |||||
| appState.RemoveBeaconFromLookup(id) | appState.RemoveBeaconFromLookup(id) | ||||
| lMsg := fmt.Sprintf("Beacon removed from lookup: %s", id) | lMsg := fmt.Sprintf("Beacon removed from lookup: %s", id) | ||||
| slog.Info(lMsg) | slog.Info(lMsg) | ||||
| @@ -83,7 +83,7 @@ func processIncoming(adv model.BeaconAdvertisement, appState *appcontext.AppStat | |||||
| func decodeBeacon(adv model.BeaconAdvertisement, appState *appcontext.AppState, writer *kafka.Writer) error { | func decodeBeacon(adv model.BeaconAdvertisement, appState *appcontext.AppState, writer *kafka.Writer) error { | ||||
| beacon := strings.TrimSpace(adv.Data) | beacon := strings.TrimSpace(adv.Data) | ||||
| id := adv.MAC | |||||
| id := adv.ID | |||||
| if beacon == "" { | if beacon == "" { | ||||
| return nil | return nil | ||||
| } | } | ||||
| @@ -109,6 +109,7 @@ func decodeBeacon(adv model.BeaconAdvertisement, appState *appcontext.AppState, | |||||
| } | } | ||||
| eMsg, err := event.ToJSON() | eMsg, err := event.ToJSON() | ||||
| fmt.Printf("event: %+v\n", eMsg) | |||||
| if err != nil { | if err != nil { | ||||
| return err | return err | ||||
| } | } | ||||
| @@ -86,6 +86,7 @@ func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) { | |||||
| settings := appState.GetSettingsValue() | settings := appState.GetSettingsValue() | ||||
| for _, beacon := range beacons { | for _, beacon := range beacons { | ||||
| fmt.Println("id: ", beacon.ID) | |||||
| // Shrinking the model because other properties have nothing to do with the location | // Shrinking the model because other properties have nothing to do with the location | ||||
| r := model.HTTPLocation{ | r := model.HTTPLocation{ | ||||
| Method: "Standard", | Method: "Standard", | ||||
| @@ -175,6 +176,8 @@ func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) { | |||||
| Value: js, | Value: js, | ||||
| } | } | ||||
| fmt.Println("sending message") | |||||
| err = writer.WriteMessages(context.Background(), msg) | err = writer.WriteMessages(context.Background(), msg) | ||||
| if err != nil { | if err != nil { | ||||
| eMsg := fmt.Sprintf("Error in sending Kafka message: %v", err) | eMsg := fmt.Sprintf("Error in sending Kafka message: %v", err) | ||||
| @@ -184,7 +187,7 @@ func getLikelyLocations(appState *appcontext.AppState, writer *kafka.Writer) { | |||||
| } | } | ||||
| func assignBeaconToList(adv model.BeaconAdvertisement, appState *appcontext.AppState) { | func assignBeaconToList(adv model.BeaconAdvertisement, appState *appcontext.AppState) { | ||||
| id := adv.MAC | |||||
| id := adv.ID | |||||
| now := time.Now().Unix() | now := time.Now().Unix() | ||||
| settings := appState.GetSettingsValue() | settings := appState.GetSettingsValue() | ||||
| @@ -15,13 +15,13 @@ import ( | |||||
| "syscall" | "syscall" | ||||
| "time" | "time" | ||||
| "github.com/AFASystems/presence/internal/pkg/apiclient" | |||||
| "github.com/AFASystems/presence/internal/pkg/common/appcontext" | "github.com/AFASystems/presence/internal/pkg/common/appcontext" | ||||
| "github.com/AFASystems/presence/internal/pkg/config" | "github.com/AFASystems/presence/internal/pkg/config" | ||||
| "github.com/AFASystems/presence/internal/pkg/controller" | "github.com/AFASystems/presence/internal/pkg/controller" | ||||
| "github.com/AFASystems/presence/internal/pkg/database" | "github.com/AFASystems/presence/internal/pkg/database" | ||||
| "github.com/AFASystems/presence/internal/pkg/kafkaclient" | "github.com/AFASystems/presence/internal/pkg/kafkaclient" | ||||
| "github.com/AFASystems/presence/internal/pkg/model" | "github.com/AFASystems/presence/internal/pkg/model" | ||||
| "github.com/AFASystems/presence/internal/pkg/service" | |||||
| "github.com/gorilla/handlers" | "github.com/gorilla/handlers" | ||||
| "github.com/gorilla/mux" | "github.com/gorilla/mux" | ||||
| "github.com/gorilla/websocket" | "github.com/gorilla/websocket" | ||||
| @@ -66,6 +66,10 @@ func main() { | |||||
| settingsWriter := appState.AddKafkaWriter(cfg.KafkaURL, "settings") | settingsWriter := appState.AddKafkaWriter(cfg.KafkaURL, "settings") | ||||
| slog.Info("Kafka writers topics: apibeacons, settings initialized") | slog.Info("Kafka writers topics: apibeacons, settings initialized") | ||||
| if err := apiclient.UpdateDB(db, ctx, cfg, writer); err != nil { | |||||
| fmt.Printf("Error in getting token: %v\n", err) | |||||
| } | |||||
| locationReader := appState.AddKafkaReader(cfg.KafkaURL, "locevents", "gid-loc-server") | locationReader := appState.AddKafkaReader(cfg.KafkaURL, "locevents", "gid-loc-server") | ||||
| alertsReader := appState.AddKafkaReader(cfg.KafkaURL, "alertbeacons", "gid-alert-serv") | alertsReader := appState.AddKafkaReader(cfg.KafkaURL, "alertbeacons", "gid-alert-serv") | ||||
| slog.Info("Kafka readers topics: locevents, alertbeacons initialized") | slog.Info("Kafka readers topics: locevents, alertbeacons initialized") | ||||
| @@ -92,10 +96,10 @@ func main() { | |||||
| r.HandleFunc("/reslevis/removeZone/{id}", controller.ZoneDeleteController(db)).Methods("DELETE") | r.HandleFunc("/reslevis/removeZone/{id}", controller.ZoneDeleteController(db)).Methods("DELETE") | ||||
| r.HandleFunc("/reslevis/updateZone", controller.ZoneUpdateController(db)).Methods("PUT") | r.HandleFunc("/reslevis/updateZone", controller.ZoneUpdateController(db)).Methods("PUT") | ||||
| r.HandleFunc("/reslevis/getTrackerZones", controller.TrackerListController(db)).Methods("GET") | |||||
| r.HandleFunc("/reslevis/postTrackerZone", controller.TrackerAddController(db)).Methods("POST") | |||||
| r.HandleFunc("/reslevis/removeTrackerZone/{id}", controller.TrackerDeleteController(db)).Methods("DELETE") | |||||
| r.HandleFunc("/reslevis/updateTrackerZone", controller.TrackerUpdateController(db)).Methods("PUT") | |||||
| r.HandleFunc("/reslevis/getTrackerZones", controller.TrackerZoneListController(db)).Methods("GET") | |||||
| r.HandleFunc("/reslevis/postTrackerZone", controller.TrackerZoneAddController(db)).Methods("POST") | |||||
| r.HandleFunc("/reslevis/removeTrackerZone/{id}", controller.TrackerZoneDeleteController(db)).Methods("DELETE") | |||||
| r.HandleFunc("/reslevis/updateTrackerZone", controller.TrackerZoneUpdateController(db)).Methods("PUT") | |||||
| r.HandleFunc("/reslevis/getTrackers", controller.TrackerList(db)).Methods("GET") | r.HandleFunc("/reslevis/getTrackers", controller.TrackerList(db)).Methods("GET") | ||||
| r.HandleFunc("/reslevis/postTracker", controller.TrackerAdd(db, writer, ctx)).Methods("POST") | r.HandleFunc("/reslevis/postTracker", controller.TrackerAdd(db, writer, ctx)).Methods("POST") | ||||
| @@ -126,15 +130,36 @@ eventLoop: | |||||
| case <-ctx.Done(): | case <-ctx.Done(): | ||||
| break eventLoop | break eventLoop | ||||
| case msg := <-chLoc: | case msg := <-chLoc: | ||||
| if err := service.LocationToBeaconService(msg, appState, ctx); err != nil { | |||||
| eMsg := fmt.Sprintf("Error in writing location change to beacon: %v\n", err) | |||||
| slog.Error(eMsg) | |||||
| id := msg.ID | |||||
| if err := db.First(&model.Tracker{}, "id = ?", id).Error; err != nil { | |||||
| fmt.Printf("Location event for untracked beacon: %s\n", id) | |||||
| continue | |||||
| } | |||||
| if err := db.Updates(&model.Tracker{ID: id, Location: msg.Location, Distance: msg.Distance}).Error; err != nil { | |||||
| fmt.Println("Error in saving distance for beacon: ", err) | |||||
| continue | |||||
| } | } | ||||
| // if err := service.LocationToBeaconService(msg, appState, ctx); err != nil { | |||||
| // eMsg := fmt.Sprintf("Error in writing location change to beacon: %v\n", err) | |||||
| // slog.Error(eMsg) | |||||
| // } | |||||
| case msg := <-chEvents: | case msg := <-chEvents: | ||||
| if err := service.EventToBeaconService(msg, appState, ctx); err != nil { | |||||
| eMsg := fmt.Sprintf("Error in writing event change to beacon: %v\n", err) | |||||
| slog.Error(eMsg) | |||||
| fmt.Printf("event: %+v\n", msg) | |||||
| id := msg.ID | |||||
| if err := db.First(&model.Tracker{}, "id = ?", id).Error; err != nil { | |||||
| fmt.Printf("Decoder event for untracked beacon: %s\n", id) | |||||
| continue | |||||
| } | |||||
| if err := db.Updates(&model.Tracker{ID: id, Battery: msg.Battery}).Error; err != nil { | |||||
| fmt.Printf("Error in saving decoder event for beacon: %s\n", id) | |||||
| continue | |||||
| } | } | ||||
| // if err := service.EventToBeaconService(msg, appState, ctx); err != nil { | |||||
| // eMsg := fmt.Sprintf("Error in writing event change to beacon: %v\n", err) | |||||
| // slog.Error(eMsg) | |||||
| // } | |||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,161 @@ | |||||
| package main | |||||
| import ( | |||||
| "context" | |||||
| "crypto/tls" | |||||
| "encoding/json" | |||||
| "fmt" | |||||
| "net/http" | |||||
| "net/url" | |||||
| "strings" | |||||
| "github.com/AFASystems/presence/internal/pkg/model" | |||||
| ) | |||||
| type response struct { | |||||
| A string `json:"access_token"` | |||||
| } | |||||
| func main() { | |||||
| ctx := context.Background() | |||||
| tr := &http.Transport{ | |||||
| TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, | |||||
| } | |||||
| client := &http.Client{Transport: tr} | |||||
| formData := url.Values{} | |||||
| formData.Set("grant_type", "password") | |||||
| formData.Set("client_id", "Fastapi") | |||||
| formData.Set("client_secret", "wojuoB7Z5xhlPFrF2lIxJSSdVHCApEgC") | |||||
| formData.Set("username", "core") | |||||
| formData.Set("password", "C0r3_us3r_Cr3d3nt14ls") | |||||
| formData.Set("audience", "Fastapi") | |||||
| req, err := http.NewRequest("POST", "https://10.251.0.30:10002/realms/API.Server.local/protocol/openid-connect/token", strings.NewReader(formData.Encode())) | |||||
| if err != nil { | |||||
| panic(err) | |||||
| } | |||||
| req.Header.Add("Content-Type", "application/x-www-form-urlencoded") | |||||
| req = req.WithContext(ctx) | |||||
| res, err := client.Do(req) | |||||
| if err != nil { | |||||
| panic(err) | |||||
| } | |||||
| var j response | |||||
| err = json.NewDecoder(res.Body).Decode(&j) | |||||
| if err != nil { | |||||
| panic(err) | |||||
| } | |||||
| token := j.A | |||||
| trackers, err := GetTrackers(token, client) | |||||
| if err != nil { | |||||
| panic(err) | |||||
| } | |||||
| fmt.Printf("trackers: %+v\n", trackers) | |||||
| gateways, err := getGateways(token, client) | |||||
| if err != nil { | |||||
| panic(err) | |||||
| } | |||||
| fmt.Printf("gateways: %+v\n", gateways) | |||||
| zones, err := GetZones(token, client) | |||||
| if err != nil { | |||||
| panic(err) | |||||
| } | |||||
| fmt.Printf("zones: %+v\n", zones) | |||||
| trackerZones, err := GetTrackerZones(token, client) | |||||
| if err != nil { | |||||
| panic(err) | |||||
| } | |||||
| fmt.Printf("tracker zones: %+v\n", trackerZones) | |||||
| } | |||||
| func GetTrackers(token string, client *http.Client) ([]model.Tracker, error) { | |||||
| res, err := getRequest(token, "getTrackers", client) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| var i []model.Tracker | |||||
| err = json.NewDecoder(res.Body).Decode(&i) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return i, nil | |||||
| } | |||||
| func getGateways(token string, client *http.Client) ([]model.Gateway, error) { | |||||
| res, err := getRequest(token, "getGateways", client) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| var i []model.Gateway | |||||
| err = json.NewDecoder(res.Body).Decode(&i) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return i, nil | |||||
| } | |||||
| func GetTrackerZones(token string, client *http.Client) ([]model.TrackerZones, error) { | |||||
| res, err := getRequest(token, "getTrackerZones", client) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| var i []model.TrackerZones | |||||
| err = json.NewDecoder(res.Body).Decode(&i) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return i, nil | |||||
| } | |||||
| func GetZones(token string, client *http.Client) ([]model.Zone, error) { | |||||
| res, err := getRequest(token, "getZones", client) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| var i []model.Zone | |||||
| err = json.NewDecoder(res.Body).Decode(&i) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return i, nil | |||||
| } | |||||
| func getRequest(token, route string, client *http.Client) (*http.Response, error) { | |||||
| url := fmt.Sprintf("https://10.251.0.30:5050/reslevis/%s", route) | |||||
| req, err := http.NewRequest("GET", url, nil) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| header := fmt.Sprintf("Bearer %s", token) | |||||
| req.Header.Add("Authorization", header) | |||||
| res, err := client.Do(req) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return res, nil | |||||
| } | |||||
| @@ -0,0 +1,45 @@ | |||||
| package apiclient | |||||
| import ( | |||||
| "context" | |||||
| "encoding/json" | |||||
| "net/http" | |||||
| "net/url" | |||||
| "strings" | |||||
| "github.com/AFASystems/presence/internal/pkg/config" | |||||
| ) | |||||
| type response struct { | |||||
| Token string `json:"access_token"` | |||||
| } | |||||
| func GetToken(ctx context.Context, cfg *config.Config, client *http.Client) (string, error) { | |||||
| formData := url.Values{} | |||||
| formData.Set("grant_type", "password") | |||||
| formData.Set("client_id", "Fastapi") | |||||
| formData.Set("client_secret", "wojuoB7Z5xhlPFrF2lIxJSSdVHCApEgC") | |||||
| formData.Set("username", "core") | |||||
| formData.Set("password", "C0r3_us3r_Cr3d3nt14ls") | |||||
| formData.Set("audience", "Fastapi") | |||||
| req, err := http.NewRequest("POST", "https://10.251.0.30:10002/realms/API.Server.local/protocol/openid-connect/token", strings.NewReader(formData.Encode())) | |||||
| if err != nil { | |||||
| return "", err | |||||
| } | |||||
| req.Header.Add("Content-Type", "application/x-www-form-urlencoded") | |||||
| req = req.WithContext(ctx) | |||||
| res, err := client.Do(req) | |||||
| if err != nil { | |||||
| return "", err | |||||
| } | |||||
| var j response | |||||
| if err := json.NewDecoder(res.Body).Decode(&j); err != nil { | |||||
| return "", err | |||||
| } | |||||
| return j.Token, nil | |||||
| } | |||||
| @@ -0,0 +1,87 @@ | |||||
| package apiclient | |||||
| import ( | |||||
| "encoding/json" | |||||
| "fmt" | |||||
| "net/http" | |||||
| "github.com/AFASystems/presence/internal/pkg/model" | |||||
| ) | |||||
| func GetTrackers(token string, client *http.Client) ([]model.Tracker, error) { | |||||
| res, err := getRequest(token, "getTrackers", client) | |||||
| if err != nil { | |||||
| return []model.Tracker{}, err | |||||
| } | |||||
| var i []model.Tracker | |||||
| err = json.NewDecoder(res.Body).Decode(&i) | |||||
| if err != nil { | |||||
| return []model.Tracker{}, err | |||||
| } | |||||
| return i, nil | |||||
| } | |||||
| func GetGateways(token string, client *http.Client) ([]model.Gateway, error) { | |||||
| res, err := getRequest(token, "getGateways", client) | |||||
| if err != nil { | |||||
| return []model.Gateway{}, err | |||||
| } | |||||
| var i []model.Gateway | |||||
| err = json.NewDecoder(res.Body).Decode(&i) | |||||
| if err != nil { | |||||
| return []model.Gateway{}, err | |||||
| } | |||||
| return i, nil | |||||
| } | |||||
| func GetTrackerZones(token string, client *http.Client) ([]model.TrackerZones, error) { | |||||
| res, err := getRequest(token, "getTrackerZones", client) | |||||
| if err != nil { | |||||
| return []model.TrackerZones{}, err | |||||
| } | |||||
| var i []model.TrackerZones | |||||
| err = json.NewDecoder(res.Body).Decode(&i) | |||||
| if err != nil { | |||||
| return []model.TrackerZones{}, err | |||||
| } | |||||
| return i, nil | |||||
| } | |||||
| func GetZones(token string, client *http.Client) ([]model.Zone, error) { | |||||
| res, err := getRequest(token, "getZones", client) | |||||
| if err != nil { | |||||
| return []model.Zone{}, err | |||||
| } | |||||
| var i []model.Zone | |||||
| err = json.NewDecoder(res.Body).Decode(&i) | |||||
| if err != nil { | |||||
| return []model.Zone{}, err | |||||
| } | |||||
| return i, nil | |||||
| } | |||||
| func getRequest(token, route string, client *http.Client) (*http.Response, error) { | |||||
| url := fmt.Sprintf("https://10.251.0.30:5050/reslevis/%s", route) | |||||
| req, err := http.NewRequest("GET", url, nil) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| header := fmt.Sprintf("Bearer %s", token) | |||||
| req.Header.Add("Authorization", header) | |||||
| res, err := client.Do(req) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return res, nil | |||||
| } | |||||
| @@ -0,0 +1,79 @@ | |||||
| package apiclient | |||||
| import ( | |||||
| "context" | |||||
| "crypto/tls" | |||||
| "fmt" | |||||
| "net/http" | |||||
| "github.com/AFASystems/presence/internal/pkg/config" | |||||
| "github.com/AFASystems/presence/internal/pkg/controller" | |||||
| "github.com/AFASystems/presence/internal/pkg/model" | |||||
| "github.com/segmentio/kafka-go" | |||||
| "gorm.io/gorm" | |||||
| "gorm.io/gorm/clause" | |||||
| ) | |||||
| func UpdateDB(db *gorm.DB, ctx context.Context, cfg *config.Config, writer *kafka.Writer) error { | |||||
| tr := &http.Transport{ | |||||
| TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, | |||||
| } | |||||
| client := &http.Client{Transport: tr} | |||||
| token, err := GetToken(ctx, cfg, client) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| trackers, err := GetTrackers(token, client) | |||||
| if err != nil { | |||||
| fmt.Printf("Error in getting trackers: %+v\n", err) | |||||
| } | |||||
| if err := controller.SendKafkaMessage(writer, &model.ApiUpdate{Method: "DELETE", MAC: "all"}, ctx); err != nil { | |||||
| fmt.Printf("Error in sending delete all from lookup message: %v", err) | |||||
| } | |||||
| for _, v := range trackers { | |||||
| apiUpdate := model.ApiUpdate{ | |||||
| Method: "POST", | |||||
| ID: v.ID, | |||||
| MAC: v.MAC, | |||||
| } | |||||
| if err := controller.SendKafkaMessage(writer, &apiUpdate, ctx); err != nil { | |||||
| fmt.Printf("Error in sending POST kafka message: %v", err) | |||||
| } | |||||
| } | |||||
| gateways, err := GetGateways(token, client) | |||||
| if err != nil { | |||||
| fmt.Printf("Error in getting gateways: %+v\n", err) | |||||
| } | |||||
| zones, err := GetZones(token, client) | |||||
| if err != nil { | |||||
| fmt.Printf("Error in getting zones: %+v\n", err) | |||||
| } | |||||
| trackerZones, err := GetTrackerZones(token, client) | |||||
| if err != nil { | |||||
| fmt.Printf("Error in getting tracker zones: %+v\n", err) | |||||
| } | |||||
| db.Clauses(clause.OnConflict{ | |||||
| Columns: []clause.Column{{Name: "id"}}, | |||||
| UpdateAll: true, | |||||
| }).Create(&trackers) | |||||
| db.Clauses(clause.OnConflict{ | |||||
| Columns: []clause.Column{{Name: "id"}}, | |||||
| UpdateAll: true, | |||||
| }).Create(&gateways) | |||||
| db.Clauses(clause.OnConflict{ | |||||
| Columns: []clause.Column{{Name: "id"}}, | |||||
| UpdateAll: true, | |||||
| }).Create(&zones) | |||||
| db.Clauses(clause.OnConflict{ | |||||
| Columns: []clause.Column{{Name: "id"}}, | |||||
| UpdateAll: true, | |||||
| }).Create(&trackerZones) | |||||
| return nil | |||||
| } | |||||
| @@ -15,7 +15,7 @@ type AppState struct { | |||||
| httpResults model.HTTPResultList | httpResults model.HTTPResultList | ||||
| settings model.Settings | settings model.Settings | ||||
| beaconEvents model.BeaconEventList | beaconEvents model.BeaconEventList | ||||
| beaconsLookup map[string]struct{} | |||||
| beaconsLookup map[string]string | |||||
| latestList model.LatestBeaconsList | latestList model.LatestBeaconsList | ||||
| kafkaReadersList model.KafkaReadersList | kafkaReadersList model.KafkaReadersList | ||||
| kafkaWritersList model.KafkaWritersList | kafkaWritersList model.KafkaWritersList | ||||
| @@ -44,7 +44,7 @@ func NewAppState() *AppState { | |||||
| beaconEvents: model.BeaconEventList{ | beaconEvents: model.BeaconEventList{ | ||||
| Beacons: make(map[string]model.BeaconEvent), | Beacons: make(map[string]model.BeaconEvent), | ||||
| }, | }, | ||||
| beaconsLookup: make(map[string]struct{}), | |||||
| beaconsLookup: make(map[string]string), | |||||
| latestList: model.LatestBeaconsList{ | latestList: model.LatestBeaconsList{ | ||||
| LatestList: make(map[string]model.Beacon), | LatestList: make(map[string]model.Beacon), | ||||
| }, | }, | ||||
| @@ -129,7 +129,7 @@ func (m *AppState) GetBeaconEvents() *model.BeaconEventList { | |||||
| } | } | ||||
| // GetBeaconsLookup returns thread-safe access to beacon lookup map | // GetBeaconsLookup returns thread-safe access to beacon lookup map | ||||
| func (m *AppState) GetBeaconsLookup() map[string]struct{} { | |||||
| func (m *AppState) GetBeaconsLookup() map[string]string { | |||||
| return m.beaconsLookup | return m.beaconsLookup | ||||
| } | } | ||||
| @@ -139,8 +139,8 @@ func (m *AppState) GetLatestList() *model.LatestBeaconsList { | |||||
| } | } | ||||
| // AddBeaconToLookup adds a beacon ID to the lookup map | // AddBeaconToLookup adds a beacon ID to the lookup map | ||||
| func (m *AppState) AddBeaconToLookup(id string) { | |||||
| m.beaconsLookup[id] = struct{}{} | |||||
| func (m *AppState) AddBeaconToLookup(id, value string) { | |||||
| m.beaconsLookup[id] = value | |||||
| } | } | ||||
| // RemoveBeaconFromLookup removes a beacon ID from the lookup map | // RemoveBeaconFromLookup removes a beacon ID from the lookup map | ||||
| @@ -148,6 +148,10 @@ func (m *AppState) RemoveBeaconFromLookup(id string) { | |||||
| delete(m.beaconsLookup, id) | delete(m.beaconsLookup, id) | ||||
| } | } | ||||
| func (m *AppState) CleanLookup() { | |||||
| clear(m.beaconsLookup) | |||||
| } | |||||
| func (m *AppState) RemoveBeacon(id string) { | func (m *AppState) RemoveBeacon(id string) { | ||||
| m.beacons.Lock.Lock() | m.beacons.Lock.Lock() | ||||
| delete(m.beacons.Beacons, id) | delete(m.beacons.Beacons, id) | ||||
| @@ -161,9 +165,9 @@ func (m *AppState) RemoveHTTPResult(id string) { | |||||
| } | } | ||||
| // BeaconExists checks if a beacon exists in the lookup | // BeaconExists checks if a beacon exists in the lookup | ||||
| func (m *AppState) BeaconExists(id string) bool { | |||||
| _, exists := m.beaconsLookup[id] | |||||
| return exists | |||||
| func (m *AppState) BeaconExists(id string) (string, bool) { | |||||
| val, exists := m.beaconsLookup[id] | |||||
| return val, exists | |||||
| } | } | ||||
| // GetBeacon returns a beacon by ID (thread-safe) | // GetBeacon returns a beacon by ID (thread-safe) | ||||
| @@ -14,6 +14,11 @@ type Config struct { | |||||
| DBUser string | DBUser string | ||||
| DBPass string | DBPass string | ||||
| DBName string | DBName string | ||||
| HTTPClientID string | |||||
| ClientSecret string | |||||
| HTTPUsername string | |||||
| HTTPPassword string | |||||
| HTTPAudience string | |||||
| } | } | ||||
| // getEnv returns env var value or a default if not set. | // getEnv returns env var value or a default if not set. | ||||
| @@ -37,5 +42,10 @@ func Load() *Config { | |||||
| DBUser: getEnv("DBUser", "postgres"), | DBUser: getEnv("DBUser", "postgres"), | ||||
| DBPass: getEnv("DBPass", "postgres"), | DBPass: getEnv("DBPass", "postgres"), | ||||
| DBName: getEnv("DBName", "go_crud_db"), | DBName: getEnv("DBName", "go_crud_db"), | ||||
| HTTPClientID: getEnv("HTTPClientID", "Fastapi"), | |||||
| ClientSecret: getEnv("ClientSecret", "wojuoB7Z5xhlPFrF2lIxJSSdVHCApEgC"), | |||||
| HTTPUsername: getEnv("HTTPUsername", "core"), | |||||
| HTTPPassword: getEnv("HTTPPassword", "C0r3_us3r_Cr3d3nt14ls"), | |||||
| HTTPAudience: getEnv("HTTPAudience", "Fastapi"), | |||||
| } | } | ||||
| } | } | ||||
| @@ -12,7 +12,7 @@ import ( | |||||
| "gorm.io/gorm" | "gorm.io/gorm" | ||||
| ) | ) | ||||
| func sendKafkaMessage(writer *kafka.Writer, value *model.ApiUpdate, ctx context.Context) error { | |||||
| func SendKafkaMessage(writer *kafka.Writer, value *model.ApiUpdate, ctx context.Context) error { | |||||
| valueStr, err := json.Marshal(&value) | valueStr, err := json.Marshal(&value) | ||||
| if err != nil { | if err != nil { | ||||
| fmt.Println("error in encoding: ", err) | fmt.Println("error in encoding: ", err) | ||||
| @@ -42,9 +42,10 @@ func TrackerAdd(db *gorm.DB, writer *kafka.Writer, ctx context.Context) http.Han | |||||
| apiUpdate := model.ApiUpdate{ | apiUpdate := model.ApiUpdate{ | ||||
| Method: "POST", | Method: "POST", | ||||
| ID: tracker.ID, | ID: tracker.ID, | ||||
| MAC: tracker.MAC, | |||||
| } | } | ||||
| if err := sendKafkaMessage(writer, &apiUpdate, ctx); err != nil { | |||||
| if err := SendKafkaMessage(writer, &apiUpdate, ctx); err != nil { | |||||
| fmt.Println("error in sending Kafka POST message") | fmt.Println("error in sending Kafka POST message") | ||||
| http.Error(w, "Error in sending kafka message", 500) | http.Error(w, "Error in sending kafka message", 500) | ||||
| return | return | ||||
| @@ -90,6 +91,9 @@ func TrackerUpdate(db *gorm.DB) http.HandlerFunc { | |||||
| func TrackerDelete(db *gorm.DB, writer *kafka.Writer, ctx context.Context) http.HandlerFunc { | func TrackerDelete(db *gorm.DB, writer *kafka.Writer, ctx context.Context) http.HandlerFunc { | ||||
| return func(w http.ResponseWriter, r *http.Request) { | return func(w http.ResponseWriter, r *http.Request) { | ||||
| id := mux.Vars(r)["id"] | id := mux.Vars(r)["id"] | ||||
| var tracker model.Tracker | |||||
| db.Find(&tracker, "id = ?", id) | |||||
| if res := db.Delete(&model.Tracker{}, "id = ?", id); res.RowsAffected == 0 { | if res := db.Delete(&model.Tracker{}, "id = ?", id); res.RowsAffected == 0 { | ||||
| http.Error(w, "no tracker with such ID found", 400) | http.Error(w, "no tracker with such ID found", 400) | ||||
| return | return | ||||
| @@ -97,12 +101,12 @@ func TrackerDelete(db *gorm.DB, writer *kafka.Writer, ctx context.Context) http. | |||||
| apiUpdate := model.ApiUpdate{ | apiUpdate := model.ApiUpdate{ | ||||
| Method: "Delete", | Method: "Delete", | ||||
| ID: id, | |||||
| ID: tracker.ID, | |||||
| } | } | ||||
| fmt.Printf("Sending DELETE tracker id: %s message\n", id) | fmt.Printf("Sending DELETE tracker id: %s message\n", id) | ||||
| if err := sendKafkaMessage(writer, &apiUpdate, ctx); err != nil { | |||||
| if err := SendKafkaMessage(writer, &apiUpdate, ctx); err != nil { | |||||
| fmt.Println("error in sending Kafka DELETE message") | fmt.Println("error in sending Kafka DELETE message") | ||||
| http.Error(w, "Error in sending kafka message", 500) | http.Error(w, "Error in sending kafka message", 500) | ||||
| return | return | ||||
| @@ -10,7 +10,7 @@ import ( | |||||
| ) | ) | ||||
| // controller/tracker_controller.go | // controller/tracker_controller.go | ||||
| func TrackerAddController(db *gorm.DB) http.HandlerFunc { | |||||
| func TrackerZoneAddController(db *gorm.DB) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | return func(w http.ResponseWriter, r *http.Request) { | ||||
| var tz model.TrackerZones | var tz model.TrackerZones | ||||
| if err := json.NewDecoder(r.Body).Decode(&tz); err != nil { | if err := json.NewDecoder(r.Body).Decode(&tz); err != nil { | ||||
| @@ -22,7 +22,7 @@ func TrackerAddController(db *gorm.DB) http.HandlerFunc { | |||||
| } | } | ||||
| } | } | ||||
| func TrackerListController(db *gorm.DB) http.HandlerFunc { | |||||
| func TrackerZoneListController(db *gorm.DB) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | return func(w http.ResponseWriter, r *http.Request) { | ||||
| var list []model.TrackerZones | var list []model.TrackerZones | ||||
| db.Find(&list) | db.Find(&list) | ||||
| @@ -30,7 +30,7 @@ func TrackerListController(db *gorm.DB) http.HandlerFunc { | |||||
| } | } | ||||
| } | } | ||||
| func TrackerUpdateController(db *gorm.DB) http.HandlerFunc { | |||||
| func TrackerZoneUpdateController(db *gorm.DB) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | return func(w http.ResponseWriter, r *http.Request) { | ||||
| var tz model.TrackerZones | var tz model.TrackerZones | ||||
| @@ -55,7 +55,7 @@ func TrackerUpdateController(db *gorm.DB) http.HandlerFunc { | |||||
| } | } | ||||
| } | } | ||||
| func TrackerDeleteController(db *gorm.DB) http.HandlerFunc { | |||||
| func TrackerZoneDeleteController(db *gorm.DB) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | return func(w http.ResponseWriter, r *http.Request) { | ||||
| id := mux.Vars(r)["id"] | id := mux.Vars(r)["id"] | ||||
| if res := db.Delete(&model.TrackerZones{}, "id = ?", id); res.RowsAffected == 0 { | if res := db.Delete(&model.TrackerZones{}, "id = ?", id); res.RowsAffected == 0 { | ||||
| @@ -1,16 +1,16 @@ | |||||
| package model | package model | ||||
| type Gateway struct { | type Gateway struct { | ||||
| ID string `json:"id" gorm:"primaryKey"` | |||||
| Name string `json:"name"` | |||||
| MAC string `json:"mac"` | |||||
| Status string `json:"status"` | |||||
| Model string `json:"model"` | |||||
| IP string `json:"ip"` | |||||
| Position string `json:"position"` | |||||
| X int `json:"x"` | |||||
| Y int `json:"y"` | |||||
| Notes string `json:"notes"` | |||||
| Floor string `json:"floor"` | |||||
| Building string `json:"building"` | |||||
| ID string `json:"id" gorm:"primaryKey"` | |||||
| Name string `json:"name"` | |||||
| MAC string `json:"mac"` | |||||
| Status string `json:"status"` | |||||
| Model string `json:"model"` | |||||
| IP string `json:"ip"` | |||||
| Position string `json:"position"` | |||||
| X float32 `json:"x"` | |||||
| Y float32 `json:"y"` | |||||
| Notes string `json:"notes"` | |||||
| Floor string `json:"floor"` | |||||
| Building string `json:"building"` | |||||
| } | } | ||||
| @@ -1,15 +1,18 @@ | |||||
| package model | package model | ||||
| type Tracker struct { | type Tracker struct { | ||||
| ID string `json:"id" gorm:"primaryKey` | |||||
| Name string `json:"name"` | |||||
| MAC string `json:"mac"` | |||||
| Status string `json:"status"` | |||||
| Model string `json:"model"` | |||||
| Position string `json:"position"` | |||||
| Notes string `json:"notes"` | |||||
| X int `json:"x"` | |||||
| Y int `json:"y"` | |||||
| Floor string `json:"floor" gorm:"type:uuid"` | |||||
| Building string `json:"building" gorm:"type:uuid"` | |||||
| ID string `json:"id" gorm:"primaryKey"` | |||||
| Name string `json:"name"` | |||||
| MAC string `json:"mac"` | |||||
| Status string `json:"status"` | |||||
| Model string `json:"model"` | |||||
| Position string `json:"position"` | |||||
| Notes string `json:"notes"` | |||||
| X float32 `json:"x"` | |||||
| Y float32 `json:"y"` | |||||
| Floor string `json:"floor"` | |||||
| Building string `json:"building"` | |||||
| Location string `json:"location"` | |||||
| Distance float64 `json:"distance"` | |||||
| Battery uint32 `json:"battery"` | |||||
| } | } | ||||
| @@ -24,6 +24,7 @@ type Settings struct { | |||||
| // BeaconAdvertisement represents the JSON payload received from beacon advertisements. | // BeaconAdvertisement represents the JSON payload received from beacon advertisements. | ||||
| type BeaconAdvertisement struct { | type BeaconAdvertisement struct { | ||||
| ID string | |||||
| Hostname string `json:"hostname"` | Hostname string `json:"hostname"` | ||||
| MAC string `json:"mac"` | MAC string `json:"mac"` | ||||
| RSSI int64 `json:"rssi"` | RSSI int64 `json:"rssi"` | ||||
| @@ -169,8 +170,8 @@ type LatestBeaconsList struct { | |||||
| type ApiUpdate struct { | type ApiUpdate struct { | ||||
| Method string | Method string | ||||
| Beacon HTTPResult | |||||
| ID string | ID string | ||||
| MAC string | |||||
| } | } | ||||
| type KafkaReadersList struct { | type KafkaReadersList struct { | ||||