fix: 修复短时间大量消息丢失问题

旧逻辑用 `if ts == prev_ts: continue` 粗暴跳过上轮时间戳的所有消息,
但同一秒内可能有多条不同消息(如连续转发公众号文章),导致只显示
最后一条,其余丢失。

改为用 (username, timestamp, msg_type) 精确去重:
- 主消息和 hidden 消息显示后都记录到 _shown_keys
- 过滤时精确匹配已显示的消息,不再按时间戳整体跳过
- _shown_keys 每轮清理过期条目(保留 5 分钟),防止内存泄漏

Fixes #20

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat/daemon-cli
ylytdeng 2026-03-09 19:52:46 +08:00
parent 64b2c9fdef
commit 030680eb85
1 changed files with 10 additions and 5 deletions

View File

@ -540,6 +540,8 @@ class SessionMonitor:
self.prev_state = {}
self.decrypt_ms = 0
self.patched_pages = 0
# 已显示消息去重: {(username, timestamp, base_msg_type), ...}
self._shown_keys = set()
def resolve_image(self, username, timestamp):
"""解密图片: username+timestamp → 解密后的图片文件名,失败返回 None"""
@ -860,11 +862,8 @@ class SessionMonitor:
hidden_msgs = []
for ts, lt, mc, ct in all_rows:
base = lt % 4294967296 if lt > 4294967296 else lt
# 跳过与 session 当前消息相同时间戳+类型的(已显示)
if ts == curr_ts and base == curr_msg_type:
continue
# 跳过 prev_ts 的消息(上一轮已显示)
if ts == prev_ts:
# 跳过已显示的消息(精确匹配 username+timestamp+type
if (username, ts, base) in self._shown_keys:
continue
# 解压 zstd
if isinstance(mc, bytes) and ct == 4:
@ -883,6 +882,7 @@ class SessionMonitor:
global messages_log
for ts, base, mc in hidden_msgs:
self._shown_keys.add((username, ts, base))
msg_data = {
'time': datetime.fromtimestamp(ts).strftime('%H:%M:%S'),
'timestamp': ts,
@ -1303,6 +1303,7 @@ class SessionMonitor:
}
new_msgs.append(msg_data)
self._shown_keys.add((username, curr['timestamp'], curr['msg_type']))
# 图片消息: 后台异步解密(不阻塞轮询)
if curr['msg_type'] == 3:
@ -1353,6 +1354,10 @@ class SessionMonitor:
self.prev_state = curr_state
# 清理过期的去重 key保留最近 5 分钟)
cutoff = int(time.time()) - 300
self._shown_keys = {k for k in self._shown_keys if k[1] > cutoff}
def monitor_thread(enc_key, session_db, contact_names, db_cache=None, username_db_map=None):
mon = SessionMonitor(enc_key, session_db, contact_names, db_cache, username_db_map)
wal_path = mon.wal_path