package services import ( "fmt" "gpt-load/internal/config" "gpt-load/internal/keypool" "gpt-load/internal/models" "gpt-load/internal/types" "sync" "time" "github.com/sirupsen/logrus" "gorm.io/gorm" ) // ManualValidationResult holds the result of a manual validation task. type ManualValidationResult struct { TotalKeys int `json:"total_keys"` ValidKeys int `json:"valid_keys"` InvalidKeys int `json:"invalid_keys"` } // KeyManualValidationService handles user-initiated key validation for a group. type KeyManualValidationService struct { DB *gorm.DB Validator *keypool.KeyValidator TaskService *TaskService SettingsManager *config.SystemSettingsManager ConfigManager types.ConfigManager } // NewKeyManualValidationService creates a new KeyManualValidationService. func NewKeyManualValidationService(db *gorm.DB, validator *keypool.KeyValidator, taskService *TaskService, settingsManager *config.SystemSettingsManager, configManager types.ConfigManager) *KeyManualValidationService { return &KeyManualValidationService{ DB: db, Validator: validator, TaskService: taskService, SettingsManager: settingsManager, ConfigManager: configManager, } } // StartValidationTask starts a new manual validation task for a given group. func (s *KeyManualValidationService) StartValidationTask(group *models.Group) (*TaskStatus, error) { var keys []models.APIKey if err := s.DB.Where("group_id = ?", group.ID).Find(&keys).Error; err != nil { return nil, fmt.Errorf("failed to get keys for group %s: %w", group.Name, err) } if len(keys) == 0 { return nil, fmt.Errorf("no keys to validate in group %s", group.Name) } timeout := 30 * time.Minute taskStatus, err := s.TaskService.StartTask(TaskTypeKeyValidation, group.Name, len(keys), timeout) if err != nil { return nil, err } // Run the validation in a separate goroutine go s.runValidation(group, keys) return taskStatus, nil } func (s *KeyManualValidationService) runValidation(group *models.Group, keys []models.APIKey) { logrus.Infof("Starting manual validation for group %s", group.Name) jobs := make(chan models.APIKey, len(keys)) results := make(chan bool, len(keys)) concurrency := group.EffectiveConfig.KeyValidationConcurrency var wg sync.WaitGroup for range concurrency { wg.Add(1) go s.validationWorker(&wg, group, jobs, results) } for _, key := range keys { jobs <- key } close(jobs) go func() { wg.Wait() close(results) }() validCount := 0 processedCount := 0 lastUpdateTime := time.Now() for isValid := range results { processedCount++ if isValid { validCount++ } // Throttle progress updates to once per second if time.Since(lastUpdateTime) > time.Second { if err := s.TaskService.UpdateProgress(processedCount); err != nil { logrus.Warnf("Failed to update task progress: %v", err) } lastUpdateTime = time.Now() } } // Ensure the final progress is always updated if err := s.TaskService.UpdateProgress(processedCount); err != nil { logrus.Warnf("Failed to update final task progress: %v", err) } result := ManualValidationResult{ TotalKeys: len(keys), ValidKeys: validCount, InvalidKeys: len(keys) - validCount, } // End the task and store the final result if err := s.TaskService.EndTask(result, nil); err != nil { logrus.Errorf("Failed to end task for group %s: %v", group.Name, err) } logrus.Infof("Manual validation finished for group %s: %+v", group.Name, result) } // validationResult 包含验证结果信息 func (s *KeyManualValidationService) validationWorker(wg *sync.WaitGroup, group *models.Group, jobs <-chan models.APIKey, results chan<- bool) { defer wg.Done() for key := range jobs { isValid, _ := s.Validator.ValidateSingleKey(&key, group) results <- isValid } }