feat(config): 配置加载与 schema 校验(.env/env 注入 + 反射解码 + 校验)
This commit is contained in:
1 parent
0236010136
commit
efed5f05b1
5 files changed
+551
No files matched your search
@@ -0,0 +1,137 @@
|
||||
// Package config loads, defaults, and validates the Cyrene v2 configuration
|
||||
// from environment variables and an optional .env file (development only).
|
||||
//
|
||||
// Every setting is sourced from an environment variable (no hard-coded values
|
||||
// in code). Nested groups map to struct fields tagged with `env:"NAME"`.
|
||||
// Missing required values cause Load/MustLoad to return an error so startup
|
||||
// can fail fast.
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Config is the root configuration tree.
|
||||
type Config struct {
|
||||
Env string `env:"ENV" default:"development"`
|
||||
LogLevel string `env:"LOG_LEVEL" default:"debug"`
|
||||
Timezone string `env:"TZ" default:"Asia/Shanghai"`
|
||||
DataDir string `env:"DATA_DIR" default:"./data"`
|
||||
AllowedOrigins []string `env:"ALLOWED_ORIGINS" default:"http://localhost:5173,http://localhost:3000"`
|
||||
|
||||
Server ServerConfig
|
||||
Auth AuthConfig
|
||||
DB DBConfig
|
||||
LLM LLMConfig
|
||||
Embedding EmbeddingConfig
|
||||
IoT IoTConfig
|
||||
Voice VoiceConfig
|
||||
Background BackgroundConfig
|
||||
WSHub WSHubConfig
|
||||
}
|
||||
|
||||
// ServerConfig holds the single gateway listener settings.
|
||||
type ServerConfig struct {
|
||||
Host string `env:"HOST" default:"0.0.0.0"`
|
||||
Port int `env:"PORT" default:"8080"`
|
||||
}
|
||||
|
||||
// AuthConfig holds authentication and admin credential settings.
|
||||
type AuthConfig struct {
|
||||
JWTSecret string `env:"JWT_SECRET" validate:"required,min=32"`
|
||||
AdminUser string `env:"ADMIN_USERNAME" default:"admin"`
|
||||
AdminPass string `env:"ADMIN_PASSWORD" default:"admin12345"`
|
||||
RegistrationEnabled bool `env:"REGISTRATION_ENABLED" default:"true"`
|
||||
}
|
||||
|
||||
// DBConfig holds database connection settings. SQLite is the default; PGURL is
|
||||
// the optional PostgreSQL+pgvector enhancement.
|
||||
type DBConfig struct {
|
||||
SQLitePath string `env:"DB_SQLITE_PATH" default:"./data/cyrene.db"`
|
||||
PGURL string `env:"DB_PG_URL"`
|
||||
}
|
||||
|
||||
// LLMConfig holds the multi-supplier LLM adapter settings.
|
||||
type LLMConfig struct {
|
||||
BaseURL string `env:"LLM_BASE_URL"`
|
||||
APIKey string `env:"LLM_API_KEY"`
|
||||
Model string `env:"LLM_MODEL"`
|
||||
Fallback string `env:"LLM_FALLBACK_MODEL"`
|
||||
}
|
||||
|
||||
// EmbeddingConfig holds the optional semantic embedding API settings. When
|
||||
// unset, the runtime falls back to built-in n-gram/FTS vectors.
|
||||
type EmbeddingConfig struct {
|
||||
APIURL string `env:"EMBEDDING_API_URL"`
|
||||
APIKey string `env:"EMBEDDING_API_KEY"`
|
||||
Model string `env:"EMBEDDING_MODEL"`
|
||||
}
|
||||
|
||||
// IoTConfig selects the IoT device provider.
|
||||
type IoTConfig struct {
|
||||
Provider string `env:"IOT_PROVIDER" default:"mock"`
|
||||
}
|
||||
|
||||
// VoiceConfig holds TTS/STT provider settings.
|
||||
type VoiceConfig struct {
|
||||
TTSProvider string `env:"TTS_PROVIDER" default:"edge-tts"`
|
||||
STTProvider string `env:"STT_PROVIDER" default:"dashscope"`
|
||||
DashscopeAPIKey string `env:"DASHSCOPE_API_KEY"`
|
||||
}
|
||||
|
||||
// BackgroundConfig holds the autonomous thinking settings.
|
||||
type BackgroundConfig struct {
|
||||
Enabled bool `env:"ENABLE_BACKGROUND_THINKING" default:"true"`
|
||||
IntervalSec int `env:"THINK_INTERVAL_SEC" default:"300"`
|
||||
SilenceTimeout int `env:"THINK_SILENCE_TIMEOUT_SEC" default:"120"`
|
||||
}
|
||||
|
||||
// WSHubConfig holds the WebSocket hub limits.
|
||||
type WSHubConfig struct {
|
||||
MaxConnections int `env:"WS_MAX_CONNECTIONS" default:"1000"`
|
||||
SessionIdleTimeout int `env:"SESSION_IDLE_TIMEOUT_MIN" default:"30"`
|
||||
}
|
||||
|
||||
// Load reads configuration, merging an optional .env file (development only)
|
||||
// with process environment variables. Process environment variables always take
|
||||
// precedence over .env values, which take precedence over code defaults.
|
||||
//
|
||||
// Passing an empty envPath skips .env entirely. A missing .env file is not an
|
||||
// error; only missing required values are.
|
||||
func Load(envPath string) (*Config, error) {
|
||||
fromEnv := map[string]string{}
|
||||
if envPath != "" {
|
||||
m, err := parseDotEnv(envPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("config: read %s: %w", envPath, err)
|
||||
}
|
||||
fromEnv = m
|
||||
}
|
||||
|
||||
cfg := &Config{}
|
||||
if err := decodeValue(reflect.ValueOf(cfg), fromEnv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if errs := validateStruct(reflect.ValueOf(cfg).Elem()); len(errs) > 0 {
|
||||
parts := make([]string, 0, len(errs))
|
||||
for _, e := range errs {
|
||||
parts = append(parts, e.Error())
|
||||
}
|
||||
return nil, fmt.Errorf("config: validation failed: %s", strings.Join(parts, "; "))
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// MustLoad is Load that panics on error. It is intended for startup, matching
|
||||
// the "schema validation fails at boot" rule.
|
||||
func MustLoad(envPath string) *Config {
|
||||
cfg, err := Load(envPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
Reference in new issue
Block a user