feat: 配置优化

This commit is contained in:
tbphp
2025-07-03 17:53:56 +08:00
parent 80662af9de
commit 0bd6a9289c
6 changed files with 77 additions and 82 deletions

View File

@@ -2,25 +2,29 @@ package channel
import ( import (
"fmt" "fmt"
"gpt-load/internal/config"
"gpt-load/internal/models" "gpt-load/internal/models"
"net/http" "net/http"
"net/url" "net/url"
"time"
"gorm.io/datatypes"
) )
// GetChannel returns a channel proxy based on the group's channel type. // GetChannel returns a channel proxy based on the group's channel type.
func GetChannel(group *models.Group) (ChannelProxy, error) { func GetChannel(group *models.Group) (ChannelProxy, error) {
switch group.ChannelType { switch group.ChannelType {
case "openai": case "openai":
return NewOpenAIChannel(group.Upstreams) return NewOpenAIChannel(group.Upstreams, group.Config)
case "gemini": case "gemini":
return NewGeminiChannel(group.Upstreams) return NewGeminiChannel(group.Upstreams, group.Config)
default: default:
return nil, fmt.Errorf("unsupported channel type: %s", group.ChannelType) return nil, fmt.Errorf("unsupported channel type: %s", group.ChannelType)
} }
} }
// newBaseChannelWithUpstreams is a helper function to create and configure a BaseChannel. // newBaseChannelWithUpstreams is a helper function to create and configure a BaseChannel.
func newBaseChannelWithUpstreams(name string, upstreams []string) (BaseChannel, error) { func newBaseChannelWithUpstreams(name string, upstreams []string, groupConfig datatypes.JSONMap) (BaseChannel, error) {
if len(upstreams) == 0 { if len(upstreams) == 0 {
return BaseChannel{}, fmt.Errorf("at least one upstream is required for %s channel", name) return BaseChannel{}, fmt.Errorf("at least one upstream is required for %s channel", name)
} }
@@ -34,9 +38,21 @@ func newBaseChannelWithUpstreams(name string, upstreams []string) (BaseChannel,
upstreamURLs = append(upstreamURLs, u) upstreamURLs = append(upstreamURLs, u)
} }
// Get effective settings by merging system and group configs
settingsManager := config.GetSystemSettingsManager()
effectiveSettings := settingsManager.GetEffectiveConfig(groupConfig)
// Configure the HTTP client with the effective timeouts
httpClient := &http.Client{
Transport: &http.Transport{
IdleConnTimeout: time.Duration(effectiveSettings.IdleConnTimeout) * time.Second,
},
Timeout: time.Duration(effectiveSettings.RequestTimeout) * time.Second,
}
return BaseChannel{ return BaseChannel{
Name: name, Name: name,
Upstreams: upstreamURLs, Upstreams: upstreamURLs,
HTTPClient: &http.Client{}, HTTPClient: httpClient,
}, nil }, nil
} }

View File

