diff --git a/Taskfile.yml b/Taskfile.yml index 0645cc3..14e41bb 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -1,7 +1,8 @@ version: '3' vars: - API_IMAGE_NAME: realz + REGISTRY: reg.cadoles.com/lacanne + API_IMAGE_NAME: realzapi API_IMAGE_VERSION: v1.0.0 DB_IMAGE_NAME: realzdb DB_IMAGE_VERSION: v1.0.0 @@ -14,15 +15,25 @@ tasks: build-api: desc: Construction de l'image Docker realz API cmds: - - docker build -t {{.API_IMAGE_NAME}}:{{.API_IMAGE_VERSION}} -t {{.API_IMAGE_NAME}}:latest -f docker/Dockerfile.api . + - docker build -t {{.REGISTRY}}/{{.API_IMAGE_NAME}}:{{.API_IMAGE_VERSION}} -t {{.REGISTRY}}/{{.API_IMAGE_NAME}}:latest -f docker/Dockerfile.api . silent: true build-db: desc: Construction de l'image Docker realz DB cmds: - - docker build -t {{.DB_IMAGE_NAME}}:{{.DB_IMAGE_VERSION}} -t {{.DB_IMAGE_NAME}}:latest -f docker/Dockerfile.db . + - docker build -t {{.REGISTRY}}/{{.DB_IMAGE_NAME}}:{{.DB_IMAGE_VERSION}} -t {{.REGISTRY}}/{{.DB_IMAGE_NAME}}:latest -f docker/Dockerfile.db . silent: true build: desc: Construction des images Docker realz deps: [ build-api, build-db ] + + publish: + deps: [ build-api, build-db ] + cmds: + - docker login {{.REGISTRY}} + - docker push {{.REGISTRY}}/{{.API_IMAGE_NAME}}:{{.API_IMAGE_VERSION}} + - docker push {{.REGISTRY}}/{{.API_IMAGE_NAME}}:latest + - docker push {{.REGISTRY}}/{{.DB_IMAGE_NAME}}:{{.DB_IMAGE_VERSION}} + - docker push {{.REGISTRY}}/{{.DB_IMAGE_NAME}}:latest + silent: true diff --git a/cmd/api/realz.go b/cmd/api/realz.go index 6a40121..127b901 100644 --- a/cmd/api/realz.go +++ b/cmd/api/realz.go @@ -1,7 +1,8 @@ -package api +package main import ( "database/sql" + "fmt" "log" "net/http" @@ -99,11 +100,13 @@ func getCorrectedAltitude(db *database.Service) gin.HandlerFunc { } func main() { - cfg, err := config.Load() + cfg, err := config.LoadConfig(".") if err != nil { log.Fatalf("Error loading configuration: %v", err) } + fmt.Printf("Config: %+v\n", cfg) + db, err := database.NewService(&cfg.Database) if err != nil { log.Fatalf("Could not initialize database: %v", err) @@ -113,8 +116,14 @@ func main() { router := gin.Default() - // Servir les fichiers statiques (index.html, etc.) depuis le répertoire courant. - router.StaticFS("/", http.Dir(".")) + // Configure les proxies de confiance pour Gin + if len(cfg.Server.TrustedProxies) > 0 { + router.SetTrustedProxies(cfg.Server.TrustedProxies) + log.Printf("Trusted proxies set to: %v", cfg.Server.TrustedProxies) + } + + // Servir les fichiers statiques de l'UI go-app + router.Static("/web", "./ui/web") // La route est maintenant un POST pour recevoir un corps de requête JSON. router.POST("/getorthocorrec", getOrthometricCorrection(db)) diff --git a/config.yaml b/config.yaml index c6d0da8..27e46a1 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,8 @@ server: address: "0.0.0.0:8088" + trustes_proxies: + - "127.0.0.1" + - "::1" database: user: "realz" diff --git a/docker/Dockerfile.api b/docker/Dockerfile.api index d52e0ad..b4e03fa 100644 --- a/docker/Dockerfile.api +++ b/docker/Dockerfile.api @@ -6,8 +6,9 @@ COPY go.mod go.sum ./ RUN go mod download COPY . . -RUN go build +RUN go build cmd/api/realz.go FROM scratch COPY --from=builder /app/realz /realz +COPY --from=builder /app/index.html /index.html ENTRYPOINT ["/realz"] \ No newline at end of file diff --git a/docker/compose.yaml b/docker/compose.yaml index deb4033..ab292be 100644 --- a/docker/compose.yaml +++ b/docker/compose.yaml @@ -1,17 +1,47 @@ services: - postgis: - image: realz - container_name: postgis_initialized + api: + image: reg.cadoles.com/lacanne/realzapi:latest + env_file: .env + restart: unless-stopped + depends_on: + postgis: + condition: service_healthy + ports: + - "8088:8080" # Expose API port (host:container) environment: - - POSTGRES_USER=${POSTGRES_USER} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - - POSTGRES_DB=${POSTGRES_DB} # Base de données pour l'administration, pas celle de l'app - - PGRST_AUTHUSER=${PGRST_AUTHUSER} - - PGRST_PASSWORD=${PGRST_PASSWORD} + APP_SERVER_ADDRESS: 0.0.0.0:8080 + APP_DATABASE_HOST: postgis + APP_DATABASE_PORT: 5432 + APP_DATABASE_USER: ${POSTGRES_USER} + APP_DATABASE_PASSWORD: ${POSTGRES_PASSWORD} + APP_DATABASE_DBNAME: ${POSTGRES_DB} + APP_DATABASE_SSLMODE: disable + networks: + - realz-net + + postgis: + image: reg.cadoles.com/lacanne/realzdb:latest + container_name: postgis_initialized + restart: unless-stopped + env_file: .env + environment: + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} ports: - "5433:5432" volumes: - postgis_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - realz-net volumes: postgis_data: + +networks: + realz-net: \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index e8560e0..fd6cf79 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -2,66 +2,67 @@ package config import ( "fmt" - "log" - "os" "strings" "github.com/spf13/viper" ) -// Config holds all configuration for the application. +// Config représente la structure globale de la configuration de l'application. type Config struct { - Database DatabaseConfig `mapstructure:"database"` - Server ServerConfig `mapstructure:"server"` + Server ServerConfig + Database DatabaseConfig } -// DatabaseConfig holds database connection configuration. +// ServerConfig contient les paramètres de configuration du serveur HTTP. +type ServerConfig struct { + Address string `mapstructure:"address"` + TrustedProxies []string `mapstructure:"trusted_proxies"` // Liste des IPs de proxies de confiance +} + +// DatabaseConfig contient les paramètres de configuration de la base de données. type DatabaseConfig struct { - User string `mapstructure:"user"` - Password string `mapstructure:"password"` - Dbname string `mapstructure:"dbname"` Host string `mapstructure:"host"` Port int `mapstructure:"port"` - Sslmode string `mapstructure:"sslmode"` + User string `mapstructure:"user"` + Password string `mapstructure:"password"` + DBName string `mapstructure:"dbname"` + SSLMode string `mapstructure:"sslmode"` } -// ServerConfig holds server-specific configuration. -type ServerConfig struct { - Address string `mapstructure:"address"` -} - -// Load reads configuration from file and environment variables. -func Load() (*Config, error) { - // 0. Configuration for environment variables - viper.SetEnvPrefix("APP") // Variables must start with "APP_" (e.g., APP_SERVER_ADDRESS) - - // 1. Base configuration file - viper.SetConfigName("config") // config.yaml +// LoadConfig charge la configuration depuis un fichier et les variables d'environnement. +func LoadConfig(path string) (config Config, err error) { + viper.AddConfigPath(path) + viper.SetConfigName("config") viper.SetConfigType("yaml") - viper.AddConfigPath(".") - // Read the base file. Don't stop if it's not found. - if err := viper.ReadInConfig(); err != nil { + viper.SetDefault("server.address", ":8080") + viper.SetDefault("server.trusted_proxies", "127.0.0.1, ::1") + viper.SetDefault("database.host", "localhost") + viper.SetDefault("database.port", 5432) + viper.SetDefault("database.user", "default_user") + viper.SetDefault("database.password", "") + viper.SetDefault("database.dbname", "default_db") + viper.SetDefault("database.sslmode", "disable") + + // L'ordre ici est important + + // 1. D'abord, on lit le fichier + err = viper.ReadInConfig() + if err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); !ok { - return nil, fmt.Errorf("error reading base config file config.yaml: %w", err) - } - } - - // 2. Override with environment-specific file (via APP_ENV) - if env := os.Getenv("APP_ENV"); env != "" { - viper.SetConfigName("config." + env) // e.g., config.prod.yaml - if err := viper.MergeInConfig(); err != nil { - log.Printf("Warning: could not load config file for environment '%s': %v", env, err) + return } } + // 2. Ensuite, on prépare Viper à lire les variables d'environnement + viper.SetEnvPrefix("APP") viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) - viper.AutomaticEnv() + viper.AutomaticEnv() // Dit à Viper de chercher les variables d'environnement - var cfg Config - if err := viper.Unmarshal(&cfg); err != nil { - return nil, fmt.Errorf("unable to decode config into struct: %w", err) - } + // 3. Enfin, on déverse le résultat final dans la struct. + // C'est à ce moment que la surcharge a lieu. + fmt.Printf("[%v]\n", config.Database.DBName) - return &cfg, nil + err = viper.Unmarshal(&config) + return } diff --git a/internal/database/database.go b/internal/database/database.go index c0bf61b..10ecfd8 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -16,8 +16,8 @@ type Service struct { // NewService initializes and returns a new database service. func NewService(cfg *config.DatabaseConfig) (*Service, error) { connStr := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%d sslmode=%s", - cfg.User, cfg.Password, cfg.Dbname, - cfg.Host, cfg.Port, cfg.Sslmode, + cfg.User, cfg.Password, cfg.DBName, + cfg.Host, cfg.Port, cfg.SSLMode, ) db, err := sql.Open("postgres", connStr)