| @@ -79,16 +79,6 @@ func main() { | |||
| 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.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/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)) | |||
| restApiHandler := handlers.CORS(originsOk, headersOk, methodsOk)(r) | |||
| 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 | |||
| } | |||
| 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 | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| package model | |||
| type TrackerZones struct { | |||
| ID string `json:"id"` | |||
| ID string `json:"id" gorm:"primaryKey"` | |||
| ZoneList []string `json:"zoneList" gorm:"serializer:json"` | |||
| Tracker string `json:"tracker"` | |||
| 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"` | |||
| } | |||