feat: Add validation and account management functionality (#21)
* feat: Add validation and account management functionality - Add validation for clientID and clientSecret in refreshOIDCToken function - Add weight field for load balancing priority in Account struct - Implement weighted轮询策略以根据账号权重分配选择概率。 - Add batch account management functionality including enabling, disabling, refreshing, and retrieving account details. - Update Kiro API version and adjust user agent strings to reflect new version numbers. - Update Kiro version and modify user agent strings and header settings. - Refactor model mapping to an ordered list for precise key matching. - Add account bulk actions and filtering toolbar to index.html * feat: Add logic to skip accounts with exhausted usage limits - Add logic to skip accounts with exhausted usage limits when selecting the next account.
This commit is contained in:
@@ -36,13 +36,25 @@ func GetPool() *AccountPool {
|
||||
}
|
||||
|
||||
// Reload 从配置重新加载账号
|
||||
// 构建加权列表:weight<=1 出现 1 次,weight>=2 出现 weight 次
|
||||
func (p *AccountPool) Reload() {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
p.accounts = config.GetEnabledAccounts()
|
||||
enabled := config.GetEnabledAccounts()
|
||||
var weighted []config.Account
|
||||
for _, a := range enabled {
|
||||
w := a.Weight
|
||||
if w < 1 {
|
||||
w = 1
|
||||
}
|
||||
for j := 0; j < w; j++ {
|
||||
weighted = append(weighted, a)
|
||||
}
|
||||
}
|
||||
p.accounts = weighted
|
||||
}
|
||||
|
||||
// GetNext 获取下一个可用账号(轮询)
|
||||
// GetNext 获取下一个可用账号(加权轮询)
|
||||
func (p *AccountPool) GetNext() *config.Account {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
@@ -53,30 +65,47 @@ func (p *AccountPool) GetNext() *config.Account {
|
||||
|
||||
now := time.Now()
|
||||
n := len(p.accounts)
|
||||
seen := make(map[string]bool)
|
||||
|
||||
// 轮询查找可用账号
|
||||
// 加权轮询查找可用账号
|
||||
for i := 0; i < n; i++ {
|
||||
idx := atomic.AddUint64(&p.currentIndex, 1) % uint64(n)
|
||||
acc := &p.accounts[idx]
|
||||
|
||||
if seen[acc.ID] {
|
||||
continue
|
||||
}
|
||||
|
||||
// 跳过冷却中的账号
|
||||
if cooldown, ok := p.cooldowns[acc.ID]; ok && now.Before(cooldown) {
|
||||
seen[acc.ID] = true
|
||||
continue
|
||||
}
|
||||
|
||||
// 跳过即将过期的 Token
|
||||
if acc.ExpiresAt > 0 && time.Now().Unix() > acc.ExpiresAt-300 {
|
||||
seen[acc.ID] = true
|
||||
continue
|
||||
}
|
||||
|
||||
// 跳过额度已用尽的账号(适用于所有订阅类型)
|
||||
if acc.UsageLimit > 0 && acc.UsageCurrent >= acc.UsageLimit {
|
||||
seen[acc.ID] = true
|
||||
continue
|
||||
}
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
// 无可用账号,返回冷却时间最短的
|
||||
// 无可用账号,返回冷却时间最短的(排除额度用尽的)
|
||||
var best *config.Account
|
||||
var earliest time.Time
|
||||
for i := range p.accounts {
|
||||
acc := &p.accounts[i]
|
||||
// 额度用尽的账号不作为 fallback
|
||||
if acc.UsageLimit > 0 && acc.UsageCurrent >= acc.UsageLimit {
|
||||
continue
|
||||
}
|
||||
if cooldown, ok := p.cooldowns[acc.ID]; ok {
|
||||
if best == nil || cooldown.Before(earliest) {
|
||||
best = acc
|
||||
|
||||
Reference in New Issue
Block a user