fix: continue daemon refill after registration failures

This commit is contained in:
mmc
2026-03-19 15:58:39 +08:00
parent fc0a2968ae
commit d6ea996e09
4 changed files with 105 additions and 19 deletions

View File

@@ -432,6 +432,11 @@ ocxxxxxxx@cursors.online
拿到什么就写什么,缺失字段会写空值或 `NULL`
现在成功和失败都会尽量入库:
- 成功时:`oauth_status = oauth=ok`
- 失败时:`oauth_status = oauth=failed`
关于 `auto_register_max_per_loop`
- `0`:按当前差值动态补齐

View File

@@ -80,6 +80,8 @@ python3 /root/standalone_cli/run.py config setup
当前你这边实际使用的数据库名是:`mail_accounts_db`
现在不仅 `oauth=ok` 的成功注册会入库,`oauth=failed` 的失败注册也会尽量记录当前已拿到的信息。
当前这台机器实测可用的代理是:
- `http://127.0.0.1:17891`
@@ -219,6 +221,7 @@ docker compose up --build
- 按配置周期检查号池状态
- 号池不足且 `auto_register = true` 时自动补号
-`threshold - candidates` 估算补号差值;当 `auto_register_max_per_loop = 0` 时按差值动态补齐,否则受该值限制
- 单个补号失败不会终止整轮补号,会继续尝试后续账号
- 号池满足阈值时不执行注册
-`maintain_interval_minutes` / `sub2api_maintain_interval_minutes` 自动维护

45
main.py
View File

@@ -226,6 +226,34 @@ def _perform_registration_once(cfg: dict[str, Any], proxy: Optional[str]) -> dic
token_data = json.loads(token_json)
email = str(token_data.get("email") or "unknown")
oauth_status = str(token_data.get("oauth_status") or "oauth=ok").strip() or "oauth=ok"
if oauth_status != "oauth=ok":
run_result: dict[str, Any] = {"ok": False, "email": email, "oauth_status": oauth_status}
if cfg.get("db_enabled"):
try:
db_result = save_registered_account(
cfg,
{
"email": token_data.get("email", ""),
"chatgpt_password": token_data.get("account_password", ""),
"mail_password": token_data.get("mail_password", ""),
"oauth_status": oauth_status,
"mail_token": token_data.get("mail_token", ""),
"name": token_data.get("name", ""),
"birthdate": token_data.get("birthdate", ""),
"source": cfg.get("db_source", "standalone_cli"),
},
)
run_result["db_saved"] = bool(db_result.get("ok", False))
print(f"[{'+' if db_result.get('ok') else '-'}] 失败记录{'写入成功' if db_result.get('ok') else '写入失败'}: {email}")
except Exception as exc:
run_result["db_saved"] = False
run_result["db_error"] = str(exc)
print(f"[-] 失败记录写入异常: {exc}")
print("[-] 本次注册失败。")
return run_result
file_name = f"token_{email.replace('@', '_')}_{time.time_ns()}.json"
file_path = Path(TOKENS_DIR) / file_name
_write_text_atomic(str(file_path), token_json)
@@ -366,11 +394,20 @@ def handle_daemon(args: argparse.Namespace) -> dict[str, Any]:
try:
result = _perform_registration_once(cfg, proxy)
if not result.get("ok"):
print("[!] 本次自动补号失败,停止本轮剩余补号")
break
email = str(result.get("email") or "").strip()
status = str(result.get("oauth_status") or result.get("error") or "failed").strip()
if email:
print(f"[!] 本次自动补号失败,继续下一个: {email} ({status})")
else:
print(f"[!] 本次自动补号失败,继续下一个: {status}")
continue
if index < planned - 1:
wait_seconds = random.randint(30, 60)
print(f"[*] 本次注册成功,等待 {wait_seconds} 秒后继续下一个账号...")
time.sleep(wait_seconds)
except Exception as exc:
print(f"[Error] 自动补号失败: {exc}")
break
print(f"[Error] 自动补号异常,继续下一个: {exc}")
continue
else:
print("[+] 当前号池满足阈值,本轮不执行注册")
elif bool(cfg.get("auto_register", False)):

View File

