mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 00:53:33 +00:00
feat: 添加Droid账户API Key管理功能
(cherry picked from commit 0cf3ca6c7eafcf28a2da7e8bfd6814b4883bb752)
This commit is contained in:
@@ -183,7 +183,10 @@ class DroidAccountService {
|
||||
? []
|
||||
: normalizedExisting
|
||||
.filter((entry) => entry && entry.id && entry.encryptedKey)
|
||||
.map((entry) => ({ ...entry }))
|
||||
.map((entry) => ({
|
||||
...entry,
|
||||
status: entry.status || 'active' // 确保有默认状态
|
||||
}))
|
||||
|
||||
const hashSet = new Set(entries.map((entry) => entry.hash).filter(Boolean))
|
||||
|
||||
@@ -214,7 +217,9 @@ class DroidAccountService {
|
||||
encryptedKey: this._encryptSensitiveData(trimmed),
|
||||
createdAt: now,
|
||||
lastUsedAt: '',
|
||||
usageCount: '0'
|
||||
usageCount: '0',
|
||||
status: 'active', // 新增状态字段
|
||||
errorMessage: '' // 新增错误信息字段
|
||||
})
|
||||
}
|
||||
|
||||
@@ -230,7 +235,9 @@ class DroidAccountService {
|
||||
id: entry.id,
|
||||
createdAt: entry.createdAt || '',
|
||||
lastUsedAt: entry.lastUsedAt || '',
|
||||
usageCount: entry.usageCount || '0'
|
||||
usageCount: entry.usageCount || '0',
|
||||
status: entry.status || 'active', // 新增状态字段
|
||||
errorMessage: entry.errorMessage || '' // 新增错误信息字段
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -252,7 +259,9 @@ class DroidAccountService {
|
||||
hash: entry.hash || '',
|
||||
createdAt: entry.createdAt || '',
|
||||
lastUsedAt: entry.lastUsedAt || '',
|
||||
usageCount: Number.isFinite(usageCountNumber) && usageCountNumber >= 0 ? usageCountNumber : 0
|
||||
usageCount: Number.isFinite(usageCountNumber) && usageCountNumber >= 0 ? usageCountNumber : 0,
|
||||
status: entry.status || 'active', // 新增状态字段
|
||||
errorMessage: entry.errorMessage || '' // 新增错误信息字段
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,6 +357,56 @@ class DroidAccountService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记指定的 Droid API Key 条目为异常状态
|
||||
*/
|
||||
async markApiKeyAsError(accountId, keyId, errorMessage = '') {
|
||||
if (!accountId || !keyId) {
|
||||
return { marked: false, error: '参数无效' }
|
||||
}
|
||||
|
||||
try {
|
||||
const accountData = await redis.getDroidAccount(accountId)
|
||||
if (!accountData) {
|
||||
return { marked: false, error: '账户不存在' }
|
||||
}
|
||||
|
||||
const entries = this._parseApiKeyEntries(accountData.apiKeys)
|
||||
if (!entries || entries.length === 0) {
|
||||
return { marked: false, error: '无API Key条目' }
|
||||
}
|
||||
|
||||
let marked = false
|
||||
const updatedEntries = entries.map((entry) => {
|
||||
if (entry && entry.id === keyId) {
|
||||
marked = true
|
||||
return {
|
||||
...entry,
|
||||
status: 'error',
|
||||
errorMessage: errorMessage || 'API Key异常'
|
||||
}
|
||||
}
|
||||
return entry
|
||||
})
|
||||
|
||||
if (!marked) {
|
||||
return { marked: false, error: '未找到指定的API Key' }
|
||||
}
|
||||
|
||||
accountData.apiKeys = JSON.stringify(updatedEntries)
|
||||
await redis.setDroidAccount(accountId, accountData)
|
||||
|
||||
logger.warn(
|
||||
`⚠️ 已标记 Droid API Key ${keyId} 为异常状态(Account: ${accountId}):${errorMessage}`
|
||||
)
|
||||
|
||||
return { marked: true }
|
||||
} catch (error) {
|
||||
logger.error(`❌ 标记 Droid API Key 异常状态失败:${keyId}(Account: ${accountId})`, error)
|
||||
return { marked: false, error: error.message }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 WorkOS Refresh Token 刷新并验证凭证
|
||||
*/
|
||||
@@ -979,7 +1038,7 @@ class DroidAccountService {
|
||||
? updates.apiKeyUpdateMode.trim().toLowerCase()
|
||||
: ''
|
||||
|
||||
let apiKeyUpdateMode = ['append', 'replace', 'delete'].includes(rawApiKeyMode)
|
||||
let apiKeyUpdateMode = ['append', 'replace', 'delete', 'update'].includes(rawApiKeyMode)
|
||||
? rawApiKeyMode
|
||||
: ''
|
||||
|
||||
@@ -1041,6 +1100,53 @@ class DroidAccountService {
|
||||
} else if (removeApiKeysInput.length > 0) {
|
||||
logger.warn(`⚠️ 删除模式未收到有效的 Droid API Key: ${accountId}`)
|
||||
}
|
||||
} else if (apiKeyUpdateMode === 'update') {
|
||||
// 更新模式:根据提供的 key 匹配现有条目并更新状态
|
||||
mergedApiKeys = [...existingApiKeyEntries]
|
||||
const updatedHashes = new Set()
|
||||
|
||||
for (const updateItem of newApiKeysInput) {
|
||||
if (!updateItem || typeof updateItem !== 'object') {
|
||||
continue
|
||||
}
|
||||
|
||||
const key = updateItem.key || updateItem.apiKey || ''
|
||||
if (!key || typeof key !== 'string') {
|
||||
continue
|
||||
}
|
||||
|
||||
const trimmed = key.trim()
|
||||
if (!trimmed) {
|
||||
continue
|
||||
}
|
||||
|
||||
const hash = crypto.createHash('sha256').update(trimmed).digest('hex')
|
||||
updatedHashes.add(hash)
|
||||
|
||||
// 查找现有条目
|
||||
const existingIndex = mergedApiKeys.findIndex(
|
||||
(entry) => entry && entry.hash === hash
|
||||
)
|
||||
|
||||
if (existingIndex !== -1) {
|
||||
// 更新现有条目的状态信息
|
||||
const existingEntry = mergedApiKeys[existingIndex]
|
||||
mergedApiKeys[existingIndex] = {
|
||||
...existingEntry,
|
||||
status: updateItem.status || existingEntry.status || 'active',
|
||||
errorMessage: updateItem.errorMessage !== undefined ? updateItem.errorMessage : existingEntry.errorMessage || '',
|
||||
lastUsedAt: updateItem.lastUsedAt !== undefined ? updateItem.lastUsedAt : existingEntry.lastUsedAt || '',
|
||||
usageCount: updateItem.usageCount !== undefined ? String(updateItem.usageCount) : existingEntry.usageCount || '0'
|
||||
}
|
||||
apiKeysUpdated = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!apiKeysUpdated) {
|
||||
logger.warn(
|
||||
`⚠️ 更新模式未匹配任何 Droid API Key: ${accountId} (提供 ${updatedHashes.size} 个哈希)`
|
||||
)
|
||||
}
|
||||
} else {
|
||||
const clearExisting = apiKeyUpdateMode === 'replace' || wantsClearApiKeys
|
||||
const baselineCount = clearExisting ? 0 : existingApiKeyEntries.length
|
||||
@@ -1063,6 +1169,10 @@ class DroidAccountService {
|
||||
logger.info(
|
||||
`🔑 删除模式更新 Droid API keys for ${accountId}: 已移除 ${removedCount} 条,剩余 ${mergedApiKeys.length}`
|
||||
)
|
||||
} else if (apiKeyUpdateMode === 'update') {
|
||||
logger.info(
|
||||
`🔑 更新模式更新 Droid API keys for ${accountId}: 更新了 ${newApiKeysInput.length} 个 API Key 的状态信息`
|
||||
)
|
||||
} else if (apiKeyUpdateMode === 'replace' || wantsClearApiKeys) {
|
||||
logger.info(
|
||||
`🔑 覆盖模式更新 Droid API keys for ${accountId}: 当前总数 ${mergedApiKeys.length},新增 ${addedCount}`
|
||||
|
||||
Reference in New Issue
Block a user