| @@ -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) { | |||
| @@ -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"), | |||
| } | |||
| } | |||
| @@ -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")) | |||
| } | |||
| } | |||
| @@ -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 | |||
| } | |||
| @@ -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"` | |||
| } | |||
| @@ -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"` | |||
| } | |||
| @@ -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"` | |||
| } | |||