package main import ( "os" "path/filepath" "strconv" ) // Config aggregates every runtime knob the sidecar reads from the // environment. Held in one struct so the rest of the package can take a // pointer instead of poking os.Getenv at use-sites. type Config struct { OriginalsRoot string // absolute path to PhotoPrism's originals dir PhotoprismBaseURL string // e.g. http://localhost:2342 ListenAddr string // bind interface — 127.0.0.1 for host mode, 0.0.0.0 in containers Port int // HTTP listen port DSN string // GORM/MySQL connection string for mule_sidecar } func loadConfig() (*Config, error) { root := envOr("ORIGINALS_ROOT", "/photoprism/originals") abs, err := filepath.Abs(root) if err != nil { return nil, err } portStr := envOr("SIDECAR_PORT", "8000") port, err := strconv.Atoi(portStr) if err != nil { return nil, err } dsn := os.Getenv("SIDECAR_DSN") if dsn == "" { // Default matches the user that mariadb/init/01-sidecar.sql provisions // on first boot. The literal placeholder password is intentional: the // SQL ships with it and an env-templating step is left for whoever // runs this in a non-local context. user := envOr("SIDECAR_DB_USER", "sidecar") pass := envOr("SIDECAR_DB_PASSWORD", "replace-at-m4-bringup") host := envOr("SIDECAR_DB_HOST", "127.0.0.1") dbPort := envOr("SIDECAR_DB_PORT", "3306") name := envOr("SIDECAR_DB_NAME", "mule_sidecar") dsn = user + ":" + pass + "@tcp(" + host + ":" + dbPort + ")/" + name + "?charset=utf8mb4&parseTime=true&loc=Local" } return &Config{ OriginalsRoot: abs, PhotoprismBaseURL: envOr("PHOTOPRISM_BASE_URL", "http://localhost:2342"), ListenAddr: envOr("SIDECAR_LISTEN_ADDR", "127.0.0.1"), Port: port, DSN: dsn, }, nil } func envOr(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback }