From 22bf9f70a8b31c23ac20d7dceb91cfbab5c8ae88 Mon Sep 17 00:00:00 2001 From: blazSmehov Date: Thu, 18 Dec 2025 22:41:01 +0100 Subject: [PATCH] feat: add postgresql connection, add models for gateways, zones and tracker zones, add ORM --- cmd/server/main.go | 12 ++- internal/pkg/config/config.go | 8 ++ .../pkg/controller/gateways_controller.go | 77 +++++++++++++++++++ internal/pkg/database/database.go | 35 +++++++++ internal/pkg/model/gateway.go | 16 ++++ internal/pkg/model/tracker_zones.go | 9 +++ internal/pkg/model/zones.go | 9 +++ 7 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 internal/pkg/controller/gateways_controller.go create mode 100644 internal/pkg/database/database.go create mode 100644 internal/pkg/model/gateway.go create mode 100644 internal/pkg/model/tracker_zones.go create mode 100644 internal/pkg/model/zones.go diff --git a/cmd/server/main.go b/cmd/server/main.go index 624fb6e..3f8beb5 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -18,6 +18,7 @@ import ( "github.com/AFASystems/presence/internal/pkg/common/appcontext" "github.com/AFASystems/presence/internal/pkg/config" "github.com/AFASystems/presence/internal/pkg/controller" + "github.com/AFASystems/presence/internal/pkg/database" "github.com/AFASystems/presence/internal/pkg/kafkaclient" "github.com/AFASystems/presence/internal/pkg/model" "github.com/AFASystems/presence/internal/pkg/service" @@ -32,7 +33,6 @@ var upgrader = websocket.Upgrader{ } var _ io.Writer = (*os.File)(nil) - var wg sync.WaitGroup func main() { @@ -53,6 +53,11 @@ func main() { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT) defer stop() + db, err := database.Connect(cfg) + if err != nil { + log.Fatalf("Failed to open database connection: %v\n", err) + } + headersOk := handlers.AllowedHeaders([]string{"X-Requested-With"}) originsOk := handlers.AllowedOrigins([]string{"*"}) methodsOk := handlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"}) @@ -87,6 +92,11 @@ func main() { r.HandleFunc("/api/settings", controller.SettingsListController(appState, ctx)).Methods("GET") r.HandleFunc("/api/settings", controller.SettingsEditController(settingsWriter, appState, ctx)).Methods("POST") + r.HandleFunc("/reslevis/getGateways", controller.GatewayListController(db)).Methods("GET") + r.HandleFunc("/reslevis/postGateway", controller.GatewayAddController(db)).Methods("POST") + r.HandleFunc("/reslevis/removeGateway/{gateway_id}", controller.GatewayDeleteController(db)).Methods("DELETE") + r.HandleFunc("/reslevis/updateGateway/{gateway_id}", controller.GatewayUpdateController(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) { diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index d5bfb0b..fdb8714 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -10,6 +10,10 @@ type Config struct { MQTTPass string MQTTClientID string KafkaURL string + DBHost string + DBUser string + DBPass string + DBName string } // getEnv returns env var value or a default if not set. @@ -29,5 +33,9 @@ func Load() *Config { MQTTPass: getEnv("MQTT_PASSWORD", "pass"), MQTTClientID: getEnv("MQTT_CLIENT_ID", "presence-detector"), KafkaURL: getEnv("KAFKA_URL", "127.0.0.1:9092"), + DBHost: getEnv("DBHost", "127.0.0.1"), + DBUser: getEnv("DBUser", "postgres"), + DBPass: getEnv("DBPass", "postgres"), + DBName: getEnv("DBName", "go_crud_db"), } } diff --git a/internal/pkg/controller/gateways_controller.go b/internal/pkg/controller/gateways_controller.go new file mode 100644 index 0000000..7d24b84 --- /dev/null +++ b/internal/pkg/controller/gateways_controller.go @@ -0,0 +1,77 @@ +package controller + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/AFASystems/presence/internal/pkg/model" + "github.com/gorilla/mux" + "gorm.io/gorm" +) + +func GatewayAddController(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + decoder := json.NewDecoder(r.Body) + var gateway model.Gateway + + if err := decoder.Decode(&gateway); err != nil { + http.Error(w, err.Error(), 400) + return + } + + db.Create(&gateway) + w.Write([]byte("ok")) + } +} + +func GatewayListController(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var gateways []model.Gateway + db.Find(&gateways) + fmt.Printf("gateways: %+v", gateways) + res, err := json.Marshal(gateways) + if err != nil { + http.Error(w, err.Error(), 400) + return + } + + w.Write(res) + } +} + +func GatewayDeleteController(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id := vars["gateway_id"] + if res := db.Delete(&model.Gateway{}, "id = ?", id); res.RowsAffected == 0 { + http.Error(w, "no gateway with such ID found", 400) + return + } + + w.Write([]byte("ok")) + } +} + +func GatewayUpdateController(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + id := vars["gateway_id"] + + if err := db.First(&model.Gateway{}, id).Error; err != nil { + http.Error(w, err.Error(), 400) + return + } + + decoder := json.NewDecoder(r.Body) + var gateway model.Gateway + + if err := decoder.Decode(&gateway); err != nil { + http.Error(w, err.Error(), 400) + return + } + + db.Save(&gateway) + w.Write([]byte("ok")) + } +} diff --git a/internal/pkg/database/database.go b/internal/pkg/database/database.go new file mode 100644 index 0000000..49ec4bd --- /dev/null +++ b/internal/pkg/database/database.go @@ -0,0 +1,35 @@ +package database + +import ( + "fmt" + + "github.com/AFASystems/presence/internal/pkg/config" + "github.com/AFASystems/presence/internal/pkg/model" + "gorm.io/driver/postgres" + "gorm.io/gorm" +) + +var DB *gorm.DB + +func Connect(cfg *config.Config) (*gorm.DB, error) { + // Connect to PostgreSQL database + dsn := fmt.Sprintf( + "host=%s user=%s password=%s dbname=%s port=5432 sslmode=disable", + cfg.DBHost, + cfg.DBUser, + cfg.DBPass, + cfg.DBName, + ) + + db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + return nil, err + } + + if err := db.AutoMigrate(&model.Gateway{}); err != nil { + return nil, err + } + + fmt.Println("Database connection established") + return db, nil +} diff --git a/internal/pkg/model/gateway.go b/internal/pkg/model/gateway.go new file mode 100644 index 0000000..3c6f2f1 --- /dev/null +++ b/internal/pkg/model/gateway.go @@ -0,0 +1,16 @@ +package model + +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"` +} diff --git a/internal/pkg/model/tracker_zones.go b/internal/pkg/model/tracker_zones.go new file mode 100644 index 0000000..7197cf8 --- /dev/null +++ b/internal/pkg/model/tracker_zones.go @@ -0,0 +1,9 @@ +package model + +type TrackerZones struct { + ID string `json:"id"` + ZoneList []string `json:"zoneList"` + Tracker string `json:"tracker"` + Days string `json:"days"` + Time string `json:"time"` +} diff --git a/internal/pkg/model/zones.go b/internal/pkg/model/zones.go new file mode 100644 index 0000000..42cfc00 --- /dev/null +++ b/internal/pkg/model/zones.go @@ -0,0 +1,9 @@ +package model + +type Zone struct { + ID string `json:"id" gorm:"primaryKey"` + Name string `json:"name"` + Groups []string `json:"groups"` + Floor string `json:"floor"` + Building string `json:"building"` +}