@@ -791,6 +791,34 @@ def _build_token_result(
return json.dumps(config, ensure_ascii=False, separators=(",", ":"))
def _build_registration_failure_result(
*,
email: str = "",
account_password: str = "",
mail_password: str = "",
mail_token: str = "",
name: str = "",
birthdate: str = "",
oauth_status: str = "oauth=failed",
failure_step: str = "",
error_message: str = "",
) -> str:
payload = {
"email": str(email or "").strip(),
"account_password": str(account_password or "").strip(),
"mail_password": str(mail_password or "").strip(),
"mail_token": str(mail_token or "").strip(),
"name": str(name or "").strip(),
"birthdate": str(birthdate or "").strip(),
"oauth_status": str(oauth_status or "oauth=failed").strip() or "oauth=failed",
}
if failure_step:
payload["failure_step"] = str(failure_step).strip()
if error_message:
payload["error_message"] = str(error_message).strip()
return json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
def _write_text_atomic(file_path: str, content: str) -> None:
directory = os.path.dirname(file_path) or "."
os.makedirs(directory, exist_ok=True)
@@ -896,6 +924,19 @@ def run(
mail_provider=None,
proxy_pool_config: Optional[Dict[str, Any]] = None,
) -> Optional[str]:
def _failure_result(step: str, error_message: str = "") -> str:
return _build_registration_failure_result(
email=locals().get("email", ""),
account_password=locals().get("account_password", ""),
mail_password=locals().get("mailbox_password", ""),
mail_token=locals().get("mailbox_token", ""),
name=locals().get("_rand_name", ""),
birthdate=locals().get("_rand_bday", ""),
oauth_status="oauth=failed",
failure_step=step,
error_message=error_message,
)
static_proxy = _normalize_proxy_value(proxy)
static_proxies: Any = _to_proxies_dict(static_proxy)
@@ -1325,12 +1366,12 @@ def run(
emitter.info(f"当前出口 IP: {current_ip}", step="check_proxy")
if loc == "CN" or loc == "HK":
emitter.error("检查代理哦 — 所在地不支持 (CN/HK)", step="check_proxy")
return None
return _failure_result("check_proxy", "所在地不支持 (CN/HK)")
emitter.success("网络环境检查通过", step="check_proxy")
_ensure_openai_relay_ready()
except Exception as e:
emitter.error(f"网络连接检查失败: {e}", step="check_proxy")
return None
return _failure_result("check_proxy", f"网络连接检查失败: {e}")
if _stopped():
return None
@@ -1360,7 +1401,7 @@ def run(
mailbox_token = str(dev_token or "").strip()
if not email or not dev_token:
emitter.error("临时邮箱创建失败", step="create_email")
return None
return _failure_result("create_email", "临时邮箱创建失败")
emitter.success(f"临时邮箱创建成功: {email}", step="create_email")
# 生成随机密码(密码注册流程需要)
@@ -1389,7 +1430,7 @@ def run(
csrf_token = ""
if not csrf_token:
emitter.error("获取 CSRF Token 失败", step="oauth_init")
return None
return _failure_result("oauth_init", "获取 CSRF Token 失败")
# 3c: 生成 Device ID
did = s.cookies.get("oai-did") or relay_cookie_jar.get("oai-did") or ""
@@ -1437,7 +1478,7 @@ def run(
f"Signin 获取授权链接失败({signin_resp.status_code}: {str(signin_resp.text or '')[:220]}",
step="oauth_init",
)
return None
return _failure_result("oauth_init", f"Signin 获取授权链接失败({signin_resp.status_code}")
emitter.info(f"OAuth 初始化状态: {signin_resp.status_code}", step="oauth_init")
# 3e: 跟随 authorize 重定向,建立 auth.openai.com 会话
@@ -1478,7 +1519,7 @@ def run(
f"注册表单提交失败(状态码 {signup_resp.status_code}: {str(signup_resp.text or '')[:220]}",
step="signup",
)
return None
return _failure_result("signup", f"注册表单提交失败(状态码 {signup_resp.status_code}")
# ------- 步骤6发送 OTP 验证码 -------
time.sleep(random.uniform(0.3, 0.8))
@@ -1497,7 +1538,7 @@ def run(
if otp_resp.status_code != 200:
emitter.error(f"验证码发送失败(状态码 {otp_resp.status_code}: {str(otp_resp.text or '')[:220]}", step="send_otp")
return None
return _failure_result("send_otp", f"验证码发送失败(状态码 {otp_resp.status_code}")
if _stopped():
return None
@@ -1529,7 +1570,7 @@ def run(
proxy_selector=None,
)
if not code:
return None
return _failure_result("wait_otp", "邮箱验证码获取失败")
if _stopped():
return None
@@ -1555,7 +1596,7 @@ def run(
f"验证码校验失败(状态码 {code_resp.status_code}: {str(code_resp.text or '')[:220]}",
step="verify_otp",
)
return None
return _failure_result("verify_otp", f"验证码校验失败(状态码 {code_resp.status_code}")
if _stopped():
return None
@@ -1591,7 +1632,7 @@ def run(
if create_account_status != 200:
emitter.error(create_account_resp.text, step="create_account")
return None
return _failure_result("create_account", str(create_account_resp.text or "")[:220])
emitter.success("账户创建成功!", step="create_account")
@@ -1776,7 +1817,7 @@ def run(
emitter.info("OAuth 需要邮箱 OTP 验证...", step="get_token")
if not dev_token or mail_provider is None:
emitter.error("OAuth OTP 验证需要邮箱 token但不可用", step="get_token")
return None
return _failure_result("get_token", "OAuth OTP 验证需要邮箱 token但不可用")
_otp_ok = False
_otp_deadline = time.time() + 120
@@ -1819,7 +1860,7 @@ def run(
if not _otp_ok:
emitter.error(f"OAuth OTP 验证失败,已尝试 {len(_tried_codes)} 个验证码", step="get_token")
return None
return _failure_result("get_token", f"OAuth OTP 验证失败,已尝试 {len(_tried_codes)} 个验证码")
if _stopped():
return None
@@ -2003,7 +2044,7 @@ def run(
emitter.error("未能获取 OAuth authorization code", step="get_token")
try: s.close()
except: pass
return None
return _failure_result("get_token", "未能获取 OAuth authorization code")
# 10g: POST /oauth/token — 用 code 换取 Token
emitter.info("OAuth 5/5: 交换 Token...", step="get_token")
@@ -2023,7 +2064,7 @@ def run(
emitter.error(f"Token 交换失败({_token_resp.status_code}): {str(_token_resp.text or '')[:200]}", step="get_token")
try: s.close()
except: pass
return None
return _failure_result("get_token", f"Token 交换失败({_token_resp.status_code})")
try:
_token_json = _token_resp.json()
@@ -2046,7 +2087,7 @@ def run(
emitter.error(f"运行时发生错误: {e}", step="runtime")
try: s.close()
except: pass
return None
return _failure_result("runtime", str(e))
# ==========================================
# CLI 入口(兼容直接运行)