feat(registration): Add email retry mechanism with team invitation support

- Add automatic email retry logic when verification code times out (5-second timeout)
- Implement new email creation and team invitation for failed verification attempts
- Add max_email_retries parameter to control retry attempts (default: 3)
- Add team_name parameter to enable automatic team invitations for new emails
- Return special "new_email:xxx@xxx.com:password" format when new email is used
- Update register_openai_account_auto() to support team_name parameter
- Update register_and_authorize() to support team_name parameter and return new email info
- Improve verification code timeout handling with configurable retry intervals
- Add nonlocal verification_timeout flag to track timeout state across retries
- Update docstrings to document new parameters and return value changes
This commit is contained in:
2026-01-30 08:46:03 +08:00
parent b7e658c567
commit 75a0dccebe
3 changed files with 261 additions and 62 deletions

View File

@@ -136,6 +136,7 @@ class ProvisionerBot:
("logs_stop", self.cmd_logs_stop),
("dashboard", self.cmd_dashboard),
("import", self.cmd_import),
("verify", self.cmd_verify),
("stock", self.cmd_stock),
("gptmail_keys", self.cmd_gptmail_keys),
("gptmail_add", self.cmd_gptmail_add),
@@ -269,6 +270,7 @@ class ProvisionerBot:
BotCommand("stock", "查看账号库存"),
BotCommand("s2a_config", "配置 S2A 参数"),
BotCommand("import", "导入账号到 team.json"),
BotCommand("verify", "验证账号并移除无效账号"),
# GPTMail
BotCommand("gptmail_keys", "查看 GPTMail API Keys"),
BotCommand("gptmail_add", "添加 GPTMail API Key"),
@@ -336,6 +338,7 @@ class ProvisionerBot:
<b>📤 导入账号:</b>
/import - 导入账号到 team.json
/verify - 验证账号并移除无效账号
或直接发送 JSON 文件
<b>📧 GPTMail 管理:</b>
@@ -2093,7 +2096,7 @@ class ProvisionerBot:
await self.app.bot.edit_message_text(
chat_id=chat_id,
message_id=progress_msg.message_id,
text=f"<b>🔍 正在验证账号...</b>\n\n⏳ 验证 {total} 个账号的 account_id...",
text=f"<b>🔍 正在验证账号...</b>\n\n⏳ 验证 {total} 个账号的 account_id (20 并发)...",
parse_mode="HTML"
)
@@ -2119,9 +2122,10 @@ class ProvisionerBot:
return idx, email, account_id
# 使用线程池并行验证
max_workers = min(10, total)
# 使用线程池并行验证 (20 并发)
max_workers = min(20, total)
completed_count = 0
last_update_time = 0
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {executor.submit(verify_account, item): item for item in accounts_to_verify}
@@ -2138,8 +2142,11 @@ class ProvisionerBot:
# 验证失败
failed_accounts.append({"idx": idx, "email": email})
# 每处理 5 个更新一次进度
if completed_count % 5 == 0 or completed_count == total:
# 每处理 10 个或间隔 1 秒更新一次进度
import time
current_time = time.time()
if completed_count % 10 == 0 or completed_count == total or current_time - last_update_time > 1:
last_update_time = current_time
try:
await self.app.bot.edit_message_text(
chat_id=chat_id,
@@ -2208,6 +2215,63 @@ class ProvisionerBot:
except Exception:
pass
@admin_only
async def cmd_verify(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""手动验证 team.json 中的账号,获取 account_id 并移除无效账号"""
chat_id = update.effective_chat.id
# 检查是否有任务正在运行
if self.current_task and not self.current_task.done():
await update.message.reply_text(
f"⚠️ 有任务正在运行: {self.current_team}\n"
"请等待任务完成或使用 /stop 停止后再验证"
)
return
# 检查 team.json 是否存在
from pathlib import Path
team_json_path = Path(TEAM_JSON_FILE)
if not team_json_path.exists():
await update.message.reply_text("❌ team.json 不存在,请先导入账号")
return
# 统计需要验证的账号
import json
try:
with open(team_json_path, "r", encoding="utf-8") as f:
accounts = json.load(f)
if not isinstance(accounts, list):
accounts = [accounts]
except Exception as e:
await update.message.reply_text(f"❌ 读取 team.json 失败: {e}")
return
total_accounts = len(accounts)
need_verify = sum(1 for acc in accounts if acc.get("token") and not acc.get("account_id"))
already_verified = sum(1 for acc in accounts if acc.get("account_id"))
if need_verify == 0:
await update.message.reply_text(
f"<b>✅ 无需验证</b>\n\n"
f"team.json 共 {total_accounts} 个账号\n"
f"已验证: {already_verified}\n"
f"待验证: 0",
parse_mode="HTML"
)
return
await update.message.reply_text(
f"<b>🔍 开始验证账号</b>\n\n"
f"team.json 共 {total_accounts} 个账号\n"
f"已验证: {already_verified}\n"
f"待验证: {need_verify}\n\n"
f"⏳ 正在验证...",
parse_mode="HTML"
)
# 执行验证
await self._validate_and_cleanup_accounts(chat_id)
async def _import_batch_timeout_callback(self, context: ContextTypes.DEFAULT_TYPE):
"""批量导入超时回调 - 由 job_queue 调用"""
chat_id = context.job.data.get("chat_id")