Add DATABASE_URL parsing for Dokku compatibility
- Parse DATABASE_URL environment variable (postgres://...) - Dokku sets this via postgres:link command - Falls back to individual env vars if DATABASE_URL not set 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,9 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -96,6 +98,34 @@ func Load() (*Config, error) {
|
|||||||
// Set defaults
|
// Set defaults
|
||||||
setDefaults()
|
setDefaults()
|
||||||
|
|
||||||
|
// Parse DATABASE_URL if set (Dokku-style)
|
||||||
|
dbConfig := DatabaseConfig{
|
||||||
|
Host: viper.GetString("DB_HOST"),
|
||||||
|
Port: viper.GetInt("DB_PORT"),
|
||||||
|
User: viper.GetString("POSTGRES_USER"),
|
||||||
|
Password: viper.GetString("POSTGRES_PASSWORD"),
|
||||||
|
Database: viper.GetString("POSTGRES_DB"),
|
||||||
|
SSLMode: viper.GetString("DB_SSLMODE"),
|
||||||
|
MaxOpenConns: viper.GetInt("DB_MAX_OPEN_CONNS"),
|
||||||
|
MaxIdleConns: viper.GetInt("DB_MAX_IDLE_CONNS"),
|
||||||
|
MaxLifetime: viper.GetDuration("DB_MAX_LIFETIME"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override with DATABASE_URL if present
|
||||||
|
if databaseURL := viper.GetString("DATABASE_URL"); databaseURL != "" {
|
||||||
|
parsed, err := parseDatabaseURL(databaseURL)
|
||||||
|
if err == nil {
|
||||||
|
dbConfig.Host = parsed.Host
|
||||||
|
dbConfig.Port = parsed.Port
|
||||||
|
dbConfig.User = parsed.User
|
||||||
|
dbConfig.Password = parsed.Password
|
||||||
|
dbConfig.Database = parsed.Database
|
||||||
|
if parsed.SSLMode != "" {
|
||||||
|
dbConfig.SSLMode = parsed.SSLMode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cfg = &Config{
|
cfg = &Config{
|
||||||
Server: ServerConfig{
|
Server: ServerConfig{
|
||||||
Port: viper.GetInt("PORT"),
|
Port: viper.GetInt("PORT"),
|
||||||
@@ -103,17 +133,7 @@ func Load() (*Config, error) {
|
|||||||
AllowedHosts: strings.Split(viper.GetString("ALLOWED_HOSTS"), ","),
|
AllowedHosts: strings.Split(viper.GetString("ALLOWED_HOSTS"), ","),
|
||||||
Timezone: viper.GetString("TIMEZONE"),
|
Timezone: viper.GetString("TIMEZONE"),
|
||||||
},
|
},
|
||||||
Database: DatabaseConfig{
|
Database: dbConfig,
|
||||||
Host: viper.GetString("DB_HOST"),
|
|
||||||
Port: viper.GetInt("DB_PORT"),
|
|
||||||
User: viper.GetString("POSTGRES_USER"),
|
|
||||||
Password: viper.GetString("POSTGRES_PASSWORD"),
|
|
||||||
Database: viper.GetString("POSTGRES_DB"),
|
|
||||||
SSLMode: viper.GetString("DB_SSLMODE"),
|
|
||||||
MaxOpenConns: viper.GetInt("DB_MAX_OPEN_CONNS"),
|
|
||||||
MaxIdleConns: viper.GetInt("DB_MAX_IDLE_CONNS"),
|
|
||||||
MaxLifetime: viper.GetDuration("DB_MAX_LIFETIME"),
|
|
||||||
},
|
|
||||||
Redis: RedisConfig{
|
Redis: RedisConfig{
|
||||||
URL: viper.GetString("REDIS_URL"),
|
URL: viper.GetString("REDIS_URL"),
|
||||||
Password: viper.GetString("REDIS_PASSWORD"),
|
Password: viper.GetString("REDIS_PASSWORD"),
|
||||||
@@ -239,3 +259,39 @@ func (p *PushConfig) ReadAPNSKey() (string, error) {
|
|||||||
|
|
||||||
return string(content), nil
|
return string(content), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseDatabaseURL parses a PostgreSQL URL into DatabaseConfig
|
||||||
|
// Format: postgres://user:password@host:port/database?sslmode=disable
|
||||||
|
func parseDatabaseURL(databaseURL string) (*DatabaseConfig, error) {
|
||||||
|
u, err := url.Parse(databaseURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse DATABASE_URL: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default port
|
||||||
|
port := 5432
|
||||||
|
if u.Port() != "" {
|
||||||
|
port, err = strconv.Atoi(u.Port())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid port in DATABASE_URL: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get password
|
||||||
|
password, _ := u.User.Password()
|
||||||
|
|
||||||
|
// Get database name (remove leading slash)
|
||||||
|
database := strings.TrimPrefix(u.Path, "/")
|
||||||
|
|
||||||
|
// Get sslmode from query params
|
||||||
|
sslMode := u.Query().Get("sslmode")
|
||||||
|
|
||||||
|
return &DatabaseConfig{
|
||||||
|
Host: u.Hostname(),
|
||||||
|
Port: port,
|
||||||
|
User: u.User.Username(),
|
||||||
|
Password: password,
|
||||||
|
Database: database,
|
||||||
|
SSLMode: sslMode,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user