fix: @提及昵称+正文拼凑吞消息+GUI冻结(主线程sleep)
问题1: '@咱想了解一下咱那个登录插件去哪儿下载?' 只剩'?'
- 根因: _at_user_pattern贪婪吞18字符当username, rest='?'
- is_clean_at=False只拦了入库, 但ts已被覆盖成rest('?')→整条问句丢失
- 修复: 不干净时仅剥@保留全部正文(宁留脏昵称不吞消息)
问题2: 跟踪日志时GUI冻结必须ctrl+c
- 根因: _execute_reply跑在Tk主线程, _paste_and_send失败后
time.sleep(5)×3次=主线程冻结15秒(QQ窗不前置时必失败)
- 修复: after()异步重试+data['_attempt']计数, 主线程不阻塞
This commit is contained in:
@@ -1145,6 +1145,7 @@ class MsgBotApp(ctk.CTk):
|
||||
msg = data.get("msg", "")
|
||||
max_retries = 3
|
||||
retry_delay = 5 # 秒
|
||||
attempt = data.get("_attempt", 0) # ⭐ 主线程异步重试计数(不阻塞GUI)
|
||||
|
||||
# ⭐ 发送前强制检查时间戳:≤300秒则发送,≥300秒则丢弃
|
||||
msg_age = self._check_message_freshness(msg)
|
||||
@@ -1161,8 +1162,6 @@ class MsgBotApp(ctk.CTk):
|
||||
if not found:
|
||||
self._log(f"[{platform}] ⚠ 找不到联系人 {sender},当前会话回复")
|
||||
|
||||
# 带重试的发送逻辑
|
||||
for attempt in range(max_retries):
|
||||
# 首次正常发送,重试时 force_retry 跳过60秒冷却
|
||||
ok = self.monitor._paste_and_send(platform, answer, force_retry=(attempt > 0))
|
||||
if ok:
|
||||
@@ -1171,7 +1170,11 @@ class MsgBotApp(ctk.CTk):
|
||||
else:
|
||||
if attempt < max_retries - 1:
|
||||
self._log(f"[{platform}] ⚠ 自动回复发送失败,{retry_delay}秒后重试({attempt+1}/{max_retries})")
|
||||
time.sleep(retry_delay)
|
||||
# ⭐ 2026-08-17 修复GUI冻结:原实现主线程 time.sleep(5) ×3 = 界面冻结15秒+
|
||||
# 窗口不前置时 _paste_and_send 必失败,用户跟踪日志时 GUI 无响应。
|
||||
# 改为 after() 异步重试:主线程立即返回,5秒后再执行,界面保持流畅。
|
||||
data["_attempt"] = attempt + 1
|
||||
self.after(int(retry_delay * 1000), lambda d=data: self._execute_reply(d))
|
||||
else:
|
||||
self._log(f"[{platform}] ⚠ 自动回复发送失败(连续{max_retries}次),用户可能在接管,本轮跳过")
|
||||
finally:
|
||||
|
||||
+13
-4
@@ -4966,7 +4966,6 @@ class MessageMonitor:
|
||||
if m_at:
|
||||
username = m_at.group(1)
|
||||
rest = ts[m_at.end():]
|
||||
ts = rest.lstrip()
|
||||
# ⭐ Task #1508: 自动入库前校验,防「昵称+正文」整段被当昵称入库。
|
||||
# 典型污染例子:"@游戏专用PHP有哪两种登录模式?" → 正则贪婪吞掉
|
||||
# "游戏专用PHP有哪两种登录模式" 整段入库,导致后续匹配时正确正文
|
||||
@@ -4975,7 +4974,10 @@ class MessageMonitor:
|
||||
# ② 长度≤12(QQ昵称常见上限,超出多半是昵称+正文拼凑)才入库。
|
||||
rest_head = rest[:1] if rest else ''
|
||||
is_clean_at = (len(username) <= 12) and (not rest_head or rest_head in ' \t,,。.!!??;;::\n')
|
||||
if is_clean_at and username not in nicknames:
|
||||
if is_clean_at:
|
||||
# 干净@提及:剥掉昵称,保留 rest
|
||||
ts = rest.lstrip()
|
||||
if username not in nicknames:
|
||||
nicknames.append(username)
|
||||
try:
|
||||
from config import load_config, save_config
|
||||
@@ -4985,8 +4987,15 @@ class MessageMonitor:
|
||||
logger.info(f"[qq] 自动入库@提及昵称: {username}")
|
||||
except Exception as e:
|
||||
logger.warning(f"[qq] 自动入库昵称失败: {e}")
|
||||
elif username not in nicknames:
|
||||
logger.debug(f"[qq] 跳过自动入库(疑似昵称+正文拼凑): {username!r}, rest={rest_head!r}")
|
||||
else:
|
||||
# ⭐ 2026-08-17 修复:疑似「昵称+正文」拼凑时**保留正文**!
|
||||
# 原先 ts=rest.lstrip() 会把正文整段吞掉:
|
||||
# "@咱想了解一下咱那个登录插件去哪儿下载?" → username=18字符,
|
||||
# rest='?' → ts='?' 只剩问号 → 整条问句丢失。
|
||||
# 未知昵称+正文粘连无法可靠切分,宁可保留所有字符(只剥@),
|
||||
# 让 KB 用正文匹配;脏文本进查询的代价 << 消息全部丢失。
|
||||
ts = ts[1:].lstrip()
|
||||
logger.debug(f"[qq] @提及疑似昵称+正文拼凑,保留正文: ts={ts[:40]!r} username={username!r} rest={rest_head!r}")
|
||||
else:
|
||||
# 无法识别用户名,只剥离@符号
|
||||
ts = ts[1:].lstrip()
|
||||
|
||||
Reference in New Issue
Block a user