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 (
"fmt"
"gpt-load/internal/config"
"gpt-load/internal/models"
"net/http"
"net/url"
"time"
"gorm.io/datatypes"
)
// GetChannel returns a channel proxy based on the group's channel type.
func GetChannel(group *models.Group) (ChannelProxy, error) {
switch group.ChannelType {
case "openai":
return NewOpenAIChannel(group.Upstreams)
return NewOpenAIChannel(group.Upstreams, group.Config)
case "gemini":
return NewGeminiChannel(group.Upstreams)
return NewGeminiChannel(group.Upstreams, group.Config)
default:
return nil, fmt.Errorf("unsupported channel type: %s", group.ChannelType)
}
}
// 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 {
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)
}
// 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{
Name: name,
Upstreams: upstreamURLs,
HTTPClient: &http.Client{},
HTTPClient: httpClient,
}, nil
}

View File

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

View File

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

View File

@@ -6,7 +6,6 @@ import (
"os"
"strconv"
"strings"
"sync/atomic"
"gpt-load/internal/errors"
"gpt-load/internal/types"
@@ -37,8 +36,7 @@ var DefaultConstants = Constants{
// Manager implements the ConfigManager interface
type Manager struct {
config *Config
roundRobinCounter uint64
config *Config
}
// 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")
}
// Get business logic defaults from the single source of truth
defaultSettings := DefaultSystemSettings()
config := &Config{
Server: types.ServerConfig{
Port: parseInteger(os.Getenv("PORT"), 3000),
Host: getEnvOrDefault("HOST", "0.0.0.0"),
// Server timeout configs now come from system settings, not environment
// Using defaults here, will be overridden by system settings
ReadTimeout: 120,
WriteTimeout: 1800,
IdleTimeout: 120,
GracefulShutdownTimeout: 60,
// Using defaults from SystemSettings struct as the initial value
ReadTimeout: defaultSettings.ServerReadTimeout,
WriteTimeout: defaultSettings.ServerWriteTimeout,
IdleTimeout: defaultSettings.ServerIdleTimeout,
GracefulShutdownTimeout: defaultSettings.ServerGracefulShutdownTimeout,
},
OpenAI: types.OpenAIConfig{
// OPENAI_BASE_URL is removed from environment config
// Base URLs will be configured per group
BaseURLs: []string{}, // Will be set per group
// BaseURLs will be configured per group
BaseURLs: []string{},
// Timeout configs now come from system settings
RequestTimeout: 30,
ResponseTimeout: 30,
IdleConnTimeout: 120,
RequestTimeout: defaultSettings.RequestTimeout,
ResponseTimeout: defaultSettings.ResponseTimeout,
IdleConnTimeout: defaultSettings.IdleConnTimeout,
},
Auth: types.AuthConfig{
Key: os.Getenv("AUTH_KEY"),
@@ -122,24 +122,6 @@ func (m *Manager) ReloadConfig() error {
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
func (m *Manager) GetAuthConfig() types.AuthConfig {
return m.config.Auth
@@ -164,7 +146,7 @@ func (m *Manager) GetLogConfig() types.LogConfig {
func (m *Manager) GetEffectiveServerConfig() types.ServerConfig {
config := m.config.Server
// Merge with system settings
// Merge with system settings from database
settingsManager := GetSystemSettingsManager()
systemSettings := settingsManager.GetSettings()
@@ -176,35 +158,6 @@ func (m *Manager) GetEffectiveServerConfig() types.ServerConfig {
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
func (m *Manager) Validate() error {
var validationErrors []string
@@ -232,7 +185,6 @@ func (m *Manager) Validate() error {
// DisplayConfig displays current configuration information
func (m *Manager) DisplayConfig() {
serverConfig := m.GetEffectiveServerConfig()
// openaiConfig := m.GetOpenAIConfig()
authConfig := m.GetAuthConfig()
corsConfig := m.GetCORSConfig()
perfConfig := m.GetPerformanceConfig()

View File

@@ -10,6 +10,7 @@ import (
"sync"
"github.com/sirupsen/logrus"
"gorm.io/datatypes"
"gorm.io/gorm/clause"
)
@@ -220,7 +221,7 @@ func (sm *SystemSettingsManager) UpdateSettings(settingsMap map[string]string) e
}
// GetEffectiveConfig 获取有效配置 (系统配置 + 分组覆盖)
func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig map[string]any) SystemSettings {
func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig datatypes.JSONMap) SystemSettings {
sm.mu.RLock()
defer sm.mu.RUnlock()
@@ -244,8 +245,19 @@ func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig map[string]any)
if fieldName, ok := jsonToField[key]; ok {
fieldValue := v.FieldByName(fieldName)
if fieldValue.IsValid() && fieldValue.CanSet() {
if intVal, err := interfaceToInt(val); err == nil {
fieldValue.SetInt(int64(intVal))
switch fieldValue.Kind() {
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)
}
}
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
type ConfigManager interface {
// GetServerConfig() ServerConfig
// GetOpenAIConfig() OpenAIConfig
GetAuthConfig() AuthConfig
GetCORSConfig() CORSConfig
GetPerformanceConfig() PerformanceConfig
GetLogConfig() LogConfig
// Effective configuration methods that merge system settings
GetEffectiveServerConfig() ServerConfig
GetEffectiveOpenAIConfig(groupConfig map[string]any) OpenAIConfig
// GetEffectivePerformanceConfig() PerformanceConfig
// GetEffectiveLogConfig() LogConfig
Validate() error
DisplayConfig()
ReloadConfig() error