package config import ( "fmt" "sync" "time" "github.com/spf13/viper" "gorm.io/driver/mysql" ) // DatabaseConfig 数据库配置 type DatabaseConfig struct { DSN string `mapstructure:"dsn"` MaxIdleConns int `mapstructure:"maxIdleConns"` MaxOpenConns int `mapstructure:"maxOpenConns"` LogLevel string `mapstructure:"logLevel"` } // ServerConfig 服务器配置 type ServerConfig struct { Addr string `mapstructure:"addr"` Port int `mapstructure:"port"` } // GatewayConfig 网关配置 type GatewayConfig struct { BaseURL string `mapstructure:"base_url"` Timeout int `mapstructure:"timeout"` Auth GatewayAuthConfig `mapstructure:"auth"` } // GatewayAuthConfig 网关鉴权配置 type GatewayAuthConfig struct { LoginURL string `mapstructure:"login_url"` Key string `mapstructure:"key"` } // SSOConfig SSO配置 type SSOConfig struct { SSOServerURL string `mapstructure:"sso_server_url"` ClientID string `mapstructure:"client_id"` ClientSecret string `mapstructure:"client_secret"` RedirectURI string `mapstructure:"redirect_uri"` Scope string `mapstructure:"scope"` ResourceAud string `mapstructure:"resource_aud"` AdminToken string `mapstructure:"admin_token"` Timeout time.Duration `mapstructure:"timeout"` } // MessagePushConfig 消息推送配置 type MessagePushConfig struct { GoalfyMaxBaseURL string `mapstructure:"goalfymax_base_url"` Timeout int `mapstructure:"timeout"` RetryCount int `mapstructure:"retry_count"` RetryInterval int `mapstructure:"retry_interval"` } // AlertConfig 告警配置 type AlertConfig struct { DingTalk DingTalkConfig `mapstructure:"dingtalk"` } // DingTalkConfig 钉钉配置 type DingTalkConfig struct { Enabled bool `mapstructure:"enabled"` Webhook string `mapstructure:"webhook"` Secret string `mapstructure:"secret"` TimeoutSeconds int `mapstructure:"timeout_seconds"` Keyword string `mapstructure:"keyword"` } // PayConfig 支付服务配置 type PayConfig struct { BaseURL string `mapstructure:"base_url"` Timeout int `mapstructure:"timeout"` } // OssConfig 对象存储(S3兼容)配置 type OssConfig struct { Endpoint string `mapstructure:"endpoint"` Region string `mapstructure:"region"` AccessKeyID string `mapstructure:"access_key_id"` AccessKeySecret string `mapstructure:"access_key_secret"` Bucket string `mapstructure:"bucket"` UploadMaxSize int64 `mapstructure:"upload_max_size"` // 上传文件最大大小(字节) AssumeRoleArn string `mapstructure:"assume_role_arn"` // AWS S3专用,阿里云不需要 PresignUrlExpire time.Duration `mapstructure:"presign_url_expire"` } // RedisConfig Redis配置 type RedisConfig struct { Addr string `mapstructure:"addr"` Password string `mapstructure:"password"` DB int `mapstructure:"db"` } // EmailConfig 邮件配置 type EmailConfig struct { Sender string `mapstructure:"sender"` Host string `mapstructure:"host"` Port int `mapstructure:"port"` Username string `mapstructure:"username"` Password string `mapstructure:"password"` InviteURLPrefix string `mapstructure:"invite_url_prefix"` } // Config 定义总配置结构 type Config struct { Server ServerConfig `mapstructure:"server"` Database DatabaseConfig `mapstructure:"database"` Gateway GatewayConfig `mapstructure:"gateway"` SSO SSOConfig `mapstructure:"sso"` MessagePush MessagePushConfig `mapstructure:"message_push"` Alert AlertConfig `mapstructure:"alert"` Oss OssConfig `mapstructure:"oss"` Redis RedisConfig `mapstructure:"redis"` Email EmailConfig `mapstructure:"email"` Log LogConfig `mapstructure:"log"` Client ClientConfig `mapstructure:"client"` PostgreSQL PostgreSQLConfig `mapstructure:"postgresql"` Pay PayConfig `mapstructure:"pay"` Jobs JobsConfig `mapstructure:"jobs"` } // LogConfig 日志配置 type LogConfig struct { Level string `mapstructure:"level"` Format string `mapstructure:"format"` Output string `mapstructure:"output"` } // ClientOption 客户端选项 type ClientOption struct { Key string `mapstructure:"key" json:"key"` Value string `mapstructure:"value" json:"value"` Label string `json:"label"` // 用于前端展示,格式:key+value } // ClientConfig 客户端配置 type ClientConfig struct { Options []ClientOption `mapstructure:"options"` } // PostgreSQLConfig PG配置 type PostgreSQLConfig struct { DSN string `mapstructure:"dsn"` Host string `mapstructure:"host"` Port int `mapstructure:"port"` User string `mapstructure:"user"` Password string `mapstructure:"password"` DBName string `mapstructure:"dbname"` SSLMode string `mapstructure:"sslmode"` MaxOpenConns int `mapstructure:"max_open_conns"` MaxIdleConns int `mapstructure:"max_idle_conns"` ConnMaxLifetime time.Duration `mapstructure:"conn_max_lifetime"` ConnMaxIdleTime time.Duration `mapstructure:"conn_max_idle_time"` } type JobsConfig struct { McpUsageBalance McpUsageBalanceJobConfig `mapstructure:"mcp_usage_balance"` ModelTokenBalance ModelTokenBalanceJobConfig `mapstructure:"model_token_balance"` } type McpUsageBalanceJobConfig struct { Enabled bool `mapstructure:"enabled"` RunOnStartup bool `mapstructure:"run_on_startup"` DelayMinutes int `mapstructure:"delay_minutes"` } type ModelTokenBalanceJobConfig struct { Enabled bool `mapstructure:"enabled"` RunOnStartup bool `mapstructure:"run_on_startup"` DelayMinutes int `mapstructure:"delay_minutes"` } func (j JobsConfig) IsMcpUsageEnabled() bool { return j.McpUsageBalance.Enabled } var ( config *Config configLock sync.RWMutex ) // LoadConfig 从文件加载配置 func LoadConfig(path string) error { fmt.Printf("Loading config from %s\n", path) viper.SetConfigFile(path) err := viper.ReadInConfig() if err != nil { return fmt.Errorf("读取配置文件失败: %w", err) } if err := viper.Unmarshal(&config); err != nil { return fmt.Errorf("解析配置文件失败: %w", err) } // 设置默认值 if config.Server.Addr == "" { config.Server.Addr = "0.0.0.0" } if config.Server.Port == 0 { config.Server.Port = 8080 } if config.Database.MaxIdleConns == 0 { config.Database.MaxIdleConns = 10 } if config.Database.MaxOpenConns == 0 { config.Database.MaxOpenConns = 100 } if config.Database.LogLevel == "" { config.Database.LogLevel = "info" } if config.Log.Level == "" { config.Log.Level = "info" } if config.Log.Format == "" { config.Log.Format = "json" } if config.Log.Output == "" { config.Log.Output = "stdout" } if config.Jobs.McpUsageBalance.DelayMinutes <= 0 { config.Jobs.McpUsageBalance.DelayMinutes = 5 } if config.Jobs.ModelTokenBalance.DelayMinutes <= 0 { config.Jobs.ModelTokenBalance.DelayMinutes = 5 } if config.Gateway.BaseURL == "" { config.Gateway.BaseURL = "http://localhost:8080" } if config.Gateway.Timeout == 0 { config.Gateway.Timeout = 30 } if config.Gateway.Auth.LoginURL == "" { config.Gateway.Auth.LoginURL = "http://44.247.156.94:8080/aigateway-admin/api/login" } if config.Gateway.Auth.Key == "" { config.Gateway.Auth.Key = "Jiahe.123" } if config.MessagePush.GoalfyMaxBaseURL == "" { config.MessagePush.GoalfyMaxBaseURL = "http://goalfymax-backend:8080" } if config.MessagePush.Timeout == 0 { config.MessagePush.Timeout = 30 } if config.MessagePush.RetryCount == 0 { config.MessagePush.RetryCount = 3 } if config.MessagePush.RetryInterval == 0 { config.MessagePush.RetryInterval = 1000 } if config.Pay.BaseURL == "" { config.Pay.BaseURL = "http://goalfy-pay:8080" } if config.Pay.Timeout == 0 { config.Pay.Timeout = 30 } if config.Redis.Addr == "" { config.Redis.Addr = "localhost:6379" } if config.Redis.DB == 0 { config.Redis.DB = 0 } // OSS 预签名默认过期时间 if config.Oss.PresignUrlExpire == 0 { config.Oss.PresignUrlExpire = 10 * time.Minute } if config.Alert.DingTalk.TimeoutSeconds <= 0 { config.Alert.DingTalk.TimeoutSeconds = 5 } // 设置客户端默认选项 if len(config.Client.Options) == 0 { config.Client.Options = []ClientOption{ {Key: "5hNXkkkVPfFWUjRvzVP23w", Value: "https://ob-staging-goalfymax.goalfyai.com/"}, {Key: "J10f8yxU1XDl1Tn00MXKeA", Value: "https://staging-goalfymax.goalfyai.com/"}, {Key: "xRpT9mgNpt2YvoY9z4FToA", Value: "https://goalfymax.goalfyai.com/"}, } } // 为每个客户端选项生成 label for i := range config.Client.Options { config.Client.Options[i].Label = config.Client.Options[i].Key + "+" + config.Client.Options[i].Value } return nil } // GetConfig 获取当前配置 func GetConfig() *Config { configLock.RLock() defer configLock.RUnlock() return config } // GetDatabaseConfig 获取数据库配置 func GetDatabaseConfig() mysql.Config { cfg := GetConfig() return mysql.Config{ DSN: cfg.Database.DSN, } } // GetClientOptions 获取客户端选项列表 func GetClientOptions() []ClientOption { cfg := GetConfig() return cfg.Client.Options } // GetClientValue 根据key获取客户端的展示值 func GetClientValue(key string) string { options := GetClientOptions() for _, opt := range options { if opt.Key == key { return opt.Value } } return "" }