optimize: WeChat QR code auth flow and channel reliability

- Generate QR code server-side when iLink API returns SPA page URL
  (added qrcode + image crates for PNG generation)
- Strip bot_token from frontend response (new WeixinQrcodeStatusPublic type)
- Add request timeouts and shared HTTP client for QR code endpoints
- Fix TOCTOU race on reply_context double-lock (single lock scope)
- Extract do_send() helper to deduplicate sendmessage logic; resend now
  checks ret field for context expiry instead of HTTP status only
- Cap pending_messages buffer at 50 to prevent unbounded memory growth
- Generate stable X-WECHAT-UIN per backend instance instead of per request
- Extract ILINK_CHANNEL_VERSION constant (was hardcoded in 4 places)
- Add 5-minute client-side QR expiry timeout in frontend dialog
- Track consecutive polling errors and show warning after 3 failures
- Stabilise onAuthSuccess/onClose callback refs to prevent polling restarts
- Replace dead i18n key weixinOpenQrcode with weixinPollError

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
xintaofei
2026-04-02 11:22:51 +08:00
parent 0ef36ee918
commit d0e0aad525
17 changed files with 379 additions and 207 deletions

View File

@@ -6,7 +6,7 @@ use serde::Deserialize;
use crate::app_error::AppCommandError;
use crate::app_state::AppState;
use crate::commands::chat_channel as cc_commands;
use crate::chat_channel::backends::weixin::{WeixinQrcodeInfo, WeixinQrcodeStatus};
use crate::chat_channel::backends::weixin::{WeixinQrcodeInfo, WeixinQrcodeStatusPublic};
use crate::models::chat_channel::{ChannelStatusInfo, ChatChannelInfo, ChatChannelMessageLogInfo};
// ---------------------------------------------------------------------------
@@ -268,7 +268,7 @@ pub struct WeixinCheckQrcodeParams {
pub async fn weixin_check_qrcode(
Extension(state): Extension<Arc<AppState>>,
Json(params): Json<WeixinCheckQrcodeParams>,
) -> Result<Json<WeixinQrcodeStatus>, AppCommandError> {
) -> Result<Json<WeixinQrcodeStatusPublic>, AppCommandError> {
let result =
cc_commands::weixin_check_qrcode_core(&state.db, params.channel_id, &params.qrcode)
.await?;