| @@ -79,16 +79,6 @@ func main() { | |||||
| r := mux.NewRouter() | r := mux.NewRouter() | ||||
| r.HandleFunc("/api/beacons/{beacon_id}", controller.BeaconsDeleteController(writer, ctx, appState)).Methods("DELETE") | |||||
| r.HandleFunc("/api/beacons", controller.BeaconsListController(appState)).Methods("GET") | |||||
| r.HandleFunc("/api/beacons/{beacon_id}", controller.BeaconsListSingleController(appState)).Methods("GET") | |||||
| r.HandleFunc("/api/beacons", controller.BeaconsAddController(writer, ctx, appState)).Methods("POST") | |||||
| r.HandleFunc("/api/beacons", controller.BeaconsAddController(writer, ctx, appState)).Methods("PUT") | |||||
| r.HandleFunc("/api/addbeacons", controller.AddListOfBeaconsController(writer, ctx, appState)).Methods("POST") | |||||
| r.HandleFunc("/api/beaconids", controller.GetBeaconIds(appState)).Methods("GET") | |||||
| r.HandleFunc("/api/settings", controller.SettingsListController(appState, ctx)).Methods("GET") | r.HandleFunc("/api/settings", controller.SettingsListController(appState, ctx)).Methods("GET") | ||||
| r.HandleFunc("/api/settings", controller.SettingsEditController(settingsWriter, appState, ctx)).Methods("POST") | r.HandleFunc("/api/settings", controller.SettingsEditController(settingsWriter, appState, ctx)).Methods("POST") | ||||
| @@ -107,6 +97,11 @@ func main() { | |||||
| r.HandleFunc("/reslevis/removeTrackerZone/{id}", controller.TrackerDeleteController(db)).Methods("DELETE") | r.HandleFunc("/reslevis/removeTrackerZone/{id}", controller.TrackerDeleteController(db)).Methods("DELETE") | ||||
| r.HandleFunc("/reslevis/updateTrackerZone", controller.TrackerUpdateController(db)).Methods("PUT") | r.HandleFunc("/reslevis/updateTrackerZone", controller.TrackerUpdateController(db)).Methods("PUT") | ||||
| r.HandleFunc("/reslevis/getTrackers", controller.TrackerList(db)).Methods("GET") | |||||
| r.HandleFunc("/reslevis/postTracker", controller.TrackerAdd(db, writer, ctx)).Methods("POST") | |||||
| r.HandleFunc("/reslevis/removeTracker/{id}", controller.TrackerDelete(db, writer, ctx)).Methods("DELETE") | |||||
| r.HandleFunc("/reslevis/updateTracker", controller.TrackerUpdate(db)).Methods("PUT") | |||||
| wsHandler := http.HandlerFunc(serveWs(appState, ctx)) | wsHandler := http.HandlerFunc(serveWs(appState, ctx)) | ||||
| restApiHandler := handlers.CORS(originsOk, headersOk, methodsOk)(r) | restApiHandler := handlers.CORS(originsOk, headersOk, methodsOk)(r) | ||||
| mainHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | mainHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| @@ -1,175 +0,0 @@ | |||||
| package controller | |||||
| import ( | |||||
| "context" | |||||
| "encoding/json" | |||||
| "fmt" | |||||
| "net/http" | |||||
| "github.com/AFASystems/presence/internal/pkg/common/appcontext" | |||||
| "github.com/AFASystems/presence/internal/pkg/model" | |||||
| "github.com/gorilla/mux" | |||||
| "github.com/segmentio/kafka-go" | |||||
| ) | |||||
| func GetBeaconIds(appstate *appcontext.AppState) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | |||||
| beacons := appstate.GetAllHttpResults() | |||||
| bIds := make([]string, len(beacons)) | |||||
| i := 0 | |||||
| for k := range beacons { | |||||
| bIds[i] = k | |||||
| i++ | |||||
| } | |||||
| w.Header().Set("Content-Type", "application/json") | |||||
| w.WriteHeader(http.StatusOK) | |||||
| json.NewEncoder(w).Encode(bIds) | |||||
| } | |||||
| } | |||||
| func BeaconsListSingleController(appstate *appcontext.AppState) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | |||||
| vars := mux.Vars(r) | |||||
| id := vars["beacon_id"] | |||||
| beacon, ok := appstate.GetHTTPResult(id) | |||||
| if !ok { | |||||
| w.Header().Set("Content-Type", "application/json") | |||||
| w.WriteHeader(http.StatusNotFound) | |||||
| json.NewEncoder(w).Encode(map[string]string{"error": "Beacon not found"}) | |||||
| return | |||||
| } | |||||
| w.Header().Set("Content-Type", "application/json") | |||||
| w.WriteHeader(http.StatusOK) | |||||
| json.NewEncoder(w).Encode(beacon) | |||||
| } | |||||
| } | |||||
| func BeaconsListController(appstate *appcontext.AppState) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | |||||
| beacons := appstate.GetAllHttpResults() | |||||
| values := make([]model.HTTPResult, len(beacons)) | |||||
| i := 0 | |||||
| for k, v := range beacons { | |||||
| if k == "" { | |||||
| continue | |||||
| } | |||||
| values[i] = v | |||||
| i++ | |||||
| } | |||||
| w.Header().Set("Content-Type", "application/json") | |||||
| w.WriteHeader(http.StatusOK) | |||||
| json.NewEncoder(w).Encode(values) | |||||
| } | |||||
| } | |||||
| // Probably define value as interface and then reuse this writer in all of the functions | |||||
| func sendKafkaMessage(writer *kafka.Writer, value *model.ApiUpdate, ctx context.Context) error { | |||||
| valueStr, err := json.Marshal(&value) | |||||
| if err != nil { | |||||
| fmt.Println("error in encoding: ", err) | |||||
| return err | |||||
| } | |||||
| msg := kafka.Message{ | |||||
| Value: valueStr, | |||||
| } | |||||
| if err := writer.WriteMessages(ctx, msg); err != nil { | |||||
| fmt.Println("Error in sending kafka message: ", err) | |||||
| return err | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func BeaconsDeleteController(writer *kafka.Writer, ctx context.Context, appstate *appcontext.AppState) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | |||||
| vars := mux.Vars(r) | |||||
| beaconId := vars["beacon_id"] | |||||
| apiUpdate := model.ApiUpdate{ | |||||
| Method: "DELETE", | |||||
| ID: beaconId, | |||||
| } | |||||
| fmt.Printf("Sending DELETE beacon id: %s message\n", beaconId) | |||||
| if err := sendKafkaMessage(writer, &apiUpdate, ctx); err != nil { | |||||
| fmt.Println("error in sending Kafka DELETE message") | |||||
| http.Error(w, "Error in sending kafka message", 500) | |||||
| return | |||||
| } | |||||
| // If message is succesfully sent delete the beacon from the list | |||||
| appstate.RemoveHTTPResult(beaconId) | |||||
| w.Write([]byte("ok")) | |||||
| } | |||||
| } | |||||
| func BeaconAddService(writer *kafka.Writer, ctx context.Context, appstate *appcontext.AppState, beacon model.HTTPResult) error { | |||||
| id := beacon.ID | |||||
| appstate.UpdateHTTPResult(id, beacon) | |||||
| apiUpdate := model.ApiUpdate{ | |||||
| Method: "POST", | |||||
| Beacon: beacon, | |||||
| } | |||||
| if err := sendKafkaMessage(writer, &apiUpdate, ctx); err != nil { | |||||
| return err | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func BeaconsAddController(writer *kafka.Writer, ctx context.Context, appstate *appcontext.AppState) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | |||||
| decoder := json.NewDecoder(r.Body) | |||||
| var inBeacon model.HTTPResult | |||||
| err := decoder.Decode(&inBeacon) | |||||
| if err != nil { | |||||
| http.Error(w, err.Error(), 400) | |||||
| return | |||||
| } | |||||
| if inBeacon.ID == "" { | |||||
| http.Error(w, "Beacon needs to include MAC addr", 400) | |||||
| return | |||||
| } | |||||
| if err := BeaconAddService(writer, ctx, appstate, inBeacon); err != nil { | |||||
| fmt.Println("error in sending Kafka POST message") | |||||
| http.Error(w, "Error in sending kafka message", 500) | |||||
| return | |||||
| } | |||||
| w.Write([]byte("ok")) | |||||
| } | |||||
| } | |||||
| func AddListOfBeaconsController(writer *kafka.Writer, ctx context.Context, appstate *appcontext.AppState) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | |||||
| decoder := json.NewDecoder(r.Body) | |||||
| var inBeacons []model.HTTPResult | |||||
| if err := decoder.Decode(&inBeacons); err != nil { | |||||
| http.Error(w, err.Error(), 400) | |||||
| return | |||||
| } | |||||
| for _, v := range inBeacons { | |||||
| if v.ID == "" { | |||||
| fmt.Println("One of the beacons is missing MAC address") | |||||
| http.Error(w, "One of the beacons is missing MAC address", 400) | |||||
| return | |||||
| } | |||||
| if err := BeaconAddService(writer, ctx, appstate, v); err != nil { | |||||
| fmt.Println("error in sending Kafka POST message") | |||||
| http.Error(w, "Error in sending kafka message", 500) | |||||
| return | |||||
| } | |||||
| } | |||||
| w.Write([]byte("ok")) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,113 @@ | |||||
| package controller | |||||
| import ( | |||||
| "context" | |||||
| "encoding/json" | |||||
| "fmt" | |||||
| "net/http" | |||||
| "github.com/AFASystems/presence/internal/pkg/model" | |||||
| "github.com/gorilla/mux" | |||||
| "github.com/segmentio/kafka-go" | |||||
| "gorm.io/gorm" | |||||
| ) | |||||
| func sendKafkaMessage(writer *kafka.Writer, value *model.ApiUpdate, ctx context.Context) error { | |||||
| valueStr, err := json.Marshal(&value) | |||||
| if err != nil { | |||||
| fmt.Println("error in encoding: ", err) | |||||
| return err | |||||
| } | |||||
| msg := kafka.Message{ | |||||
| Value: valueStr, | |||||
| } | |||||
| if err := writer.WriteMessages(ctx, msg); err != nil { | |||||
| fmt.Println("Error in sending kafka message: ", err) | |||||
| return err | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func TrackerAdd(db *gorm.DB, writer *kafka.Writer, ctx context.Context) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | |||||
| var tracker model.Tracker | |||||
| if err := json.NewDecoder(r.Body).Decode(&tracker); err != nil { | |||||
| http.Error(w, err.Error(), 400) | |||||
| return | |||||
| } | |||||
| db.Create(&tracker) | |||||
| apiUpdate := model.ApiUpdate{ | |||||
| Method: "POST", | |||||
| ID: tracker.ID, | |||||
| } | |||||
| if err := sendKafkaMessage(writer, &apiUpdate, ctx); err != nil { | |||||
| fmt.Println("error in sending Kafka POST message") | |||||
| http.Error(w, "Error in sending kafka message", 500) | |||||
| return | |||||
| } | |||||
| w.Write([]byte("ok")) | |||||
| } | |||||
| } | |||||
| func TrackerList(db *gorm.DB) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | |||||
| var list []model.Tracker | |||||
| db.Find(&list) | |||||
| json.NewEncoder(w).Encode(list) | |||||
| } | |||||
| } | |||||
| func TrackerUpdate(db *gorm.DB) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | |||||
| var tracker model.Tracker | |||||
| if err := json.NewDecoder(r.Body).Decode(&tracker); err != nil { | |||||
| http.Error(w, "Invalid JSON", 400) | |||||
| return | |||||
| } | |||||
| id := tracker.ID | |||||
| if err := db.First(&model.Tracker{}, "id = ?", id).Error; err != nil { | |||||
| http.Error(w, err.Error(), 400) | |||||
| return | |||||
| } | |||||
| if err := db.Save(&tracker).Error; err != nil { | |||||
| http.Error(w, err.Error(), 500) | |||||
| return | |||||
| } | |||||
| w.Write([]byte("ok")) | |||||
| } | |||||
| } | |||||
| func TrackerDelete(db *gorm.DB, writer *kafka.Writer, ctx context.Context) http.HandlerFunc { | |||||
| return func(w http.ResponseWriter, r *http.Request) { | |||||
| id := mux.Vars(r)["id"] | |||||
| if res := db.Delete(&model.Tracker{}, "id = ?", id); res.RowsAffected == 0 { | |||||
| http.Error(w, "no tracker with such ID found", 400) | |||||
| return | |||||
| } | |||||
| apiUpdate := model.ApiUpdate{ | |||||
| Method: "Delete", | |||||
| ID: id, | |||||
| } | |||||
| fmt.Printf("Sending DELETE tracker id: %s message\n", id) | |||||
| if err := sendKafkaMessage(writer, &apiUpdate, ctx); err != nil { | |||||
| fmt.Println("error in sending Kafka DELETE message") | |||||
| http.Error(w, "Error in sending kafka message", 500) | |||||
| return | |||||
| } | |||||
| w.Write([]byte("ok")) | |||||
| } | |||||
| } | |||||
| @@ -26,7 +26,7 @@ func Connect(cfg *config.Config) (*gorm.DB, error) { | |||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| if err := db.AutoMigrate(&model.Gateway{}, model.Zone{}, model.TrackerZones{}); err != nil { | |||||
| if err := db.AutoMigrate(&model.Gateway{}, model.Zone{}, model.TrackerZones{}, model.Tracker{}); err != nil { | |||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| @@ -1,7 +1,7 @@ | |||||
| package model | package model | ||||
| type TrackerZones struct { | type TrackerZones struct { | ||||
| ID string `json:"id"` | |||||
| ID string `json:"id" gorm:"primaryKey"` | |||||
| ZoneList []string `json:"zoneList" gorm:"serializer:json"` | ZoneList []string `json:"zoneList" gorm:"serializer:json"` | ||||
| Tracker string `json:"tracker"` | Tracker string `json:"tracker"` | ||||
| Days string `json:"days"` | Days string `json:"days"` | ||||
| @@ -0,0 +1,15 @@ | |||||
| package model | |||||
| 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"` | |||||
| } | |||||