4
This commit is contained in:
@@ -20,6 +20,20 @@ except ImportError:
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
def _is_shutdown_requested():
|
||||||
|
"""检查是否收到停止请求"""
|
||||||
|
try:
|
||||||
|
import run
|
||||||
|
return run._shutdown_requested
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class ShutdownRequested(Exception):
|
||||||
|
"""用户请求停止异常"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def log_status(step, message):
|
def log_status(step, message):
|
||||||
"""日志输出"""
|
"""日志输出"""
|
||||||
timestamp = time.strftime("%H:%M:%S")
|
timestamp = time.strftime("%H:%M:%S")
|
||||||
@@ -330,12 +344,20 @@ def get_verification_code_api(target_email: str, mail_api_base: str, mail_api_to
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: 验证码,失败返回空字符串
|
str: 验证码,失败返回空字符串
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ShutdownRequested: 用户请求停止时抛出
|
||||||
"""
|
"""
|
||||||
log_status("API监听", "正在监听邮件...")
|
log_status("API监听", "正在监听邮件...")
|
||||||
headers = {"Authorization": mail_api_token, "Content-Type": "application/json"}
|
headers = {"Authorization": mail_api_token, "Content-Type": "application/json"}
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
for i in range(max_retries):
|
for i in range(max_retries):
|
||||||
|
# 检查停止请求
|
||||||
|
if _is_shutdown_requested():
|
||||||
|
log_status("停止", "[!] 检测到停止请求,中断邮件监听")
|
||||||
|
raise ShutdownRequested("用户请求停止")
|
||||||
|
|
||||||
elapsed = int(time.time() - start_time)
|
elapsed = int(time.time() - start_time)
|
||||||
try:
|
try:
|
||||||
url = f"{mail_api_base}/api/public/emailList"
|
url = f"{mail_api_base}/api/public/emailList"
|
||||||
@@ -389,6 +411,9 @@ def api_register_flow(
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
ChatGPTAPIRegister: 成功返回 reg 对象,失败返回 None
|
ChatGPTAPIRegister: 成功返回 reg 对象,失败返回 None
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ShutdownRequested: 用户请求停止时抛出
|
||||||
"""
|
"""
|
||||||
def log_cb(msg):
|
def log_cb(msg):
|
||||||
if progress_callback:
|
if progress_callback:
|
||||||
@@ -396,57 +421,72 @@ def api_register_flow(
|
|||||||
else:
|
else:
|
||||||
log_progress(msg)
|
log_progress(msg)
|
||||||
|
|
||||||
|
def check_shutdown():
|
||||||
|
"""检查停止请求"""
|
||||||
|
if _is_shutdown_requested():
|
||||||
|
log_cb("[!] 检测到停止请求")
|
||||||
|
raise ShutdownRequested("用户请求停止")
|
||||||
|
|
||||||
reg = ChatGPTAPIRegister(proxy=proxy)
|
reg = ChatGPTAPIRegister(proxy=proxy)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
check_shutdown()
|
||||||
log_status("API注册", "初始化会话...")
|
log_status("API注册", "初始化会话...")
|
||||||
if not reg.init_session():
|
if not reg.init_session():
|
||||||
log_cb("[X] 初始化失败")
|
log_cb("[X] 初始化失败")
|
||||||
return None
|
return None
|
||||||
log_cb("[OK] 会话初始化成功")
|
log_cb("[OK] 会话初始化成功")
|
||||||
|
|
||||||
|
check_shutdown()
|
||||||
log_status("API注册", "获取授权 URL...")
|
log_status("API注册", "获取授权 URL...")
|
||||||
if not reg.get_authorize_url(email):
|
if not reg.get_authorize_url(email):
|
||||||
log_cb("[X] 获取授权 URL 失败")
|
log_cb("[X] 获取授权 URL 失败")
|
||||||
return None
|
return None
|
||||||
log_cb("[OK] 授权 URL 获取成功")
|
log_cb("[OK] 授权 URL 获取成功")
|
||||||
|
|
||||||
|
check_shutdown()
|
||||||
log_status("API注册", "开始授权流程...")
|
log_status("API注册", "开始授权流程...")
|
||||||
if not reg.start_authorize():
|
if not reg.start_authorize():
|
||||||
log_cb("[X] 授权流程启动失败")
|
log_cb("[X] 授权流程启动失败")
|
||||||
return None
|
return None
|
||||||
log_cb("[OK] 授权流程已启动")
|
log_cb("[OK] 授权流程已启动")
|
||||||
|
|
||||||
|
check_shutdown()
|
||||||
log_status("API注册", "注册账户...")
|
log_status("API注册", "注册账户...")
|
||||||
if not reg.register(email, password):
|
if not reg.register(email, password):
|
||||||
log_cb("[X] 注册失败")
|
log_cb("[X] 注册失败")
|
||||||
return None
|
return None
|
||||||
log_cb("[OK] 账户注册成功")
|
log_cb("[OK] 账户注册成功")
|
||||||
|
|
||||||
|
check_shutdown()
|
||||||
log_status("API注册", "发送验证邮件...")
|
log_status("API注册", "发送验证邮件...")
|
||||||
if not reg.send_verification_email():
|
if not reg.send_verification_email():
|
||||||
log_cb("[X] 发送验证邮件失败")
|
log_cb("[X] 发送验证邮件失败")
|
||||||
return None
|
return None
|
||||||
log_cb("[OK] 验证邮件已发送")
|
log_cb("[OK] 验证邮件已发送")
|
||||||
|
|
||||||
|
check_shutdown()
|
||||||
# 获取验证码
|
# 获取验证码
|
||||||
otp_code = get_verification_code_api(email, mail_api_base, mail_api_token)
|
otp_code = get_verification_code_api(email, mail_api_base, mail_api_token)
|
||||||
if not otp_code:
|
if not otp_code:
|
||||||
log_cb("[X] 未能获取验证码")
|
log_cb("[X] 未能获取验证码")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
check_shutdown()
|
||||||
log_status("API注册", f"验证 OTP: {otp_code}")
|
log_status("API注册", f"验证 OTP: {otp_code}")
|
||||||
if not reg.validate_otp(otp_code):
|
if not reg.validate_otp(otp_code):
|
||||||
log_cb("[X] OTP 验证失败")
|
log_cb("[X] OTP 验证失败")
|
||||||
return None
|
return None
|
||||||
log_cb("[OK] OTP 验证成功")
|
log_cb("[OK] OTP 验证成功")
|
||||||
|
|
||||||
|
check_shutdown()
|
||||||
# 创建账户(带重试)
|
# 创建账户(带重试)
|
||||||
log_status("API注册", "创建账户...")
|
log_status("API注册", "创建账户...")
|
||||||
create_success = reg.create_account(real_name, birthdate)
|
create_success = reg.create_account(real_name, birthdate)
|
||||||
|
|
||||||
# 如果创建失败,重新获取验证码再试一次
|
# 如果创建失败,重新获取验证码再试一次
|
||||||
if not create_success:
|
if not create_success:
|
||||||
|
check_shutdown()
|
||||||
log_cb("[!] 创建账户失败,尝试重新验证...")
|
log_cb("[!] 创建账户失败,尝试重新验证...")
|
||||||
|
|
||||||
# 重新发送验证邮件
|
# 重新发送验证邮件
|
||||||
@@ -456,6 +496,7 @@ def api_register_flow(
|
|||||||
return None
|
return None
|
||||||
log_cb("[OK] 验证邮件已重新发送")
|
log_cb("[OK] 验证邮件已重新发送")
|
||||||
|
|
||||||
|
check_shutdown()
|
||||||
# 重新获取验证码
|
# 重新获取验证码
|
||||||
time.sleep(2) # 等待新邮件
|
time.sleep(2) # 等待新邮件
|
||||||
otp_code = get_verification_code_api(email, mail_api_base, mail_api_token)
|
otp_code = get_verification_code_api(email, mail_api_base, mail_api_token)
|
||||||
@@ -463,12 +504,14 @@ def api_register_flow(
|
|||||||
log_cb("[X] 未能获取新验证码")
|
log_cb("[X] 未能获取新验证码")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
check_shutdown()
|
||||||
log_status("API注册", f"重新验证 OTP: {otp_code}")
|
log_status("API注册", f"重新验证 OTP: {otp_code}")
|
||||||
if not reg.validate_otp(otp_code):
|
if not reg.validate_otp(otp_code):
|
||||||
log_cb("[X] OTP 重新验证失败")
|
log_cb("[X] OTP 重新验证失败")
|
||||||
return None
|
return None
|
||||||
log_cb("[OK] OTP 重新验证成功")
|
log_cb("[OK] OTP 重新验证成功")
|
||||||
|
|
||||||
|
check_shutdown()
|
||||||
# 再次尝试创建账户
|
# 再次尝试创建账户
|
||||||
log_status("API注册", "重新创建账户...")
|
log_status("API注册", "重新创建账户...")
|
||||||
if not reg.create_account(real_name, birthdate):
|
if not reg.create_account(real_name, birthdate):
|
||||||
@@ -477,6 +520,7 @@ def api_register_flow(
|
|||||||
|
|
||||||
log_cb("[OK] 账户创建成功")
|
log_cb("[OK] 账户创建成功")
|
||||||
|
|
||||||
|
check_shutdown()
|
||||||
# 验证 session 是否有效
|
# 验证 session 是否有效
|
||||||
token = reg.get_session_token()
|
token = reg.get_session_token()
|
||||||
if token:
|
if token:
|
||||||
@@ -486,6 +530,8 @@ def api_register_flow(
|
|||||||
|
|
||||||
return reg
|
return reg
|
||||||
|
|
||||||
|
except ShutdownRequested:
|
||||||
|
raise # 重新抛出停止请求异常
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_status("错误", f"注册异常: {e}")
|
log_status("错误", f"注册异常: {e}")
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ try:
|
|||||||
api_login_flow,
|
api_login_flow,
|
||||||
is_api_mode_available,
|
is_api_mode_available,
|
||||||
get_verification_code_api,
|
get_verification_code_api,
|
||||||
|
ShutdownRequested,
|
||||||
)
|
)
|
||||||
API_MODE_AVAILABLE = is_api_mode_available()
|
API_MODE_AVAILABLE = is_api_mode_available()
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -37,6 +38,7 @@ except ImportError:
|
|||||||
ChatGPTAPIRegister = None
|
ChatGPTAPIRegister = None
|
||||||
api_register_flow = None
|
api_register_flow = None
|
||||||
api_login_flow = None
|
api_login_flow = None
|
||||||
|
ShutdownRequested = Exception # 回退到基础异常类
|
||||||
|
|
||||||
# ================= 配置加载 =================
|
# ================= 配置加载 =================
|
||||||
try:
|
try:
|
||||||
@@ -2432,6 +2434,9 @@ def run_single_registration_api(progress_callback=None, step_callback=None, prox
|
|||||||
log_status("失败", "注册成功但支付/获取token失败")
|
log_status("失败", "注册成功但支付/获取token失败")
|
||||||
return {"success": False, "error": "支付流程失败", "account": email, "password": password}
|
return {"success": False, "error": "支付流程失败", "account": email, "password": password}
|
||||||
|
|
||||||
|
except ShutdownRequested:
|
||||||
|
log_status("停止", "[!] 用户请求停止")
|
||||||
|
return {"success": False, "error": "用户停止", "stopped": True, "account": email, "password": password}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = str(e)
|
error_msg = str(e)
|
||||||
# 只有连接断开才认为是停止请求
|
# 只有连接断开才认为是停止请求
|
||||||
|
|||||||
110
telegram_bot.py
110
telegram_bot.py
@@ -2716,6 +2716,54 @@ class ProvisionerBot:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
await update.message.reply_text(f"❌ 修改配置失败: {e}")
|
await update.message.reply_text(f"❌ 修改配置失败: {e}")
|
||||||
|
|
||||||
|
async def _test_mail_api_connection(self, mail_api_base: str, mail_api_token: str, domain: str) -> tuple[bool, str]:
|
||||||
|
"""测试邮件 API 连接
|
||||||
|
|
||||||
|
Args:
|
||||||
|
mail_api_base: 邮件 API 地址
|
||||||
|
mail_api_token: 邮件 API Token
|
||||||
|
domain: 测试用的邮箱域名
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple: (success, message)
|
||||||
|
"""
|
||||||
|
import requests
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 生成测试邮箱
|
||||||
|
random_str = ''.join(random.choices(string.ascii_lowercase + string.digits, k=8))
|
||||||
|
test_email = f"test-{random_str}@{domain.lstrip('@')}"
|
||||||
|
|
||||||
|
# 测试 API 连接
|
||||||
|
url = f"{mail_api_base}/api/public/emailList"
|
||||||
|
headers = {
|
||||||
|
"Authorization": mail_api_token,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
payload = {
|
||||||
|
"toEmail": test_email,
|
||||||
|
"timeSort": "desc",
|
||||||
|
"size": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(url, headers=headers, json=payload, timeout=10)
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
if data.get("code") == 200:
|
||||||
|
return True, "邮件 API 连接正常"
|
||||||
|
else:
|
||||||
|
error_msg = data.get("message", "未知错误")
|
||||||
|
return False, f"API 响应异常: {error_msg}"
|
||||||
|
|
||||||
|
except requests.exceptions.Timeout:
|
||||||
|
return False, "连接超时,无法连接到邮件 API 服务器"
|
||||||
|
except requests.exceptions.ConnectionError:
|
||||||
|
return False, "连接失败,请检查 mail_api_base 配置"
|
||||||
|
except Exception as e:
|
||||||
|
return False, f"测试失败: {e}"
|
||||||
|
|
||||||
@admin_only
|
@admin_only
|
||||||
async def cmd_team_register(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def cmd_team_register(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
"""开始 GPT Team 自动订阅注册"""
|
"""开始 GPT Team 自动订阅注册"""
|
||||||
@@ -2757,6 +2805,25 @@ class ProvisionerBot:
|
|||||||
parse_mode="HTML"
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 测试邮件 API 连接
|
||||||
|
await update.message.reply_text("⏳ 正在检测邮件 API 连接...")
|
||||||
|
|
||||||
|
import random
|
||||||
|
test_domain = random.choice(domains)
|
||||||
|
success, message = await self._test_mail_api_connection(MAIL_API_BASE, MAIL_API_TOKEN, test_domain)
|
||||||
|
|
||||||
|
if not success:
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"<b>❌ 邮件 API 连接失败</b>\n\n"
|
||||||
|
f"错误: {message}\n\n"
|
||||||
|
f"请检查配置后重试:\n"
|
||||||
|
f"• mail_api_base: {MAIL_API_BASE}\n"
|
||||||
|
f"• mail_api_token: {'已配置' if MAIL_API_TOKEN else '未配置'}",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
await update.message.reply_text("❌ auto_gpt_team 模块未找到")
|
await update.message.reply_text("❌ auto_gpt_team 模块未找到")
|
||||||
return
|
return
|
||||||
@@ -2943,6 +3010,8 @@ class ProvisionerBot:
|
|||||||
try:
|
try:
|
||||||
import run
|
import run
|
||||||
if run._shutdown_requested:
|
if run._shutdown_requested:
|
||||||
|
with step_lock:
|
||||||
|
current_step[0] = "用户请求停止..."
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
@@ -2953,6 +3022,13 @@ class ProvisionerBot:
|
|||||||
import functools
|
import functools
|
||||||
|
|
||||||
def run_with_callback():
|
def run_with_callback():
|
||||||
|
# 在执行前再次检查停止请求
|
||||||
|
try:
|
||||||
|
import run as run_module
|
||||||
|
if run_module._shutdown_requested:
|
||||||
|
return {"success": False, "error": "用户停止", "stopped": True}
|
||||||
|
except:
|
||||||
|
pass
|
||||||
return run_single_registration_auto(
|
return run_single_registration_auto(
|
||||||
progress_callback=None,
|
progress_callback=None,
|
||||||
step_callback=step_callback
|
step_callback=step_callback
|
||||||
@@ -2971,6 +3047,8 @@ class ProvisionerBot:
|
|||||||
if result.get("stopped"):
|
if result.get("stopped"):
|
||||||
# 被 /stop 命令中断,不计入失败
|
# 被 /stop 命令中断,不计入失败
|
||||||
log.info("注册被用户停止")
|
log.info("注册被用户停止")
|
||||||
|
with step_lock:
|
||||||
|
current_step[0] = "已停止"
|
||||||
break
|
break
|
||||||
elif result.get("success"):
|
elif result.get("success"):
|
||||||
success_count += 1
|
success_count += 1
|
||||||
@@ -2985,12 +3063,35 @@ class ProvisionerBot:
|
|||||||
else:
|
else:
|
||||||
fail_count += 1
|
fail_count += 1
|
||||||
log.warning(f"注册失败: {result.get('error', '未知错误')}")
|
log.warning(f"注册失败: {result.get('error', '未知错误')}")
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
log.info("注册任务被取消")
|
||||||
|
with step_lock:
|
||||||
|
current_step[0] = "已取消"
|
||||||
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
fail_count += 1
|
fail_count += 1
|
||||||
log.error(f"注册异常: {e}")
|
log.error(f"注册异常: {e}")
|
||||||
|
|
||||||
# 清理浏览器进程
|
# 清理浏览器进程
|
||||||
cleanup_chrome_processes()
|
cleanup_chrome_processes()
|
||||||
|
|
||||||
|
# 每次注册后检查停止请求
|
||||||
|
try:
|
||||||
|
import run
|
||||||
|
if run._shutdown_requested:
|
||||||
|
with step_lock:
|
||||||
|
current_step[0] = "用户请求停止..."
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 检查是否被停止
|
||||||
|
stopped = False
|
||||||
|
try:
|
||||||
|
import run
|
||||||
|
stopped = run._shutdown_requested
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# 停止进度更新任务
|
# 停止进度更新任务
|
||||||
progress_task.cancel()
|
progress_task.cancel()
|
||||||
@@ -3001,8 +3102,15 @@ class ProvisionerBot:
|
|||||||
|
|
||||||
# 完成进度
|
# 完成进度
|
||||||
progress_bar = '▰' * 20
|
progress_bar = '▰' * 20
|
||||||
|
completed = success_count + fail_count
|
||||||
|
|
||||||
|
if stopped:
|
||||||
|
status_text = f"<b>🛑 注册已停止</b> {completed}/{count}"
|
||||||
|
else:
|
||||||
|
status_text = f"<b>🎉 注册完成!</b> {success_count}/{count}"
|
||||||
|
|
||||||
await progress_msg.edit_text(
|
await progress_msg.edit_text(
|
||||||
f"<b>🎉 注册完成!</b> {success_count}/{count}\n"
|
f"{status_text}\n"
|
||||||
f"{progress_bar}\n\n"
|
f"{progress_bar}\n\n"
|
||||||
f"✅ 成功: {success_count}\n"
|
f"✅ 成功: {success_count}\n"
|
||||||
f"❌ 失败: {fail_count}",
|
f"❌ 失败: {fail_count}",
|
||||||
|
|||||||
Reference in New Issue
Block a user