fix: continue daemon refill after registration failures
This commit is contained in:
@@ -432,6 +432,11 @@ ocxxxxxxx@cursors.online
|
||||
|
||||
拿到什么就写什么,缺失字段会写空值或 `NULL`。
|
||||
|
||||
现在成功和失败都会尽量入库:
|
||||
|
||||
- 成功时:`oauth_status = oauth=ok`
|
||||
- 失败时:`oauth_status = oauth=failed`
|
||||
|
||||
关于 `auto_register_max_per_loop`:
|
||||
|
||||
- `0`:按当前差值动态补齐
|
||||
|
||||
@@ -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
45
main.py
@@ -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)):
|
||||
|
||||
@@ -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 入口(兼容直接运行)
|
||||
|
||||
Reference in New Issue
Block a user