@@ -5,14 +5,15 @@ import (
"net/http" "net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/datatypes"
) )
type GeminiChannel struct { type GeminiChannel struct {
BaseChannel BaseChannel
} }
func NewGeminiChannel(upstreams []string) (*GeminiChannel, error) { func NewGeminiChannel(upstreams []string, config datatypes.JSONMap) (*GeminiChannel, error) {
base, err := newBaseChannelWithUpstreams("gemini", upstreams) base, err := newBaseChannelWithUpstreams("gemini", upstreams, config)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -5,14 +5,15 @@ import (
"net/http" "net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/datatypes"
) )
type OpenAIChannel struct { type OpenAIChannel struct {
BaseChannel BaseChannel
} }
func NewOpenAIChannel(upstreams []string) (*OpenAIChannel, error) { func NewOpenAIChannel(upstreams []string, config datatypes.JSONMap) (*OpenAIChannel, error) {
base, err := newBaseChannelWithUpstreams("openai", upstreams) base, err := newBaseChannelWithUpstreams("openai", upstreams, config)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -6,7 +6,6 @@ import (
"os" "os"
"strconv" "strconv"
"strings" "strings"
"sync/atomic"
"gpt-load/internal/errors" "gpt-load/internal/errors"
"gpt-load/internal/types" "gpt-load/internal/types"
@@ -37,8 +36,7 @@ var DefaultConstants = Constants{
// Manager implements the ConfigManager interface // Manager implements the ConfigManager interface
type Manager struct { type Manager struct {
config *Config config *Config
roundRobinCounter uint64
} }
// Config represents the application configuration // Config represents the application configuration
@@ -67,25 +65,27 @@ func (m *Manager) ReloadConfig() error {
logrus.Info("Info: Create .env file to support environment variable configuration") logrus.Info("Info: Create .env file to support environment variable configuration")
} }
// Get business logic defaults from the single source of truth
defaultSettings := DefaultSystemSettings()
config := &Config{ config := &Config{
Server: types.ServerConfig{ Server: types.ServerConfig{
Port: parseInteger(os.Getenv("PORT"), 3000), Port: parseInteger(os.Getenv("PORT"), 3000),
Host: getEnvOrDefault("HOST", "0.0.0.0"), Host: getEnvOrDefault("HOST", "0.0.0.0"),
// Server timeout configs now come from system settings, not environment // Server timeout configs now come from system settings, not environment
// Using defaults here, will be overridden by system settings // Using defaults from SystemSettings struct as the initial value
ReadTimeout: 120, ReadTimeout: defaultSettings.ServerReadTimeout,
WriteTimeout: 1800, WriteTimeout: defaultSettings.ServerWriteTimeout,
IdleTimeout: 120, IdleTimeout: defaultSettings.ServerIdleTimeout,
GracefulShutdownTimeout: 60, GracefulShutdownTimeout: defaultSettings.ServerGracefulShutdownTimeout,
}, },
OpenAI: types.OpenAIConfig{ OpenAI: types.OpenAIConfig{
// OPENAI_BASE_URL is removed from environment config // BaseURLs will be configured per group
// Base URLs will be configured per group BaseURLs: []string{},
BaseURLs: []string{}, // Will be set per group
// Timeout configs now come from system settings // Timeout configs now come from system settings
RequestTimeout: 30, RequestTimeout: defaultSettings.RequestTimeout,
ResponseTimeout: 30, ResponseTimeout: defaultSettings.ResponseTimeout,
IdleConnTimeout: 120, IdleConnTimeout: defaultSettings.IdleConnTimeout,
}, },
Auth: types.AuthConfig{ Auth: types.AuthConfig{
Key: os.Getenv("AUTH_KEY"), Key: os.Getenv("AUTH_KEY"),
@@ -122,24 +122,6 @@ func (m *Manager) ReloadConfig() error {
return nil return nil
} }
// GetServerConfig returns server configuration
// func (m *Manager) GetServerConfig() types.ServerConfig {
// return m.config.Server
// }
// GetOpenAIConfig returns OpenAI configuration
// func (m *Manager) GetOpenAIConfig() types.OpenAIConfig {
// config := m.config.OpenAI
// if len(config.BaseURLs) > 1 {
// // Use atomic counter for thread-safe round-robin
// index := atomic.AddUint64(&m.roundRobinCounter, 1) - 1
// config.BaseURL = config.BaseURLs[index%uint64(len(config.BaseURLs))]
// } else if len(config.BaseURLs) == 1 {
// config.BaseURL = config.BaseURLs[0]
// }
// return config
// }
// GetAuthConfig returns authentication configuration // GetAuthConfig returns authentication configuration
func (m *Manager) GetAuthConfig() types.AuthConfig { func (m *Manager) GetAuthConfig() types.AuthConfig {
return m.config.Auth return m.config.Auth
@@ -164,7 +146,7 @@ func (m *Manager) GetLogConfig() types.LogConfig {
func (m *Manager) GetEffectiveServerConfig() types.ServerConfig { func (m *Manager) GetEffectiveServerConfig() types.ServerConfig {
config := m.config.Server config := m.config.Server
// Merge with system settings // Merge with system settings from database
settingsManager := GetSystemSettingsManager() settingsManager := GetSystemSettingsManager()
systemSettings := settingsManager.GetSettings() systemSettings := settingsManager.GetSettings()
@@ -176,35 +158,6 @@ func (m *Manager) GetEffectiveServerConfig() types.ServerConfig {
return config return config
} }
// GetEffectiveOpenAIConfig returns OpenAI configuration merged with system settings and group config
func (m *Manager) GetEffectiveOpenAIConfig(groupConfig map[string]any) types.OpenAIConfig {
config := m.config.OpenAI
// Merge with system settings
settingsManager := GetSystemSettingsManager()
effectiveSettings := settingsManager.GetEffectiveConfig(groupConfig)
config.RequestTimeout = effectiveSettings.RequestTimeout
config.ResponseTimeout = effectiveSettings.ResponseTimeout
config.IdleConnTimeout = effectiveSettings.IdleConnTimeout
// Apply round-robin for multiple URLs if configured
if len(config.BaseURLs) > 1 {
index := atomic.AddUint64(&m.roundRobinCounter, 1) - 1
config.BaseURL = config.BaseURLs[index%uint64(len(config.BaseURLs))]
} else if len(config.BaseURLs) == 1 {
config.BaseURL = config.BaseURLs[0]
}
return config
}
// GetEffectiveLogConfig returns log configuration (now uses environment config only)
// func (m *Manager) GetEffectiveLogConfig() types.LogConfig {
// // Log configuration is now managed via environment variables only
// return m.config.Log
// }
// Validate validates the configuration // Validate validates the configuration
func (m *Manager) Validate() error { func (m *Manager) Validate() error {
var validationErrors []string var validationErrors []string
@@ -232,7 +185,6 @@ func (m *Manager) Validate() error {
// DisplayConfig displays current configuration information // DisplayConfig displays current configuration information
func (m *Manager) DisplayConfig() { func (m *Manager) DisplayConfig() {
serverConfig := m.GetEffectiveServerConfig() serverConfig := m.GetEffectiveServerConfig()
// openaiConfig := m.GetOpenAIConfig()
authConfig := m.GetAuthConfig() authConfig := m.GetAuthConfig()
corsConfig := m.GetCORSConfig() corsConfig := m.GetCORSConfig()
perfConfig := m.GetPerformanceConfig() perfConfig := m.GetPerformanceConfig()

View File

@@ -10,6 +10,7 @@ import (
"sync" "sync"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"gorm.io/datatypes"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
) )
@@ -220,7 +221,7 @@ func (sm *SystemSettingsManager) UpdateSettings(settingsMap map[string]string) e
} }
// GetEffectiveConfig 获取有效配置 (系统配置 + 分组覆盖) // GetEffectiveConfig 获取有效配置 (系统配置 + 分组覆盖)
func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig map[string]any) SystemSettings { func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig datatypes.JSONMap) SystemSettings {
sm.mu.RLock() sm.mu.RLock()
defer sm.mu.RUnlock() defer sm.mu.RUnlock()
@@ -244,8 +245,19 @@ func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig map[string]any)
if fieldName, ok := jsonToField[key]; ok { if fieldName, ok := jsonToField[key]; ok {
fieldValue := v.FieldByName(fieldName) fieldValue := v.FieldByName(fieldName)
if fieldValue.IsValid() && fieldValue.CanSet() { if fieldValue.IsValid() && fieldValue.CanSet() {
if intVal, err := interfaceToInt(val); err == nil { switch fieldValue.Kind() {
fieldValue.SetInt(int64(intVal)) case reflect.Int:
if intVal, err := interfaceToInt(val); err == nil {
fieldValue.SetInt(int64(intVal))
}
case reflect.String:
if strVal, ok := interfaceToString(val); ok {
fieldValue.SetString(strVal)
}
case reflect.Bool:
if boolVal, ok := interfaceToBool(val); ok {
fieldValue.SetBool(boolVal)
}
} }
} }
} }
@@ -360,3 +372,24 @@ func interfaceToInt(val interface{}) (int, error) {
return 0, fmt.Errorf("cannot convert to int: %v", val) return 0, fmt.Errorf("cannot convert to int: %v", val)
} }
} }
func interfaceToString(val interface{}) (string, bool) {
s, ok := val.(string)
return s, ok
}
func interfaceToBool(val interface{}) (bool, bool) {
switch v := val.(type) {
case bool:
return v, true
case string:
lowerV := strings.ToLower(v)
if lowerV == "true" || lowerV == "1" || lowerV == "on" {
return true, true
}
if lowerV == "false" || lowerV == "0" || lowerV == "off" {
return false, true
}
}
return false, false
}

View File

@@ -7,19 +7,11 @@ import (
// ConfigManager defines the interface for configuration management // ConfigManager defines the interface for configuration management
type ConfigManager interface { type ConfigManager interface {
// GetServerConfig() ServerConfig
// GetOpenAIConfig() OpenAIConfig
GetAuthConfig() AuthConfig GetAuthConfig() AuthConfig
GetCORSConfig() CORSConfig GetCORSConfig() CORSConfig
GetPerformanceConfig() PerformanceConfig GetPerformanceConfig() PerformanceConfig
GetLogConfig() LogConfig GetLogConfig() LogConfig
// Effective configuration methods that merge system settings
GetEffectiveServerConfig() ServerConfig GetEffectiveServerConfig() ServerConfig
GetEffectiveOpenAIConfig(groupConfig map[string]any) OpenAIConfig
// GetEffectivePerformanceConfig() PerformanceConfig
// GetEffectiveLogConfig() LogConfig
Validate() error Validate() error
DisplayConfig() DisplayConfig()
ReloadConfig() error ReloadConfig() error