feat: 优化分组缓存配置功能

This commit is contained in:
tbphp
2025-07-10 23:20:52 +08:00
parent a23c4c2735
commit ca431ce3a3
6 changed files with 131 additions and 100 deletions

View File

@@ -118,7 +118,7 @@ func (a *App) Start() error {
} }
logrus.Info("System settings initialized in DB.") logrus.Info("System settings initialized in DB.")
a.settingsManager.Initialize(a.storage) a.settingsManager.Initialize(a.storage, a.groupManager)
// 从数据库加载密钥到 Redis // 从数据库加载密钥到 Redis
if err := a.keyPoolProvider.LoadKeysFromDB(); err != nil { if err := a.keyPoolProvider.LoadKeysFromDB(); err != nil {
@@ -131,7 +131,7 @@ func (a *App) Start() error {
if err := a.leaderService.WaitForInitializationToComplete(); err != nil { if err := a.leaderService.WaitForInitializationToComplete(); err != nil {
return fmt.Errorf("follower failed to start: %w", err) return fmt.Errorf("follower failed to start: %w", err)
} }
a.settingsManager.Initialize(a.storage) a.settingsManager.Initialize(a.storage, a.groupManager)
} }
a.groupManager.Initialize() a.groupManager.Initialize()

View File

@@ -1,11 +1,13 @@
package config package config
import ( import (
"encoding/json"
"fmt" "fmt"
"gpt-load/internal/db" "gpt-load/internal/db"
"gpt-load/internal/models" "gpt-load/internal/models"
"gpt-load/internal/store" "gpt-load/internal/store"
"gpt-load/internal/syncer" "gpt-load/internal/syncer"
"gpt-load/internal/types"
"os" "os"
"reflect" "reflect"
"strconv" "strconv"
@@ -16,38 +18,15 @@ import (
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
) )
// SystemSettings 定义所有系统配置项 const SettingsUpdateChannel = "system_settings:updated"
// 使用结构体标签作为唯一事实来源
type SystemSettings struct {
// 基础参数
AppUrl string `json:"app_url" default:"" name:"项目地址" category:"基础参数" desc:"项目的基础 URL用于拼接分组终端节点地址。系统配置优先于环境变量 APP_URL。"`
RequestLogRetentionDays int `json:"request_log_retention_days" default:"30" name:"日志保留天数" category:"基础参数" desc:"请求日志在数据库中的保留天数" validate:"min=1"`
// 服务超时
ServerReadTimeout int `json:"server_read_timeout" default:"120" name:"读取超时" category:"服务超时" desc:"HTTP 服务器读取超时时间(秒)" validate:"min=1"`
ServerWriteTimeout int `json:"server_write_timeout" default:"1800" name:"写入超时" category:"服务超时" desc:"HTTP 服务器写入超时时间(秒)" validate:"min=1"`
ServerIdleTimeout int `json:"server_idle_timeout" default:"120" name:"空闲超时" category:"服务超时" desc:"HTTP 服务器空闲超时时间(秒)" validate:"min=1"`
ServerGracefulShutdownTimeout int `json:"server_graceful_shutdown_timeout" default:"60" name:"优雅关闭超时" category:"服务超时" desc:"服务优雅关闭的等待超时时间(秒)" validate:"min=1"`
// 请求超时
RequestTimeout int `json:"request_timeout" default:"30" name:"请求超时" category:"请求超时" desc:"请求处理的总体超时时间(秒)" validate:"min=1"`
ResponseTimeout int `json:"response_timeout" default:"30" name:"响应超时" category:"请求超时" desc:"TLS 握手和响应头的超时时间(秒)" validate:"min=1"`
IdleConnTimeout int `json:"idle_conn_timeout" default:"120" name:"空闲连接超时" category:"请求超时" desc:"空闲连接的超时时间(秒)" validate:"min=1"`
// 密钥配置
MaxRetries int `json:"max_retries" default:"3" name:"最大重试次数" category:"密钥配置" desc:"单个请求使用不同 Key 的最大重试次数" validate:"min=0"`
BlacklistThreshold int `json:"blacklist_threshold" default:"1" name:"黑名单阈值" category:"密钥配置" desc:"一个 Key 连续失败多少次后进入黑名单" validate:"min=0"`
KeyValidationIntervalMinutes int `json:"key_validation_interval_minutes" default:"60" name:"定时验证周期" category:"密钥配置" desc:"后台定时验证密钥的默认周期(分钟)" validate:"min=5"`
KeyValidationTaskTimeoutMinutes int `json:"key_validation_task_timeout_minutes" default:"60" name:"手动验证超时" category:"密钥配置" desc:"手动触发的全量验证任务的超时时间(分钟)" validate:"min=10"`
}
// GenerateSettingsMetadata 使用反射从 SystemSettings 结构体动态生成元数据 // GenerateSettingsMetadata 使用反射从 SystemSettings 结构体动态生成元数据
func GenerateSettingsMetadata(s *SystemSettings) []models.SystemSettingInfo { func GenerateSettingsMetadata(s *types.SystemSettings) []models.SystemSettingInfo {
var settingsInfo []models.SystemSettingInfo var settingsInfo []models.SystemSettingInfo
v := reflect.ValueOf(s).Elem() v := reflect.ValueOf(s).Elem()
t := v.Type() t := v.Type()
for i := 0; i < t.NumField(); i++ { for i := range t.NumField() {
field := t.Field(i) field := t.Field(i)
fieldValue := v.Field(i) fieldValue := v.Field(i)
@@ -86,12 +65,12 @@ func GenerateSettingsMetadata(s *SystemSettings) []models.SystemSettingInfo {
} }
// DefaultSystemSettings 返回默认的系统配置 // DefaultSystemSettings 返回默认的系统配置
func DefaultSystemSettings() SystemSettings { func DefaultSystemSettings() types.SystemSettings {
s := SystemSettings{} s := types.SystemSettings{}
v := reflect.ValueOf(&s).Elem() v := reflect.ValueOf(&s).Elem()
t := v.Type() t := v.Type()
for i := 0; i < t.NumField(); i++ { for i := range t.NumField() {
field := t.Field(i) field := t.Field(i)
defaultTag := field.Tag.Get("default") defaultTag := field.Tag.Get("default")
if defaultTag == "" { if defaultTag == "" {
@@ -110,22 +89,24 @@ func DefaultSystemSettings() SystemSettings {
// SystemSettingsManager 管理系统配置 // SystemSettingsManager 管理系统配置
type SystemSettingsManager struct { type SystemSettingsManager struct {
syncer *syncer.CacheSyncer[SystemSettings] syncer *syncer.CacheSyncer[types.SystemSettings]
} }
const SettingsUpdateChannel = "system_settings:updated"
// NewSystemSettingsManager creates a new, uninitialized SystemSettingsManager. // NewSystemSettingsManager creates a new, uninitialized SystemSettingsManager.
func NewSystemSettingsManager() (*SystemSettingsManager, error) { func NewSystemSettingsManager() *SystemSettingsManager {
return &SystemSettingsManager{}, nil return &SystemSettingsManager{}
}
type gm interface {
Invalidate() error
} }
// Initialize initializes the SystemSettingsManager with database and store dependencies. // Initialize initializes the SystemSettingsManager with database and store dependencies.
func (sm *SystemSettingsManager) Initialize(store store.Store) error { func (sm *SystemSettingsManager) Initialize(store store.Store, gm gm) error {
settingsLoader := func() (SystemSettings, error) { settingsLoader := func() (types.SystemSettings, error) {
var dbSettings []models.SystemSetting var dbSettings []models.SystemSetting
if err := db.DB.Find(&dbSettings).Error; err != nil { if err := db.DB.Find(&dbSettings).Error; err != nil {
return SystemSettings{}, fmt.Errorf("failed to load system settings from db: %w", err) return types.SystemSettings{}, fmt.Errorf("failed to load system settings from db: %w", err)
} }
settingsMap := make(map[string]string) settingsMap := make(map[string]string)
@@ -138,7 +119,7 @@ func (sm *SystemSettingsManager) Initialize(store store.Store) error {
v := reflect.ValueOf(&settings).Elem() v := reflect.ValueOf(&settings).Elem()
t := v.Type() t := v.Type()
jsonToField := make(map[string]string) jsonToField := make(map[string]string)
for i := 0; i < t.NumField(); i++ { for i := range t.NumField() {
field := t.Field(i) field := t.Field(i)
jsonTag := strings.Split(field.Tag.Get("json"), ",")[0] jsonTag := strings.Split(field.Tag.Get("json"), ",")[0]
if jsonTag != "" { if jsonTag != "" {
@@ -162,11 +143,18 @@ func (sm *SystemSettingsManager) Initialize(store store.Store) error {
return settings, nil return settings, nil
} }
afterLoader := func(newData types.SystemSettings) {
if err := gm.Invalidate(); err != nil {
logrus.Debugf("Failed to invalidate group manager cache after settings update: %v", err)
}
}
syncer, err := syncer.NewCacheSyncer( syncer, err := syncer.NewCacheSyncer(
settingsLoader, settingsLoader,
store, store,
SettingsUpdateChannel, SettingsUpdateChannel,
logrus.WithField("syncer", "system_settings"), logrus.WithField("syncer", "system_settings"),
afterLoader,
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to create system settings syncer: %w", err) return fmt.Errorf("failed to create system settings syncer: %w", err)
@@ -227,7 +215,7 @@ func (sm *SystemSettingsManager) EnsureSettingsInitialized() error {
// GetSettings 获取当前系统配置 // GetSettings 获取当前系统配置
// If the syncer is not initialized, it returns default settings. // If the syncer is not initialized, it returns default settings.
func (sm *SystemSettingsManager) GetSettings() SystemSettings { func (sm *SystemSettingsManager) GetSettings() types.SystemSettings {
if sm.syncer == nil { if sm.syncer == nil {
logrus.Warn("SystemSettingsManager is not initialized, returning default settings.") logrus.Warn("SystemSettingsManager is not initialized, returning default settings.")
return DefaultSystemSettings() return DefaultSystemSettings()
@@ -278,7 +266,7 @@ func (sm *SystemSettingsManager) UpdateSettings(settingsMap map[string]any) erro
} }
// GetEffectiveConfig 获取有效配置 (系统配置 + 分组覆盖) // GetEffectiveConfig 获取有效配置 (系统配置 + 分组覆盖)
func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig datatypes.JSONMap) SystemSettings { func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig datatypes.JSONMap) types.SystemSettings {
// 从系统配置开始 // 从系统配置开始
effectiveConfig := sm.GetSettings() effectiveConfig := sm.GetSettings()
v := reflect.ValueOf(&effectiveConfig).Elem() v := reflect.ValueOf(&effectiveConfig).Elem()
@@ -286,7 +274,7 @@ func (sm *SystemSettingsManager) GetEffectiveConfig(groupConfig datatypes.JSONMa
// 创建一个从 json 标签到字段名的映射 // 创建一个从 json 标签到字段名的映射
jsonToField := make(map[string]string) jsonToField := make(map[string]string)
for i := 0; i < t.NumField(); i++ { for i := range t.NumField() {
field := t.Field(i) field := t.Field(i)
jsonTag := strings.Split(field.Tag.Get("json"), ",")[0] jsonTag := strings.Split(field.Tag.Get("json"), ",")[0]
if jsonTag != "" { if jsonTag != "" {
@@ -378,7 +366,7 @@ func (sm *SystemSettingsManager) ValidateSettings(settingsMap map[string]any) er
} }
// DisplayCurrentSettings 显示当前系统配置信息 // DisplayCurrentSettings 显示当前系统配置信息
func (sm *SystemSettingsManager) DisplayCurrentSettings(settings SystemSettings) { func (sm *SystemSettingsManager) DisplayCurrentSettings(settings types.SystemSettings) {
logrus.Info("Current System Settings:") logrus.Info("Current System Settings:")
logrus.Infof(" App URL: %s", settings.AppUrl) logrus.Infof(" App URL: %s", settings.AppUrl)
logrus.Infof(" Blacklist threshold: %d", settings.BlacklistThreshold) logrus.Infof(" Blacklist threshold: %d", settings.BlacklistThreshold)
@@ -386,8 +374,10 @@ func (sm *SystemSettingsManager) DisplayCurrentSettings(settings SystemSettings)
logrus.Infof(" Server timeouts: read=%ds, write=%ds, idle=%ds, shutdown=%ds", logrus.Infof(" Server timeouts: read=%ds, write=%ds, idle=%ds, shutdown=%ds",
settings.ServerReadTimeout, settings.ServerWriteTimeout, settings.ServerReadTimeout, settings.ServerWriteTimeout,
settings.ServerIdleTimeout, settings.ServerGracefulShutdownTimeout) settings.ServerIdleTimeout, settings.ServerGracefulShutdownTimeout)
logrus.Infof(" Request timeouts: request=%ds, response=%ds, idle_conn=%ds", logrus.Infof(" Request timeouts: request=%ds, connect=%ds, idle_conn=%ds",
settings.RequestTimeout, settings.ResponseTimeout, settings.IdleConnTimeout) settings.RequestTimeout, settings.ConnectTimeout, settings.IdleConnTimeout)
logrus.Infof(" HTTP Client Pool: max_idle_conns=%d, max_idle_conns_per_host=%d",
settings.MaxIdleConns, settings.MaxIdleConnsPerHost)
logrus.Infof(" Request log retention: %d days", settings.RequestLogRetentionDays) logrus.Infof(" Request log retention: %d days", settings.RequestLogRetentionDays)
logrus.Infof(" Key validation: interval=%dmin, task_timeout=%dmin", logrus.Infof(" Key validation: interval=%dmin, task_timeout=%dmin",
settings.KeyValidationIntervalMinutes, settings.KeyValidationTaskTimeoutMinutes) settings.KeyValidationIntervalMinutes, settings.KeyValidationTaskTimeoutMinutes)
@@ -424,10 +414,15 @@ func setFieldFromString(fieldValue reflect.Value, value string) error {
func interfaceToInt(val any) (int, error) { func interfaceToInt(val any) (int, error) {
switch v := val.(type) { switch v := val.(type) {
case json.Number:
i64, err := v.Int64()
if err != nil {
return 0, err
}
return int(i64), nil
case int: case int:
return v, nil return v, nil
case float64: case float64:
// JSON unmarshals numbers into float64
if v != float64(int(v)) { if v != float64(int(v)) {
return 0, fmt.Errorf("value is a float, not an integer: %v", v) return 0, fmt.Errorf("value is a float, not an integer: %v", v)
} }
@@ -448,6 +443,12 @@ func interfaceToString(val any) (string, bool) {
// interfaceToBool is kept for GetEffectiveConfig // interfaceToBool is kept for GetEffectiveConfig
func interfaceToBool(val any) (bool, bool) { func interfaceToBool(val any) (bool, bool) {
switch v := val.(type) { switch v := val.(type) {
case json.Number:
if s := v.String(); s == "1" {
return true, true
} else if s == "0" {
return false, true
}
case bool: case bool:
return v, true return v, true
case string: case string:

View File

@@ -1,6 +1,7 @@
package models package models
import ( import (
"gpt-load/internal/types"
"time" "time"
"gorm.io/datatypes" "gorm.io/datatypes"
@@ -38,21 +39,22 @@ type GroupConfig struct {
// Group 对应 groups 表 // Group 对应 groups 表
type Group struct { type Group struct {
ID uint `gorm:"primaryKey;autoIncrement" json:"id"` ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
Name string `gorm:"type:varchar(255);not null;unique" json:"name"` EffectiveConfig types.SystemSettings `gorm:"-" json:"effective_config,omitempty"`
Endpoint string `gorm:"-" json:"endpoint"` Name string `gorm:"type:varchar(255);not null;unique" json:"name"`
DisplayName string `gorm:"type:varchar(255)" json:"display_name"` Endpoint string `gorm:"-" json:"endpoint"`
Description string `gorm:"type:varchar(512)" json:"description"` DisplayName string `gorm:"type:varchar(255)" json:"display_name"`
Upstreams datatypes.JSON `gorm:"type:json;not null" json:"upstreams"` Description string `gorm:"type:varchar(512)" json:"description"`
ChannelType string `gorm:"type:varchar(50);not null" json:"channel_type"` Upstreams datatypes.JSON `gorm:"type:json;not null" json:"upstreams"`
Sort int `gorm:"default:0" json:"sort"` ChannelType string `gorm:"type:varchar(50);not null" json:"channel_type"`
TestModel string `gorm:"type:varchar(255);not null" json:"test_model"` Sort int `gorm:"default:0" json:"sort"`
ParamOverrides datatypes.JSONMap `gorm:"type:json" json:"param_overrides"` TestModel string `gorm:"type:varchar(255);not null" json:"test_model"`
Config datatypes.JSONMap `gorm:"type:json" json:"config"` ParamOverrides datatypes.JSONMap `gorm:"type:json" json:"param_overrides"`
APIKeys []APIKey `gorm:"foreignKey:GroupID" json:"api_keys"` Config datatypes.JSONMap `gorm:"type:json" json:"config"`
LastValidatedAt *time.Time `json:"last_validated_at"` APIKeys []APIKey `gorm:"foreignKey:GroupID" json:"api_keys"`
CreatedAt time.Time `json:"created_at"` LastValidatedAt *time.Time `json:"last_validated_at"`
UpdatedAt time.Time `json:"updated_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} }
// APIKey 对应 api_keys 表 // APIKey 对应 api_keys 表

View File

@@ -2,6 +2,7 @@ package services
import ( import (
"fmt" "fmt"
"gpt-load/internal/config"
"gpt-load/internal/models" "gpt-load/internal/models"
"gpt-load/internal/store" "gpt-load/internal/store"
"gpt-load/internal/syncer" "gpt-load/internal/syncer"
@@ -14,16 +15,22 @@ const GroupUpdateChannel = "groups:updated"
// GroupManager manages the caching of group data. // GroupManager manages the caching of group data.
type GroupManager struct { type GroupManager struct {
syncer *syncer.CacheSyncer[map[string]*models.Group] syncer *syncer.CacheSyncer[map[string]*models.Group]
db *gorm.DB db *gorm.DB
store store.Store store store.Store
settingsManager *config.SystemSettingsManager
} }
// NewGroupManager creates a new, uninitialized GroupManager. // NewGroupManager creates a new, uninitialized GroupManager.
func NewGroupManager(db *gorm.DB, store store.Store) *GroupManager { func NewGroupManager(
db *gorm.DB,
store store.Store,
settingsManager *config.SystemSettingsManager,
) *GroupManager {
return &GroupManager{ return &GroupManager{
db: db, db: db,
store: store, store: store,
settingsManager: settingsManager,
} }
} }
@@ -38,7 +45,13 @@ func (gm *GroupManager) Initialize() error {
groupMap := make(map[string]*models.Group, len(groups)) groupMap := make(map[string]*models.Group, len(groups))
for _, group := range groups { for _, group := range groups {
g := *group g := *group
g.EffectiveConfig = gm.settingsManager.GetEffectiveConfig(g.Config)
groupMap[g.Name] = &g groupMap[g.Name] = &g
logrus.WithFields(logrus.Fields{
"group_name": g.Name,
"group_config": g.Config,
"effective_config": g.EffectiveConfig,
}).Debug("Loaded group with effective config")
} }
return groupMap, nil return groupMap, nil
} }
@@ -48,6 +61,7 @@ func (gm *GroupManager) Initialize() error {
gm.store, gm.store,
GroupUpdateChannel, GroupUpdateChannel,
logrus.WithField("syncer", "groups"), logrus.WithField("syncer", "groups"),
nil,
) )
if err != nil { if err != nil {
return fmt.Errorf("failed to create group syncer: %w", err) return fmt.Errorf("failed to create group syncer: %w", err)

View File

@@ -23,6 +23,7 @@ type CacheSyncer[T any] struct {
logger *logrus.Entry logger *logrus.Entry
stopChan chan struct{} stopChan chan struct{}
wg sync.WaitGroup wg sync.WaitGroup
afterReload func(newValue T)
} }
// NewCacheSyncer creates and initializes a new CacheSyncer. // NewCacheSyncer creates and initializes a new CacheSyncer.
@@ -31,6 +32,7 @@ func NewCacheSyncer[T any](
store store.Store, store store.Store,
channelName string, channelName string,
logger *logrus.Entry, logger *logrus.Entry,
afterReload func(newValue T),
) (*CacheSyncer[T], error) { ) (*CacheSyncer[T], error) {
s := &CacheSyncer[T]{ s := &CacheSyncer[T]{
loader: loader, loader: loader,
@@ -38,6 +40,7 @@ func NewCacheSyncer[T any](
channelName: channelName, channelName: channelName,
logger: logger, logger: logger,
stopChan: make(chan struct{}), stopChan: make(chan struct{}),
afterReload: afterReload,
} }
if err := s.reload(); err != nil { if err := s.reload(); err != nil {
@@ -85,6 +88,11 @@ func (s *CacheSyncer[T]) reload() error {
s.mu.Unlock() s.mu.Unlock()
s.logger.Info("cache reloaded successfully") s.logger.Info("cache reloaded successfully")
// After successfully reloading and updating the cache, trigger the hook.
if s.afterReload != nil {
s.logger.Debug("triggering afterReload hook")
s.afterReload(newData)
}
return nil return nil
} }

View File

@@ -1,10 +1,5 @@
// Package types defines common interfaces and types used across the application
package types package types
import (
"github.com/gin-gonic/gin"
)
// ConfigManager defines the interface for configuration management // ConfigManager defines the interface for configuration management
type ConfigManager interface { type ConfigManager interface {
GetAuthConfig() AuthConfig GetAuthConfig() AuthConfig
@@ -19,29 +14,40 @@ type ConfigManager interface {
ReloadConfig() error ReloadConfig() error
} }
// ProxyServer defines the interface for proxy server // SystemSettings 定义所有系统配置项
type ProxyServer interface { type SystemSettings struct {
HandleProxy(c *gin.Context) // 基础参数
Close() AppUrl string `json:"app_url" default:"" name:"项目地址" category:"基础参数" desc:"项目的基础 URL用于拼接分组终端节点地址。系统配置优先于环境变量 APP_URL。"`
RequestLogRetentionDays int `json:"request_log_retention_days" default:"30" name:"日志保留天数" category:"基础参数" desc:"请求日志在数据库中的保留天数" validate:"min=1"`
// 服务超时
ServerReadTimeout int `json:"server_read_timeout" default:"120" name:"读取超时" category:"服务超时" desc:"HTTP 服务器读取超时时间(秒)" validate:"min=1"`
ServerWriteTimeout int `json:"server_write_timeout" default:"1800" name:"写入超时" category:"服务超时" desc:"HTTP 服务器写入超时时间(秒)" validate:"min=1"`
ServerIdleTimeout int `json:"server_idle_timeout" default:"120" name:"空闲超时" category:"服务超时" desc:"HTTP 服务器空闲超时时间(秒)" validate:"min=1"`
ServerGracefulShutdownTimeout int `json:"server_graceful_shutdown_timeout" default:"60" name:"优雅关闭超时" category:"服务超时" desc:"服务优雅关闭的等待超时时间(秒)" validate:"min=1"`
// 请求超时
RequestTimeout int `json:"request_timeout" default:"600" name:"请求超时" category:"请求超时" desc:"转发请求的完整生命周期超时(秒),包括连接、重试等。" validate:"min=1"`
ConnectTimeout int `json:"connect_timeout" default:"5" name:"连接超时" category:"请求超时" desc:"与上游服务建立新连接的超时时间(秒)。" validate:"min=1"`
IdleConnTimeout int `json:"idle_conn_timeout" default:"120" name:"空闲连接超时" category:"请求超时" desc:"HTTP 客户端中空闲连接的超时时间(秒)。" validate:"min=1"`
MaxIdleConns int `json:"max_idle_conns" default:"100" name:"最大空闲连接数" category:"请求超时" desc:"HTTP 客户端连接池中允许的最大空闲连接总数。" validate:"min=1"`
MaxIdleConnsPerHost int `json:"max_idle_conns_per_host" default:"10" name:"每主机最大空闲连接数" category:"请求超时" desc:"HTTP 客户端连接池对每个上游主机允许的最大空闲连接数。" validate:"min=1"`
// 密钥配置
MaxRetries int `json:"max_retries" default:"3" name:"最大重试次数" category:"密钥配置" desc:"单个请求使用不同 Key 的最大重试次数" validate:"min=0"`
BlacklistThreshold int `json:"blacklist_threshold" default:"1" name:"黑名单阈值" category:"密钥配置" desc:"一个 Key 连续失败多少次后进入黑名单" validate:"min=0"`
KeyValidationIntervalMinutes int `json:"key_validation_interval_minutes" default:"60" name:"定时验证周期" category:"密钥配置" desc:"后台定时验证密钥的默认周期(分钟)" validate:"min=5"`
KeyValidationTaskTimeoutMinutes int `json:"key_validation_task_timeout_minutes" default:"60" name:"手动验证超时" category:"密钥配置" desc:"手动触发的全量验证任务的超时时间(分钟)" validate:"min=10"`
} }
// ServerConfig represents server configuration // ServerConfig represents server configuration
type ServerConfig struct { type ServerConfig struct {
Port int `json:"port"` Port int `json:"port"`
Host string `json:"host"` Host string `json:"host"`
ReadTimeout int `json:"readTimeout"` ReadTimeout int `json:"read_timeout"`
WriteTimeout int `json:"writeTimeout"` WriteTimeout int `json:"write_timeout"`
IdleTimeout int `json:"idleTimeout"` IdleTimeout int `json:"idle_timeout"`
GracefulShutdownTimeout int `json:"gracefulShutdownTimeout"` GracefulShutdownTimeout int `json:"graceful_shutdown_timeout"`
}
// OpenAIConfig represents OpenAI API configuration
type OpenAIConfig struct {
BaseURL string `json:"baseUrl"`
BaseURLs []string `json:"baseUrls"`
RequestTimeout int `json:"requestTimeout"`
ResponseTimeout int `json:"responseTimeout"`
IdleConnTimeout int `json:"idleConnTimeout"`
} }
// AuthConfig represents authentication configuration // AuthConfig represents authentication configuration
@@ -53,26 +59,26 @@ type AuthConfig struct {
// CORSConfig represents CORS configuration // CORSConfig represents CORS configuration
type CORSConfig struct { type CORSConfig struct {
Enabled bool `json:"enabled"` Enabled bool `json:"enabled"`
AllowedOrigins []string `json:"allowedOrigins"` AllowedOrigins []string `json:"allowed_origins"`
AllowedMethods []string `json:"allowedMethods"` AllowedMethods []string `json:"allowed_methods"`
AllowedHeaders []string `json:"allowedHeaders"` AllowedHeaders []string `json:"allowed_headers"`
AllowCredentials bool `json:"allowCredentials"` AllowCredentials bool `json:"allow_credentials"`
} }
// PerformanceConfig represents performance configuration // PerformanceConfig represents performance configuration
type PerformanceConfig struct { type PerformanceConfig struct {
MaxConcurrentRequests int `json:"maxConcurrentRequests"` MaxConcurrentRequests int `json:"max_concurrent_requests"`
KeyValidationPoolSize int `json:"KeyValidationPoolSize"` KeyValidationPoolSize int `json:"key_validation_pool_size"`
EnableGzip bool `json:"enableGzip"` EnableGzip bool `json:"enable_gzip"`
} }
// LogConfig represents logging configuration // LogConfig represents logging configuration
type LogConfig struct { type LogConfig struct {
Level string `json:"level"` Level string `json:"level"`
Format string `json:"format"` Format string `json:"format"`
EnableFile bool `json:"enableFile"` EnableFile bool `json:"enable_file"`
FilePath string `json:"filePath"` FilePath string `json:"file_path"`
EnableRequest bool `json:"enableRequest"` EnableRequest bool `json:"enable_request"`
} }
// DatabaseConfig represents database configuration // DatabaseConfig represents database configuration