feat: Implement CodexAuth proxy pool management with a new frontend configuration page and a dedicated backend service for API, database, and proxy testing.
This commit is contained in:
@@ -54,10 +54,14 @@ func Init(dbPath string) error {
|
||||
// migrate 数据库迁移
|
||||
func (d *DB) migrate() error {
|
||||
// 添加 last_checked_at 列(如果不存在)
|
||||
_, err := d.db.Exec(`ALTER TABLE team_owners ADD COLUMN last_checked_at DATETIME`)
|
||||
if err != nil && !isColumnExistsError(err) {
|
||||
return err
|
||||
}
|
||||
_, _ = d.db.Exec(`ALTER TABLE team_owners ADD COLUMN last_checked_at DATETIME`)
|
||||
|
||||
// 添加 last_test_at 列 (如果不存在)
|
||||
_, _ = d.db.Exec(`ALTER TABLE codex_auth_proxies ADD COLUMN last_test_at DATETIME`)
|
||||
|
||||
// 添加 location 列 (如果不存在)
|
||||
_, _ = d.db.Exec(`ALTER TABLE codex_auth_proxies ADD COLUMN location TEXT`)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -135,6 +139,8 @@ func (d *DB) createTables() error {
|
||||
last_used_at DATETIME,
|
||||
success_count INTEGER DEFAULT 0,
|
||||
fail_count INTEGER DEFAULT 0,
|
||||
location TEXT,
|
||||
last_test_at DATETIME,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
@@ -272,7 +278,7 @@ func (d *DB) GetTeamOwners(status string, limit, offset int) ([]TeamOwner, int,
|
||||
return owners, total, nil
|
||||
}
|
||||
|
||||
// GetPendingOwners 获取待处理(排除已使用和处理中的)
|
||||
// GetPendingOwners 获取待处理(排除已使用 and 处理中的)
|
||||
func (d *DB) GetPendingOwners() ([]TeamOwner, error) {
|
||||
rows, err := d.db.Query(`
|
||||
SELECT id, email, password, token, account_id, status, created_at, last_checked_at
|
||||
@@ -760,6 +766,8 @@ type CodexProxy struct {
|
||||
LastUsedAt *time.Time `json:"last_used_at,omitempty"`
|
||||
SuccessCount int `json:"success_count"`
|
||||
FailCount int `json:"fail_count"`
|
||||
Location string `json:"location"`
|
||||
LastTestAt *time.Time `json:"last_test_at,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
@@ -813,7 +821,7 @@ func (d *DB) AddCodexProxies(proxies []string) (int, error) {
|
||||
// GetCodexProxies 获取代理列表
|
||||
func (d *DB) GetCodexProxies() ([]CodexProxy, error) {
|
||||
rows, err := d.db.Query(`
|
||||
SELECT id, proxy_url, COALESCE(description, ''), is_enabled, last_used_at, success_count, fail_count, created_at
|
||||
SELECT id, proxy_url, COALESCE(description, ''), is_enabled, last_used_at, success_count, fail_count, COALESCE(location, ''), last_test_at, created_at
|
||||
FROM codex_auth_proxies
|
||||
ORDER BY created_at DESC
|
||||
`)
|
||||
@@ -825,14 +833,17 @@ func (d *DB) GetCodexProxies() ([]CodexProxy, error) {
|
||||
var proxies []CodexProxy
|
||||
for rows.Next() {
|
||||
var p CodexProxy
|
||||
var lastUsedAt sql.NullTime
|
||||
err := rows.Scan(&p.ID, &p.ProxyURL, &p.Description, &p.IsEnabled, &lastUsedAt, &p.SuccessCount, &p.FailCount, &p.CreatedAt)
|
||||
var lastUsedAt, lastTestAt sql.NullTime
|
||||
err := rows.Scan(&p.ID, &p.ProxyURL, &p.Description, &p.IsEnabled, &lastUsedAt, &p.SuccessCount, &p.FailCount, &p.Location, &lastTestAt, &p.CreatedAt)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if lastUsedAt.Valid {
|
||||
p.LastUsedAt = &lastUsedAt.Time
|
||||
}
|
||||
if lastTestAt.Valid {
|
||||
p.LastTestAt = &lastTestAt.Time
|
||||
}
|
||||
proxies = append(proxies, p)
|
||||
}
|
||||
return proxies, nil
|
||||
@@ -841,7 +852,7 @@ func (d *DB) GetCodexProxies() ([]CodexProxy, error) {
|
||||
// GetEnabledCodexProxies 获取已启用的代理列表
|
||||
func (d *DB) GetEnabledCodexProxies() ([]CodexProxy, error) {
|
||||
rows, err := d.db.Query(`
|
||||
SELECT id, proxy_url, COALESCE(description, ''), is_enabled, last_used_at, success_count, fail_count, created_at
|
||||
SELECT id, proxy_url, COALESCE(description, ''), is_enabled, last_used_at, success_count, fail_count, COALESCE(location, ''), last_test_at, created_at
|
||||
FROM codex_auth_proxies
|
||||
WHERE is_enabled = 1
|
||||
ORDER BY success_count DESC, fail_count ASC
|
||||
@@ -854,14 +865,17 @@ func (d *DB) GetEnabledCodexProxies() ([]CodexProxy, error) {
|
||||
var proxies []CodexProxy
|
||||
for rows.Next() {
|
||||
var p CodexProxy
|
||||
var lastUsedAt sql.NullTime
|
||||
err := rows.Scan(&p.ID, &p.ProxyURL, &p.Description, &p.IsEnabled, &lastUsedAt, &p.SuccessCount, &p.FailCount, &p.CreatedAt)
|
||||
var lastUsedAt, lastTestAt sql.NullTime
|
||||
err := rows.Scan(&p.ID, &p.ProxyURL, &p.Description, &p.IsEnabled, &lastUsedAt, &p.SuccessCount, &p.FailCount, &p.Location, &lastTestAt, &p.CreatedAt)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if lastUsedAt.Valid {
|
||||
p.LastUsedAt = &lastUsedAt.Time
|
||||
}
|
||||
if lastTestAt.Valid {
|
||||
p.LastTestAt = &lastTestAt.Time
|
||||
}
|
||||
proxies = append(proxies, p)
|
||||
}
|
||||
return proxies, nil
|
||||
@@ -897,6 +911,24 @@ func (d *DB) UpdateCodexProxyStats(proxyURL string, success bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateCodexProxyTestResult 更新代理测试结果
|
||||
func (d *DB) UpdateCodexProxyTestResult(id int64, location string, success bool) error {
|
||||
if success {
|
||||
_, err := d.db.Exec(`
|
||||
UPDATE codex_auth_proxies
|
||||
SET location = ?, last_test_at = CURRENT_TIMESTAMP, success_count = success_count + 1
|
||||
WHERE id = ?
|
||||
`, location, id)
|
||||
return err
|
||||
}
|
||||
_, err := d.db.Exec(`
|
||||
UPDATE codex_auth_proxies
|
||||
SET last_test_at = CURRENT_TIMESTAMP, fail_count = fail_count + 1
|
||||
WHERE id = ?
|
||||
`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
// ToggleCodexProxy 切换代理启用状态
|
||||
func (d *DB) ToggleCodexProxy(id int64) error {
|
||||
_, err := d.db.Exec("UPDATE codex_auth_proxies SET is_enabled = 1 - is_enabled WHERE id = ?", id)
|
||||
|
||||
Reference in New Issue
Block a user