# TG Forwarder 排查+修复: 硬编码黑名单误杀 + chat_id 提取 bug + 频道切换 (2026-09-22 ~ 2026-09-24) ## 症状 用户报"监听频道要更新 / 现在交易信号都没转发了吗" → 排查发现 forwarder 一直在跑, 但日志显示: ``` [用户] 消息命中硬编码黑名单, 跳过转发 最终决定: 不转发 或 Got difference for channel 2651333064 updates (但 0 处理规则/消息内容日志) ``` ## 根因 1: 硬编码黑名单误杀 (2026-09-22) `/app/handlers/user_handler.py` 的 `HARD_BLACKLIST_PATTERNS` 含 `r'(?i)usdt|cny|套现'` 和裸 `带单|指导|喊单|牛牛老师`、`\bVIP\b|\b老师\b`。 **所有信号都带 USDT** (【币种】:BTCUSDT 永续) → 每条都命中 → 信号时有时无。 修复 (收窄正则): ```python # 修复前 (误杀) r'(?i)usdt|cny|套现', r'(?i)带单|指导|喊单|牛牛老师', r'(?i)\bVIP\b|\b老师\b', # 修复后 r'(?i)(usdt|cny)(?!永续|usdt).{0,4}套现|套现', r'(?i)牛牛老师|喊单指导', r'(?i)\bVIP群\b|付费指导', ``` 改完必须 `docker restart telegram-forwarder`。 ## 根因 2: chat_id 提取 bug (2026-09-24) 切换 source 到新频道 @shipan_jiankong 后, forwarder 收到 `Got difference for channel 2651333064 updates` (每15分钟轮询一次), 但**完全没"消息内容/处理规则"日志**。 `/app/message_listener.py` line 75-76: ```python chat = await event.get_chat() chat_id = abs(chat.id) # 错! 剥掉了 -100 前缀 ``` 实际 telethon: - `event.chat.id` = 正数 `2651333064` (Channel 对象剥了 -100) - `event.chat_id` = 完整 `-1002651333064` ← 正确 DB 存 `Chat.telegram_chat_id == '-1002651333064'` 字符串, `str(2651333064)` 永远匹配不上 → Chat 查询 None → 早 return → 无日志。 后续 `int(f"100{chat_id}")` 二次覆盖更错 (应是 `-100{...}`), 但只在 `state_manager.check_state()` 为真时触发。 修复: ```python chat = await event.get_chat() chat_id = event.chat_id # 用完整 -100xxxxxxxxxx ``` 同时 Chat 查询加防御, 兼容两种格式 (防御性, 防止 chat_id 来源不一致时再次错): ```python _chat_id_str = str(chat_id) if abs(chat_id) > 1e10 and not _chat_id_str.startswith('-100'): _alt_id_str = f'-100{abs(chat_id) - 1e12}' if abs(chat_id) > 1e12 else f'-100{_chat_id_str}' else: _alt_id_str = f'100{_chat_id_str.lstrip("-")}' source_chat = session.query(Chat).filter( Chat.telegram_chat_id.in_([_chat_id_str, _alt_id_str, f'-100{_chat_id_str.lstrip("100")}']) ).first() ``` 修改后必须 `docker restart telegram-forwarder`。 ## 双频道区分 (易混, 别再装错) | 频道 | chat_id | 标题 | 当前状态 | |---|---|---|---| | **@shipan_jiankong** | -1002651333064 | 币圈实盘监控 \| 熬鹰 风寻 | ✅ **当前 source** (chats.id=4) | | @jiankongshipan | 3805472665 | 实盘监控 | ❌ 已停用, 记录保留 (chats.id=1) | 频道切换 SQL: ```sql INSERT INTO chats (telegram_chat_id, name, current_add_id) VALUES ('-1002651333064', '币圈实盘监控 熬鹰 风寻', NULL); UPDATE forward_rules SET source_chat_id = (SELECT id FROM chats WHERE telegram_chat_id='-1002651333064') WHERE id=1; ``` ## 双白名单 AND 校验 (v4.5.4, 未动) 消息必须同时含交易员关键词 (麻吉/魏神/熬鹰/风寻/狙击手/百发百胜) + 信号类型 (开仓/平仓/加仓/减仓) 才转发。 ## 排查手法 (套路) - 规则库: 容器内 `python3 -c "import sqlite3; ..."` 读 `/app/db/forward.db` (chats/forward_rules/keywords 表) - session 被主进程锁 → `cp /app/sessions/user.session /tmp/xx.session` 再连 - 容器内连 TG 必带 `proxy=('socks5','127.0.0.1',7891)`, `request_retries=1` + timeout 防挂 - 容器内无 sqlite3 CLI, 用 python sqlite3 模块 - 验证消息实体存在: `async for m in c.iter_messages(username, limit=10)` - 验证 chat.id vs chat_id 区别: `print(event.chat.id, event.chat_id)` - 区分 telethon.channel.get_difference (轮询 update) vs message.NewMessage (新消息事件) - 复现信号让用户从实际频道发一条, 看 docker logs --since 1m | grep 处理规则 是否命中