Token 池管理器(数据库驱动)
| 192 | |
| 193 | |
| 194 | class TokenPool: |
| 195 | """Token 池管理器(数据库驱动)""" |
| 196 | |
| 197 | def __init__( |
| 198 | self, |
| 199 | tokens: List[Tuple[int, str, str]], # [(token_id, token_value, token_type), ...] |
| 200 | failure_threshold: int = 3, |
| 201 | recovery_timeout: int = 1800 |
| 202 | ): |
| 203 | """ |
| 204 | 初始化 Token 池 |
| 205 | |
| 206 | Args: |
| 207 | tokens: Token 列表 [(token_id, token_value, token_type), ...] |
| 208 | failure_threshold: 失败阈值,超过此次数将标记为不可用 |
| 209 | recovery_timeout: 恢复超时时间(秒),失败 Token 在此时间后重新尝试 |
| 210 | """ |
| 211 | self.failure_threshold = failure_threshold |
| 212 | self.recovery_timeout = recovery_timeout |
| 213 | self._lock = Lock() |
| 214 | self._current_index = 0 |
| 215 | |
| 216 | # 初始化 Token 状态(内存中) |
| 217 | self.token_statuses: Dict[str, TokenStatus] = {} |
| 218 | self.token_id_map: Dict[str, int] = {} # token -> token_id 映射 |
| 219 | |
| 220 | for token_id, token_value, token_type in tokens: |
| 221 | if token_value and token_value not in self.token_statuses: |
| 222 | self.token_statuses[token_value] = TokenStatus( |
| 223 | token=token_value, |
| 224 | token_id=token_id, |
| 225 | token_type=token_type |
| 226 | ) |
| 227 | self.token_id_map[token_value] = token_id |
| 228 | |
| 229 | if not self.token_statuses: |
| 230 | logger.warning("⚠️ Token 池为空,将依赖匿名模式") |
| 231 | |
| 232 | def get_next_token(self, exclude_tokens: Optional[Set[str]] = None) -> Optional[str]: |
| 233 | """ |
| 234 | 获取下一个可用的认证用户 Token(轮询算法) |
| 235 | |
| 236 | Returns: |
| 237 | 可用的 Token 字符串,如果没有可用 Token 则返回 None |
| 238 | """ |
| 239 | with self._lock: |
| 240 | if not self.token_statuses: |
| 241 | return None |
| 242 | |
| 243 | excluded = exclude_tokens or set() |
| 244 | |
| 245 | available_tokens = self._get_available_user_tokens() |
| 246 | if excluded: |
| 247 | available_tokens = [ |
| 248 | token for token in available_tokens if token not in excluded |
| 249 | ] |
| 250 | if not available_tokens: |
| 251 | # 尝试恢复过期的失败 Token |
no outgoing calls