This commit is contained in:
Your Name
2026-07-28 09:00:19 +08:00
parent 8ba13a8ff9
commit 153db97dc7
14 changed files with 793 additions and 75 deletions
+27 -15
View File
@@ -6,7 +6,6 @@ from typing import Optional
from rpa_engine.douyin_im.auth import DouyinAuth
from rpa_engine.douyin_im.frontier import ensure_frontier_ws
from rpa_engine.douyin_im.http_client import DouyinImHttpClient
from rpa_engine.douyin_im.session import DouyinImSession
from utils.cookie_store import analyze_cookie
@@ -131,13 +130,26 @@ async def build_cookie_credential_detail(
async def validate_im_session(
session: DouyinImSession,
_bypass_global_limit: bool = False,
*,
startup_priority: bool = False,
) -> tuple[bool, str]:
if not _bypass_global_limit:
from rpa_engine.douyin_im.traffic_control import get_traffic_controller
controller = get_traffic_controller()
async with controller.background_slot(0, "credential validation"):
return await validate_im_session(session, _bypass_global_limit=True)
# Startup validation must not sit behind hundreds of recurring
# conversation polls. It still shares the same global concurrency
# cap, so this changes ordering without increasing bandwidth usage.
async with controller.background_slot(
0,
"credential validation",
startup=startup_priority,
):
return await validate_im_session(
session,
_bypass_global_limit=True,
startup_priority=startup_priority,
)
if not session.can_direct_im():
if not has_im_session_token(session):
@@ -155,17 +167,12 @@ async def validate_im_session(
if not auth.is_sign_ready():
return False, "缺少 IM 签名密钥(web_protect/keys),请用浏览器登录补全"
session.my_uid = int(uid)
async with DouyinImHttpClient(session) as http:
await http.get_unread_count()
# 若已缓存到会话票据,优先校验其是否仍新鲜(最理想)。
if session.conv_meta:
ok, reason = await http.verify_messaging_capability(auth, session.my_uid)
if ok:
return True, reason
# 没有缓存会话票据是首次登录的正常情况:会话 ticket 会在发送时即时
# 创建/获取(resolve_conversation_meta),因此只要 Cookie + sessionid +
# 签名密钥(web_protect/keys) + UID 齐全,就视为可 IM 直连托管,不必再开浏览器。
return True, "IM 凭证就绪(Cookie 与签名密钥齐全,可直连托管)"
# unread_count and ticket probes were previously issued here, but
# neither result changed the final decision: unread failures become
# zero and a stale/missing ticket is resolved lazily at send time.
# Keeping those probes doubled large-batch startup traffic without
# adding an authoritative validation signal.
return True, "IM 凭证就绪(Cookie 与签名密钥齐全,可直连托管)"
except Exception as e:
logger.warning(f"IM session validation failed: {e}")
return False, f"IM 运行时验证失败: {e}"
@@ -174,6 +181,8 @@ async def validate_im_session(
async def assess_account_credential(
cookie_data: Optional[str],
im_session_data: Optional[str] = None,
*,
startup_priority: bool = False,
) -> dict:
cookie_info = analyze_cookie(cookie_data)
result = {
@@ -212,7 +221,10 @@ async def assess_account_credential(
result["should_reset"] = _should_reset_credentials(result)
return result
im_ok, im_reason = await validate_im_session(session)
im_ok, im_reason = await validate_im_session(
session,
startup_priority=startup_priority,
)
result["im_ready"] = im_ok
if im_ok:
result["can_skip_browser"] = True