package config import ( "fmt" "os" "path/filepath" "strconv" ) type Config struct { Host string Port int APIBaseURL string TilePublicBaseURL string VectorPublicBaseURL string SQLitePath string BasemapScanRoot string VectorScanRoot string AutoScanOnStart bool Env string ServiceName string ServiceVersion string Commit string } func Load() (Config, error) { if err := LoadEnvDefaults(); err != nil { return Config{}, err } port, err := intEnv("API_PORT", 8910) if err != nil { return Config{}, fmt.Errorf("parse API_PORT: %w", err) } autoScanOnStart, err := boolEnv("AUTO_SCAN_ON_START", true) if err != nil { return Config{}, fmt.Errorf("parse AUTO_SCAN_ON_START: %w", err) } cfg := Config{ Host: stringEnv("API_HOST", "127.0.0.1"), Port: port, APIBaseURL: stringEnv("API_BASE_URL", ""), TilePublicBaseURL: stringEnv("TILE_PUBLIC_BASE_URL", ""), VectorPublicBaseURL: stringEnv("VECTOR_PUBLIC_BASE_URL", ""), SQLitePath: stringEnv("SQLITE_PATH", filepath.Clean(filepath.Join("data", "map-asset-gateway.db"))), BasemapScanRoot: stringEnv("BASEMAP_SCAN_ROOT", filepath.Clean(filepath.Join("data", "tiles"))), VectorScanRoot: stringEnv("VECTOR_SCAN_ROOT", filepath.Clean(filepath.Join("data", "geojson"))), AutoScanOnStart: autoScanOnStart, Env: stringEnv("APP_ENV", "dev"), ServiceName: stringEnv("SERVICE_NAME", "map-asset-gateway"), ServiceVersion: stringEnv("SERVICE_VERSION", "0.2.0"), Commit: stringEnv("SERVICE_COMMIT", "local"), } if cfg.APIBaseURL == "" { cfg.APIBaseURL = deriveBaseURL(cfg.Host, cfg.Port) } if cfg.TilePublicBaseURL == "" { cfg.TilePublicBaseURL = cfg.APIBaseURL } if cfg.VectorPublicBaseURL == "" { cfg.VectorPublicBaseURL = cfg.APIBaseURL } return cfg, nil } func (c Config) ListenAddr() string { return fmt.Sprintf("%s:%d", c.Host, c.Port) } func deriveBaseURL(host string, port int) string { if host == "" || host == "0.0.0.0" { host = "127.0.0.1" } return fmt.Sprintf("http://%s:%d", host, port) } func stringEnv(key, fallback string) string { value, ok := os.LookupEnv(key) if ok && value != "" { return value } return fallback } func intEnv(key string, fallback int) (int, error) { value, ok := os.LookupEnv(key) if ok && value != "" { parsed, err := strconv.Atoi(value) if err != nil { return 0, err } return parsed, nil } return fallback, nil } func boolEnv(key string, fallback bool) (bool, error) { value, ok := os.LookupEnv(key) if ok && value != "" { parsed, err := strconv.ParseBool(value) if err != nil { return false, err } return parsed, nil } return fallback, nil }