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:
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user