- Add http module for proper FX dependency injection - Fix router to accept state manager parameter - Implement proper CIDR-based checking for RFC1918 and documentation IPs - Add reasonable timeouts (30s) for database downloads - Update tests to download databases to temporary directories - Add tests for multiple IP lookups and error cases - All tests passing
104 lines
2.0 KiB
Go
104 lines
2.0 KiB
Go
// Package config handles application configuration.
|
|
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strconv"
|
|
|
|
"git.eeqj.de/sneak/smartconfig"
|
|
)
|
|
|
|
// Config holds the application configuration.
|
|
type Config struct {
|
|
Port int
|
|
StateDir string
|
|
LogLevel string
|
|
}
|
|
|
|
// New creates a new configuration instance.
|
|
func New(configFile string) (*Config, error) {
|
|
// Check if config file exists first
|
|
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
|
return newDefaultConfig(), nil
|
|
}
|
|
|
|
// Load smartconfig
|
|
sc, err := smartconfig.NewFromConfigPath(configFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
cfg := &Config{}
|
|
|
|
// Get port from smartconfig or environment or default
|
|
if port, err := sc.GetInt("port"); err == nil {
|
|
cfg.Port = port
|
|
} else {
|
|
cfg.Port = getPortFromEnv()
|
|
}
|
|
|
|
// Get state directory
|
|
if stateDir, err := sc.GetString("state_dir"); err == nil {
|
|
cfg.StateDir = stateDir
|
|
} else {
|
|
cfg.StateDir = getDefaultStateDir()
|
|
}
|
|
|
|
// Get log level
|
|
if logLevel, err := sc.GetString("log_level"); err == nil {
|
|
cfg.LogLevel = logLevel
|
|
} else {
|
|
cfg.LogLevel = "info"
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
func newDefaultConfig() *Config {
|
|
return &Config{
|
|
Port: getPortFromEnv(),
|
|
StateDir: getDefaultStateDir(),
|
|
LogLevel: "info",
|
|
}
|
|
}
|
|
|
|
func getPortFromEnv() int {
|
|
const defaultPort = 8080
|
|
portStr := os.Getenv("PORT")
|
|
if portStr == "" {
|
|
return defaultPort
|
|
}
|
|
port, err := strconv.Atoi(portStr)
|
|
if err != nil {
|
|
return defaultPort
|
|
}
|
|
|
|
return port
|
|
}
|
|
|
|
func getDefaultStateDir() string {
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
// macOS: use ~/Library/Application Support/berlin.sneak.app.ipapi/
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return "/var/lib/ipapi"
|
|
}
|
|
|
|
return filepath.Join(home, "Library", "Application Support", "berlin.sneak.app.ipapi")
|
|
case "windows":
|
|
// Windows: use %APPDATA%\berlin.sneak.app.ipapi
|
|
appData := os.Getenv("APPDATA")
|
|
if appData == "" {
|
|
return "/var/lib/ipapi"
|
|
}
|
|
|
|
return filepath.Join(appData, "berlin.sneak.app.ipapi")
|
|
default:
|
|
// Linux and other Unix-like systems
|
|
return "/var/lib/ipapi"
|
|
}
|
|
}
|