From 08ef01bf1f20fedee45660bea28b14c3aef77067 Mon Sep 17 00:00:00 2001 From: leandrofars Date: Tue, 28 Nov 2023 11:59:06 -0300 Subject: [PATCH] feat(controller): list devices with pagination --- .../services/controller/internal/api/api.go | 1 + .../controller/internal/api/device.go | 88 ++++++++++++++++++- .../services/controller/internal/db/device.go | 31 ++++--- 3 files changed, 105 insertions(+), 15 deletions(-) diff --git a/backend/services/controller/internal/api/api.go b/backend/services/controller/internal/api/api.go index cbb8643..4a247ca 100644 --- a/backend/services/controller/internal/api/api.go +++ b/backend/services/controller/internal/api/api.go @@ -52,6 +52,7 @@ func StartApi(a Api) { iot := r.PathPrefix("/api/device").Subrouter() //TODO: create query for devices iot.HandleFunc("", a.retrieveDevices).Methods("GET") + iot.HandleFunc("/{id}", a.retrieveDevices).Methods("GET") iot.HandleFunc("/{sn}/get", a.deviceGetMsg).Methods("PUT") iot.HandleFunc("/{sn}/add", a.deviceCreateMsg).Methods("PUT") iot.HandleFunc("/{sn}/del", a.deviceDeleteMsg).Methods("PUT") diff --git a/backend/services/controller/internal/api/device.go b/backend/services/controller/internal/api/device.go index 5719d48..af4e798 100644 --- a/backend/services/controller/internal/api/device.go +++ b/backend/services/controller/internal/api/device.go @@ -2,8 +2,10 @@ package api import ( "encoding/json" + "go.mongodb.org/mongo-driver/bson" "log" "net/http" + "strconv" "github.com/gorilla/mux" "github.com/leandrofars/oktopus/internal/db" @@ -31,12 +33,90 @@ func (a *Api) deviceGetSupportedParametersMsg(w http.ResponseWriter, r *http.Req } func (a *Api) retrieveDevices(w http.ResponseWriter, r *http.Request) { - devices, err := a.Db.RetrieveDevices() - if err != nil { - log.Println(err) - w.WriteHeader(http.StatusInternalServerError) + const PAGE_SIZE_LIMIT = 50 + const PAGE_SIZE_DEFAULT = 20 + + // Get specific device + id := mux.Vars(r)["id"] + if id != "" { + device, err := a.Db.RetrieveDevice(id) + if err != nil { + log.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + err = json.NewEncoder(w).Encode(device) + if err != nil { + log.Println(err) + } return } + + // Get devices with pagination + page_n := r.URL.Query().Get("page_number") + page_s := r.URL.Query().Get("page_size") + var err error + + var page_number int64 + if page_n == "" { + page_number = 1 + } else { + page_number, err = strconv.ParseInt(page_n, 10, 64) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode("Page number must be an integer") + return + } + } + + var page_size int64 + if page_s != "" { + page_size, err = strconv.ParseInt(page_s, 10, 64) + + if err != nil { + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode("Page size must be an integer") + return + } + + if page_size > PAGE_SIZE_LIMIT { + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode("Page size must not exceed " + strconv.Itoa(PAGE_SIZE_LIMIT)) + return + } + + } else { + page_size = PAGE_SIZE_DEFAULT + } + + total, err := a.Db.RetrieveDevicesCount(bson.M{}) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + json.NewEncoder(w).Encode("Unable to get devices count from database") + } + + skip := page_number * (page_size - 1) + if total < page_size { + skip = 0 + } + + //TODO: Create filters + //TODO: Create sorting + + filter := bson.A{ + //bson.M{"$match": filter}, + //bson.M{"$sort": sort}, + bson.M{"$skip": skip}, + bson.M{"$limit": page_size}, + } + + devices, err := a.Db.RetrieveDevices(filter) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + json.NewEncoder(w).Encode("Unable to aggregate database devices info") + return + } + err = json.NewEncoder(w).Encode(devices) if err != nil { log.Println(err) diff --git a/backend/services/controller/internal/db/device.go b/backend/services/controller/internal/db/device.go index 0e7f9b2..a01dc85 100644 --- a/backend/services/controller/internal/db/device.go +++ b/backend/services/controller/internal/db/device.go @@ -42,20 +42,24 @@ func (d *Database) CreateDevice(device Device) error { log.Printf("Device %s already existed, and got replaced for new info", device.SN) return err } +func (d *Database) RetrieveDevices(filter bson.A) ([]Device, error) { + cursor, err := d.devices.Aggregate(d.ctx, filter) -func (d *Database) RetrieveDevices() ([]Device, error) { var results []Device - //TODO: filter devices by user ownership - cursor, err := d.devices.Find(d.ctx, bson.D{}, nil) - if err != nil { - log.Println(err) - return nil, err + + for cursor.Next(d.ctx) { + var device Device + + err := cursor.Decode(&device) + if err != nil { + log.Println("Error to decode device info fields") + continue + } + + results = append(results, device) } - if err = cursor.All(d.ctx, &results); err != nil { - log.Println(err) - return nil, err - } - return results, nil + + return results, err } func (d *Database) RetrieveDevice(sn string) (Device, error) { @@ -68,6 +72,11 @@ func (d *Database) RetrieveDevice(sn string) (Device, error) { return result, err } +func (d *Database) RetrieveDevicesCount(filter bson.M) (int64, error) { + count, err := d.devices.CountDocuments(d.ctx, filter) + return count, err +} + func (d *Database) DeleteDevice() { }