98 lines
2.8 KiB
Go
98 lines
2.8 KiB
Go
|
|
// Package config loads smartrund's runtime configuration from environment
|
||
|
|
// variables (a single-user local app has no need for a config file/flags
|
||
|
|
// beyond this).
|
||
|
|
package config
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"os"
|
||
|
|
"strconv"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Config holds everything smartrund needs to start.
|
||
|
|
type Config struct {
|
||
|
|
// Addr is the HTTP listen address, e.g. ":8080".
|
||
|
|
Addr string
|
||
|
|
// DBPath is the SQLite database file path.
|
||
|
|
DBPath string
|
||
|
|
|
||
|
|
// GarminPythonPath is mcp-garmin's venv python executable.
|
||
|
|
GarminPythonPath string
|
||
|
|
// GarminServerPath is mcp-garmin's server.py.
|
||
|
|
GarminServerPath string
|
||
|
|
GarminEmail string
|
||
|
|
GarminPassword string
|
||
|
|
// GarminTokenStore, if set, overrides mcp-garmin's default ~/.garth
|
||
|
|
// session cache location.
|
||
|
|
GarminTokenStore string
|
||
|
|
|
||
|
|
MaxHR float64
|
||
|
|
MinConfidence float64
|
||
|
|
BackfillHorizonDays int
|
||
|
|
IncrementalSyncEvery time.Duration
|
||
|
|
}
|
||
|
|
|
||
|
|
// Load reads configuration from environment variables, applying defaults
|
||
|
|
// for anything optional. Returns an error if a required variable is unset.
|
||
|
|
func Load() (Config, error) {
|
||
|
|
cfg := Config{
|
||
|
|
Addr: getEnvDefault("SMARTRUN_ADDR", ":8080"),
|
||
|
|
DBPath: getEnvDefault("SMARTRUN_DB_PATH", "smartrun.db"),
|
||
|
|
GarminPythonPath: os.Getenv("MCP_GARMIN_PYTHON"),
|
||
|
|
GarminServerPath: os.Getenv("MCP_GARMIN_SERVER"),
|
||
|
|
GarminEmail: os.Getenv("GARMIN_EMAIL"),
|
||
|
|
GarminPassword: os.Getenv("GARMIN_PASSWORD"),
|
||
|
|
GarminTokenStore: os.Getenv("GARMIN_TOKENSTORE"),
|
||
|
|
MaxHR: getEnvFloat("SMARTRUN_MAX_HR", 190),
|
||
|
|
MinConfidence: getEnvFloat("SMARTRUN_MIN_CONFIDENCE", 0.6),
|
||
|
|
BackfillHorizonDays: getEnvInt("SMARTRUN_BACKFILL_HORIZON_DAYS", 3*365),
|
||
|
|
IncrementalSyncEvery: getEnvDuration("SMARTRUN_INCREMENTAL_SYNC_EVERY", 6*time.Hour),
|
||
|
|
}
|
||
|
|
|
||
|
|
if cfg.GarminPythonPath == "" {
|
||
|
|
return cfg, fmt.Errorf("MCP_GARMIN_PYTHON is required (path to mcp-garmin's venv python)")
|
||
|
|
}
|
||
|
|
if cfg.GarminServerPath == "" {
|
||
|
|
return cfg, fmt.Errorf("MCP_GARMIN_SERVER is required (path to mcp-garmin's server.py)")
|
||
|
|
}
|
||
|
|
if cfg.GarminEmail == "" || cfg.GarminPassword == "" {
|
||
|
|
return cfg, fmt.Errorf("GARMIN_EMAIL and GARMIN_PASSWORD are required")
|
||
|
|
}
|
||
|
|
return cfg, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func getEnvDefault(key, def string) string {
|
||
|
|
if v := os.Getenv(key); v != "" {
|
||
|
|
return v
|
||
|
|
}
|
||
|
|
return def
|
||
|
|
}
|
||
|
|
|
||
|
|
func getEnvFloat(key string, def float64) float64 {
|
||
|
|
if v := os.Getenv(key); v != "" {
|
||
|
|
if f, err := strconv.ParseFloat(v, 64); err == nil {
|
||
|
|
return f
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return def
|
||
|
|
}
|
||
|
|
|
||
|
|
func getEnvInt(key string, def int) int {
|
||
|
|
if v := os.Getenv(key); v != "" {
|
||
|
|
if n, err := strconv.Atoi(v); err == nil {
|
||
|
|
return n
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return def
|
||
|
|
}
|
||
|
|
|
||
|
|
func getEnvDuration(key string, def time.Duration) time.Duration {
|
||
|
|
if v := os.Getenv(key); v != "" {
|
||
|
|
if d, err := time.ParseDuration(v); err == nil {
|
||
|
|
return d
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return def
|
||
|
|
}
|