Skip to content

Latest commit

 

History

59 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go Telegram Forwarder Bot

一个功能完整的 Telegram Bot 系统,用于在不同用户和群组之间转发消息,支持管理多个转发 Bot 并提供详细的数据统计功能。

✨ 功能特性

核心功能

  • 双层架构:ManagerBot 管理多个 ForwarderBot,ForwarderBot 执行实际的消息转发
  • 双向转发:Guest → Recipients(入向),Recipients → Guest(出向)
  • 双向回复:支持 Guest 和 Recipient 互相回复消息,实现完整的对话流程
  • 多级权限:Superuser、Manager、Admin、Guest 四级权限体系
  • 黑名单管理:支持审批流程,多 Manager/Admin 协同审批,自动过期处理
  • 实时统计:消息转发量、用户数等实时统计
  • 错误处理:自动重试、失败通知、关键错误告警

高级特性

  • 动态 Bot 管理:支持运行时动态启动/停止 ForwarderBot,无需重启应用
  • 限流保护:Telegram API 限流(25条/秒)和 Guest 消息限流(1条/秒)
  • 重试机制:网络错误、429、5xx 自动重试(最多10次,间隔30秒)
  • 群组监控:自动检测无效群组并清理
  • Token 加密:Bot Token 使用 AES-256 加密存储
  • 审计日志:关键操作永久记录
  • Redis 支持:可选 Redis 用于限流和缓存
  • Proxy 支持:支持 HTTP/HTTPS/SOCKS5 代理,适用于无法直接访问 Telegram API 的网络环境
  • Markdown 安全:自动转义用户输入中的 Markdown 特殊字符,防止格式错误
  • 详细日志:完整的 debug 级别日志,记录所有操作和状态变化
  • 消息映射:完整记录所有消息的映射关系,支持复杂的双向对话场景
  • 智能黑名单:正确处理 ban/unban 组合,确保黑名单状态准确
  • 广告拦截:可配置的广告拦截功能,自动拦截包含 @用户名、链接、按钮或通过其他 Bot 发送的消息,以及外部回复消息引用内容中的广告,防止广告骚扰
  • LLM 广告拦截(可选二级):在规则拦截之后接入 LLM(Claude / OpenAI 兼容),识别绕过规则的纯文本广告(VPN、频道买卖、虚拟货币推广等)。按 Guest 时间窗合并多条消息一并判断,捕捉拆分发送的广告。仅 Superuser 可针对单个 ForwarderBot 开启,由 Superuser 在 /manage 菜单中手动控制;失败时 fail-open(按正常消息转发)。

🏗️ 系统架构

架构图

┌─────────────────────────────────────────┐
│         ManagerBot (管理 Bot)           │
│  - 管理多个 ForwarderBot                │
│  - 用户权限管理                          │
│  - 全局统计                              │
└─────────────────────────────────────────┘
              │
              │ 管理
              ▼
┌─────────────────────────────────────────┐
│      ForwarderBot 1, 2, 3... (转发 Bot) │
│  - 执行实际的消息转发                    │
│  - 管理 Recipients                      │
│  - 黑名单管理                            │
│  - Bot 级别统计                          │
└─────────────────────────────────────────┘

角色体系

ManagerBot 层:

  • Superuser:系统超级管理员(配置文件指定)
  • Manager:ForwarderBot 的拥有者

ForwarderBot 层:

  • Manager:Bot 拥有者
  • Admin:管理员(由 Manager 添加)
  • Guest:发送消息的普通用户
  • Recipient:接收消息的目标(用户或群组)

📦 技术栈

  • Go 1.23+
  • gotgbot/v2:Telegram Bot API 客户端
  • GORM:数据库 ORM(支持 SQLite、MySQL、PostgreSQL)
  • Viper:配置管理
  • Zap:结构化日志
  • go-redis:Redis 客户端(可选)
  • UUID:唯一标识符

🚀 快速开始

前置要求

  • Go 1.23 或更高版本
  • Telegram Bot Token(从 @BotFather 获取)
  • (可选)Redis 服务器

安装步骤

  1. 克隆项目
git clone https://github.com/Liki4/go-telegram-forwarder-bot
cd go-telegram-forwarder-bot
  1. 安装依赖
go mod tidy
  1. 配置项目
cp configs/config.yaml.example configs/config.yaml
  1. 编辑配置文件 编辑 configs/config.yaml,至少需要配置:
  • manager_bot.token:ManagerBot 的 Token
  • manager_bot.superusers:Superuser 的 Telegram User ID 列表
  • encryption_key:加密密钥(见下方说明)
  1. 生成加密密钥(重要!)
openssl rand -base64 32

将生成的密钥填入配置文件的 encryption_key 字段。

⚠️ 注意:生产环境必须配置加密密钥,否则无法解密已存储的 Bot Token。

  1. 构建项目
go build ./cmd/bot
  1. 运行
./bot

⚙️ 配置说明

完整的配置示例请参考 configs/config.yaml.example。

Proxy 配置

当网络无法直接访问 Telegram API 时,可以配置代理:

proxy:
  enabled: true
  url: "http://127.0.0.1:7890"  # 代理地址
  username: ""                  # 可选:代理认证用户名
  password: ""                   # 可选:代理认证密码

支持的代理类型:

  • HTTP/HTTPS 代理:http://127.0.0.1:7890
  • SOCKS5 代理:socks5://127.0.0.1:1080
  • 带认证的代理:http://user:pass@proxy.example.com:8080

说明:

  • 启用代理后,所有 Telegram API 请求(包括 ManagerBot 和所有 ForwarderBot)都会通过代理
  • 代理配置会在启动时验证,如果配置错误会立即报错
  • 建议在生产环境使用稳定的代理服务

必需配置

manager_bot:
  token: "YOUR_MANAGER_BOT_TOKEN"      # ManagerBot Token
  superusers: [123456789, 987654321]   # Superuser User ID 列表

encryption_key: "base64_encoded_32_byte_key"  # 加密密钥(必需)

可选配置

database:
  type: "sqlite"          # sqlite, mysql, postgres
  dsn: "bot.db"           # 数据库连接字符串

redis:
  enabled: false          # 是否启用 Redis
  address: "localhost:6379"
  password: ""
  db: 0

rate_limit:
  telegram_api: 25        # Telegram API 限流(条/秒)
  guest_message: 1        # Guest 消息限流(条/秒)

retry:
  max_attempts: 10        # 最大重试次数
  interval_seconds: 30    # 重试间隔(秒)

log:
  level: "debug"          # debug, info, warn, error
  output: "stdout"        # stdout, file, both (both = 同时输出到控制台和文件)
  file_path: "bot.log"    # 日志文件路径(当 output 为 file 或 both 时必需)

environment: "development"  # development, production

proxy:
  enabled: false          # 是否启用代理
  url: ""                # 代理地址,如 "http://127.0.0.1:7890" 或 "socks5://127.0.0.1:1080"
  username: ""           # 代理认证用户名(可选)
  password: ""            # 代理认证密码(可选)

ad_filter:
  enabled: false          # 是否启用广告拦截(拦截包含 @用户名、链接、按钮或通过其他 Bot 发送的消息)

# 可选:LLM 二级广告拦截。规则拦截通过后接入 LLM 判定纯文本广告。
# 全局配置 provider/api_key/model;具体哪些 ForwarderBot 启用由 Superuser
# 在 /manage 菜单里逐个开关(默认全部关闭)。失败 fail-open。
# llm_ad_filter:
#   provider: "anthropic"          # "anthropic" 或 "openai"(兼容 gpt-*、vLLM、ollama、OpenRouter 等)
#   api_key: "sk-ant-..."
#   model: "claude-opus-4-8"       # 成本敏感场景可用 "claude-haiku-4-5-20251001"
#   base_url: ""                   # 可选;用于 OpenAI 兼容端点
#   timeout_seconds: 10            # 每次请求超时;默认 10
#   max_text_chars: 500            # 送 LLM 之前截断长度;默认 500
#   batch_window_seconds: 5        # 同一 Guest 消息合并窗口;默认 5 秒

📖 使用指南

ManagerBot 命令

/addbot <token>

添加新的 ForwarderBot。

示例:

/addbot 123456789:ABCdefGHIjklMNOpqrsTUVwxyz

说明:

  • 执行命令的用户将成为该 Bot 的 Manager
  • Token 会通过 Telegram API 验证
  • Token 会加密存储
  • Bot 添加成功后会自动启动,无需重启应用
  • Manager 会自动添加为该 Bot 的第一个 Recipient

/mybots

列出当前 Manager 管理的所有 ForwarderBot。

功能:

  • 显示 Bot 列表
  • 点击 Bot 可查看详细信息
  • 支持删除 Bot(需确认)

/manage(Superuser 专用)

打开管理界面。

功能:

  • 查看所有 Manager(点击可查看 Manager 详情及其管理的所有 Bots)
  • 查看所有 ForwarderBot(点击可查看 Bot 详细信息)
  • 查看 Manager 详情(包括统计信息和 Bot 列表)
  • 查看 Bot 详细信息(包括统计信息)
  • 删除 Bot(需确认,删除后立即停止)
  • 所有页面都有 Back 按钮,支持完整导航

/stats(Superuser 专用)

查看全局统计信息。

统计内容:

  • Manager 数量
  • ForwarderBot 数量
  • 总转发消息量(入向/出向)
  • 总 Guest 数量

/help

显示帮助信息,列出所有可用命令。

说明:

  • 根据用户角色(Superuser/Manager/Guest)显示相应的命令列表
  • ManagerBot 和 ForwarderBot 都有独立的帮助信息

ForwarderBot 命令

/addrecipient <chat_id>

添加 Recipient(接收者)。

示例:

/addrecipient -1001234567890

说明:

  • chat_id 可以是用户 ID 或群组 ID
  • 群组 ID 通常为负数
  • 不需要验证,直接添加

/delrecipient <chat_id>

删除 Recipient。

/listrecipient

列出所有 Recipient。

/addadmin <user_id>

添加 Admin。

示例:

/addadmin 123456789

说明:

  • Admin 拥有除添加/删除 Admin 外的所有 Manager 权限

/deladmin <user_id>

删除 Admin。

/listadmins

列出所有 Admin。

/stats

查看该 Bot 的统计信息。

统计内容:

  • 入向消息量(Guest → Recipients)
  • 出向消息量(Recipients → Guest)
  • Guest 数量

/help

显示帮助信息,列出所有可用命令。

说明:

  • 根据用户角色(Manager/Admin/Recipient/Guest)显示相应的命令列表
  • 纯 Guest(既不是 Manager/Admin,也不是 Recipient)只显示 /help 和 /unban 命令,不显示 /ban 命令

/ban(需 Reply)

将 Guest 加入黑名单。

使用方式:

  1. Reply 一条 Guest 发送的消息(在 Recipient 端)
  2. 发送 /ban 命令
  3. Manager 和所有 Admin 会收到审批请求
  4. 任意 Manager 或 Admin 点击 Approve/Reject 按钮
  5. 所有收到审批请求的用户都会看到审批结果

说明:

  • 如果 Recipient 是用户,该用户可以使用 /ban
  • 如果 Recipient 是群组,群组中所有用户都可以使用 /ban
  • 审批请求会发送给 Manager 和所有 Admin
  • 点击 Approve/Reject 后,执行操作的人会看到 "Approved"/"Rejected" 按钮,其他人会看到 "Approved by {执行者}"/"Rejected by {执行者}" 按钮
  • 审批超时 1 天后自动通过
  • Ban 请求在 Pending 状态即生效,无需等待审批

/unban

将 Guest 移出黑名单。

使用方式(两种):

方式 1:管理员/Recipient 操作(需 Reply)

  1. Reply 一条被 ban 的 Guest 的消息(在 Recipient 端)
  2. 发送 /unban 命令
  3. Manager 和所有 Admin 会收到审批请求
  4. 任意 Manager 或 Admin 点击 Approve/Reject 按钮

方式 2:Guest 自请求(无需 Reply)

  1. 被 ban 的 Guest 直接发送 /unban 命令(无需 reply)
  2. Manager 和所有 Admin 会收到自请求审批通知
  3. 审批超时 1 天后自动通过

说明:

  • 审批请求会发送给 Manager 和所有 Admin
  • 点击 Approve/Reject 后,所有收到审批请求的用户都会看到审批结果
  • 审批超时 1 天后自动通过

审批流程说明

审批请求发送:

  • Ban/Unban 请求会同时发送给 Manager 和所有 Admin
  • 每个用户都会收到独立的审批消息,包含 Approve 和 Reject 按钮

审批结果展示:

  • 执行操作的用户:消息会更新为只显示 "Approved" 或 "Rejected" 按钮
  • 其他收到审批请求的用户:消息会更新为显示 "Approved by {执行者用户名}" 或 "Rejected by {执行者用户名}" 按钮
  • 执行者信息优先显示用户名(如果有),否则显示用户 ID

审批状态:

  • Ban 请求在 Pending 状态即生效,无需等待审批
  • Unban 请求需要 Approved 状态才生效
  • 系统会正确处理 ban/unban 组合,确保状态准确

🔄 消息转发流程

Guest 发送消息

Guest 发送消息
    ↓
ForwarderBot 接收
    ↓
检查黑名单 → 如果在黑名单,丢弃
    ↓
检查广告内容(如果启用) → 如果包含 @用户名、链接、按钮或通过其他 Bot 发送,或外部回复的引用内容包含广告,拦截并通知用户
    ↓
LLM 广告拦截(如果该 Bot 由 Superuser 开启) → 加入时间窗 buffer,窗口到期后合并判断;判为广告则丢弃整批并通知,否则在 batcher goroutine 中转发
    ↓
检查限流 → 如果超限,延迟发送
    ↓
并发转发给所有 Recipients
    ├─→ Recipient 1 (goroutine)
    ├─→ Recipient 2 (goroutine)
    └─→ Recipient 3 (goroutine)
    ↓
每个转发:
    ├─→ 检查 Telegram API 限流
    ├─→ 执行转发(带重试)
    ├─→ 存储消息映射
    └─→ 记录错误(如失败)

Recipient 回复消息

Recipient 回复消息
    ↓
ForwarderBot 接收
    ↓
查找消息映射(通过 recipient_message_id)
    ↓
找到对应的 guest_chat_id 和 guest_message_id
    ↓
转发回复给 Guest
    ↓
存储回复映射(记录 bot 发送给 guest 的消息 ID)

Guest 回复消息

Guest 回复消息
    ↓
ForwarderBot 接收
    ↓
检查黑名单 → 如果在黑名单,丢弃
    ↓
查找消息映射(通过 guest_message_id)
    ↓
找到所有对应的 recipient_chat_id
    ↓
并发转发给所有对应的 Recipients
    ├─→ Recipient 1 (goroutine)
    ├─→ Recipient 2 (goroutine)
    └─→ Recipient 3 (goroutine)
    ↓
存储回复映射

说明:

  • Guest 可以回复任何收到的消息
  • 系统会找到该消息对应的所有 Recipients
  • 如果消息被转发给多个 Recipients,Guest 的回复会发送给所有这些 Recipients

广告拦截

系统支持可配置的广告拦截功能,用于防止广告骚扰。

拦截规则:

  • 检测消息中的 @用户名(mention 或 text_mention 类型的 Entity)
    • 支持纯文字消息(检查 Entities)
    • 支持媒体消息的说明文字(检查 CaptionEntities)
  • 检测消息中的链接(url 或 text_link 类型的 Entity)
    • 支持纯文字消息(检查 Entities)
    • 支持媒体消息的说明文字(检查 CaptionEntities)
  • 检测消息中的按钮(ReplyMarkup,包括内联键盘按钮和回复键盘)
  • 检测通过其他 Bot 发送的消息(ViaBot)
  • 检测外部回复消息的引用内容(ExternalReply + Quote)
    • 当消息回复来自其他聊天或论坛主题的消息时(ExternalReply 存在)
    • 检查引用文本(Quote.Text)中是否包含 @用户名 或链接
    • 优先检查 Quote.Entities(如果包含 mention/url 实体)
    • 如果 Entities 中没有,使用正则表达式精确匹配 @username 格式和 URL 格式
    • 避免误判(如邮箱地址中的 @ 不会被识别为用户名)

工作流程:

Guest 发送消息
    ↓
检查广告拦截是否启用
    ↓
如果启用,检查消息是否包含:
  - @用户名(在文字或说明中,通过 Entities/CaptionEntities 检测)
  - 链接(在文字或说明中,通过 Entities/CaptionEntities 检测)
  - 按钮(ReplyMarkup)
  - 通过其他 Bot 发送(ViaBot)
    ↓
如果消息是外部回复(ExternalReply 存在),检查引用内容(Quote)
  - 优先检查 Quote.Entities 中是否有 mention/url 实体
  - 如果 Entities 中没有,使用正则表达式检查 Quote.Text
    - 匹配 @username 格式(避免误判邮箱地址)
    - 匹配 http:// 或 https:// 开头的完整 URL
    ↓
如果包含任何一项,拦截消息并通知用户
    ↓
不转发消息

配置方式: 在配置文件中设置 ad_filter.enabled: true 即可启用。

用户通知: 当消息被拦截时,系统会向发送者发送通知,说明拦截原因:

  • 包含 @用户名:"Your message was not forwarded because it contains a mention (@username)."
  • 包含链接:"Your message was not forwarded because it contains a link (http/https)."
  • 包含按钮:"Your message was not forwarded because it contains buttons."
  • 通过其他 Bot 发送:"Your message was not forwarded because it was sent via another bot."
  • 包含多项:"Your message was not forwarded because it contains mention, link, button, via bot."(根据实际情况组合)

注意事项:

  • 广告拦截只对 Guest 发送的消息生效
  • 命令和系统消息不受广告拦截影响
  • 系统消息(如进群/离群)会被系统消息过滤器处理,不会触发广告拦截
  • 支持检测纯文字消息和带说明的媒体消息(图片、视频等)
  • 对于外部回复消息(ExternalReply),会检查引用文本(Quote.Text)中的广告内容
  • 广告检测优先使用 Telegram 的 Entity 系统(更准确),如果没有 Entity 则使用正则表达式精确匹配
  • 正则表达式匹配避免误判(如邮箱地址中的 @ 不会被识别为用户名)

LLM 广告拦截(可选二级过滤)

规则拦截只能识别带 @用户名、链接、按钮、ViaBot 这类显式特征的广告。对于纯文本广告(VPN、机场代理、频道买卖、虚拟货币推广、博彩、跑分、贷款、刷单兼职等),需要语义理解。系统支持接入 LLM 作为二级过滤层。

支持的 Provider:

  • Anthropic Claude:通过官方 Go SDK,推荐 claude-opus-4-8(最准)或 claude-haiku-4-5-20251001(更便宜,约 1/5 价格,对短文本分类完全够用)
  • OpenAI 兼容:通过 HTTP 调用 /v1/chat/completions,自动兼容 vLLM、ollama、OpenRouter、LM Studio、自建 OpenAI 兼容端点等任何标准 OpenAI 协议服务

访问控制:

  • 全局配置(API key、provider、model)放在 config.yaml 的 llm_ad_filter 块中
  • 针对单个 ForwarderBot 的启用/禁用仅 Superuser 可控,Manager 和 Admin 无权操作
  • 在 ManagerBot 的 /manage → 选择 Bot 菜单里会显示当前状态以及切换按钮
  • 默认所有 ForwarderBot 都关闭

多消息时间窗合并:

广告主常常会把广告拆成多条无害消息发出来,比如:

第 1 条:朋友们有个好东西分享
第 2 条:内容很丰富,便宜量大
第 3 条:详情看签名 / 私聊

每条单看都不像广告,只有合起来才能判定。系统按 (bot_id, guest_user_id) 维护一个时间窗 buffer(默认 5 秒),同一 Guest 在窗口内发出的所有消息会被合并、拼接、一次性送 LLM 判断。

代价: 启用 LLM 拦截的 ForwarderBot,每条消息会延迟 batch_window_seconds 秒后才转发。这是接入 LLM 必须接受的取舍——窗口越长抓得越准(捕捉更多拆分广告),延迟越大。可以在配置里调整这个值(默认 5 秒)。

工作流程:

Guest 发送消息
    ↓
(黑名单 / 规则广告 / 命令等检查通过)
    ↓
ForwarderBot 是否启用 LLM 广告拦截?(Superuser 控制)
    ↓ 是
按 (bot_id, guest_user_id) 加入 batch buffer
启动/复用 batch_window_seconds 定时器
    ↓
立即返回,HandleMessage 不阻塞
    ↓ 定时器到期
拼接 batch 内所有消息文本(用 ---  分隔)
    ↓
送 LLM 判断(带提示词:识别 VPN/虚拟货币/博彩等推广)
    ↓
NORMAL → 按顺序转发 batch 内所有消息
AD     → 丢弃 batch 内所有消息 + 给 Guest 发一条聚合通知
错误   → fail-open,按 NORMAL 处理(避免误伤)

LLM 判定结果会写入 audit log(audit_logs 表的 llm_ad_blocked 动作),包含截断后的文本、模型给出的原因、Bot ID、Guest user ID 等,便于 Superuser 复盘和调优 prompt。/manage 中切换开关本身也会写 llm_ad_filter_toggle audit log。

Proxy 支持: 两种 provider 都走项目现有的 proxy 配置,所以受限网络环境下也能用。

关机优雅退出: 收到 SIGTERM/SIGINT 时,系统会先把所有 pending 的 batch 走 fail-open 路径直接转发(不送 LLM),避免 buffer 里的消息丢失。

配置方式:

llm_ad_filter:
  provider: "anthropic"
  api_key: "sk-ant-..."
  model: "claude-opus-4-8"
  timeout_seconds: 10
  max_text_chars: 500
  batch_window_seconds: 5

配置之后还需要由 Superuser 在 ManagerBot 中针对具体的 ForwarderBot 手动启用(/manage → 选 Bot → Enable LLM Ad Filter)。

禁用方式: 把 llm_ad_filter 块整个删掉或留空(特征性的 provider/api_key/model 三个字段都为空),则全局禁用,所有 ForwarderBot 的开关都成为 no-op。

🧪 测试

运行测试

# 运行所有测试
go test ./...

# 运行特定包的测试
go test ./internal/utils/...
go test ./internal/service/message/...

# 运行测试并显示覆盖率
go test -cover ./...

测试覆盖

当前测试覆盖:

  • ✅ 加密/解密功能
  • ✅ 限流器(Telegram API 和 Guest 消息)
  • ✅ 重试机制(各种错误场景)

📁 项目结构

go-telegram-forwarder-bot/
├── cmd/
│   └── bot/
│       └── main.go                 # 应用入口
├── internal/
│   ├── bot/                        # Bot 实例管理
│   │   ├── manager_bot.go          # ManagerBot 实现
│   │   ├── forwarder_bot.go        # ForwarderBot 实现
│   │   └── manager.go              # BotManager:动态管理 ForwarderBot 生命周期
│   ├── config/                     # 配置管理
│   │   ├── config.go               # 配置结构
│   │   └── loader.go               # 配置加载
│   ├── database/                   # 数据库层
│   │   ├── connection.go           # 数据库连接
│   │   ├── migration.go            # 数据库迁移
│   │   └── redis.go                # Redis 连接
│   ├── models/                     # 数据模型(9个)
│   │   ├── user.go
│   │   ├── forwarder_bot.go
│   │   ├── recipient.go
│   │   ├── guest.go
│   │   ├── blacklist.go
│   │   ├── blacklist_approval_message.go  # 审批消息映射
│   │   ├── bot_admin.go
│   │   ├── message_mapping.go
│   │   └── audit_log.go
│   ├── repository/                 # 数据访问层(9个)
│   │   └── *_repo.go
│   ├── service/                    # 业务逻辑层
│   │   ├── manager_bot/            # ManagerBot 服务
│   │   ├── forwarder_bot/          # ForwarderBot 服务
│   │   ├── message/                # 消息处理
│   │   │   ├── forwarder.go        # 消息转发
│   │   │   ├── rate_limiter.go     # 限流
│   │   │   └── retry.go            # 重试
│   │   ├── blacklist/              # 黑名单服务
│   │   ├── statistics/             # 统计服务
│   │   ├── adfilter/               # LLM 广告分类器(Judge 接口 + Anthropic/OpenAI 实现 + 时间窗 Batcher)
│   │   ├── error_notifier.go       # 错误通知
│   │   └── group_monitor.go        # 群组监控
│   ├── logger/                     # 日志封装
│   └── utils/                      # 工具函数
│       ├── encryption.go           # Token 加密
│       ├── proxy.go                # Proxy 工具
│       └── markdown.go             # Markdown 转义工具
├── configs/                        # 配置文件
│   └── config.yaml.example
└── go.mod                          # Go 模块定义

🔒 安全特性

  1. Token 加密:Bot Token 使用 AES-256-GCM 加密存储
  2. 权限控制:多级权限体系,操作需授权,权限检查贯穿所有命令和回调
  3. 审计日志:关键操作永久记录
  4. 错误通知:关键错误自动通知 Superuser
  5. 限流保护:防止 API 滥用和消息轰炸
  6. Markdown 安全:自动转义用户输入,防止 Markdown 注入和格式错误
  7. 输入验证:所有用户输入都经过验证和清理
  8. 消息映射安全:通过消息映射准确识别用户,防止误操作
  9. 黑名单逻辑:正确处理 ban/unban 组合,确保状态准确
  10. 广告拦截:可配置的广告拦截功能,自动拦截包含 @用户名、链接、按钮或通过其他 Bot 发送的消息,防止广告骚扰
  11. LLM 广告拦截:可选的二级语义广告过滤,仅 Superuser 可针对单个 ForwarderBot 开启;判定结果与开关变更均写入审计日志

🐛 故障排除

常见问题

1. 无法解密 Token

问题:启动时提示无法解密 Token。

解决方案:

  • 确保配置文件中 encryption_key 与创建 Bot 时使用的密钥一致
  • 如果密钥丢失,需要重新添加所有 ForwarderBot

2. Redis 连接失败

问题:Redis 连接失败。

解决方案:

  • 检查 Redis 服务是否运行
  • 检查配置中的 Redis 地址和密码
  • 如果不需要 Redis,可以设置 redis.enabled: false

3. 消息转发失败

问题:消息转发失败,收到失败通知。

可能原因:

  • Bot 被 Recipient 阻止
  • 群组已删除或 Bot 被移除
  • 网络问题

解决方案:

  • 检查 Bot 是否被阻止
  • 检查群组状态
  • 系统会自动检测并清理无效的 Recipient

4. 限流问题

问题:消息发送被限流。

解决方案:

  • 检查配置中的限流设置
  • 对于 Guest 消息限流,系统会延迟发送
  • Telegram API 限流会等待后重试

5. Proxy 连接失败

问题:配置了代理但无法连接 Telegram API。

可能原因:

  • 代理地址配置错误
  • 代理服务未运行
  • 代理认证信息错误
  • 代理不支持 HTTPS 连接

解决方案:

  • 检查代理服务是否正常运行
  • 验证代理地址和端口是否正确
  • 如果使用认证,检查用户名和密码
  • 尝试使用 curl 测试代理连接:
    curl -x http://127.0.0.1:7890 https://api.telegram.org
  • 查看日志中的 proxy 相关错误信息

6. Guest 回复找不到消息

问题:Guest 回复消息时提示找不到对应的消息。

可能原因:

  • 消息映射记录不完整
  • 回复的消息已被删除

解决方案:

  • 系统会自动记录所有消息映射,包括 bot 发送给 guest 的消息 ID
  • 如果问题持续,检查数据库中的 message_mappings 表
  • 确保系统正常运行,不要手动删除消息映射记录

7. 黑名单状态不正确

问题:用户被 ban 后 unban,但状态显示不正确。

解决方案:

  • 系统已优化黑名单逻辑,正确处理 ban/unban 组合
  • 如果遇到问题,检查数据库中的 blacklists 表记录
  • 系统会查找最新的 approved unban 和 active ban 来判断当前状态

8. 广告拦截功能

问题:如何启用或禁用广告拦截功能?

配置方式: 在配置文件中设置 ad_filter.enabled: true 即可启用广告拦截。

拦截规则:

  • 拦截包含 @用户名 的消息(mention 或 text_mention 类型的 Entity)
    • 支持纯文字消息(检查 Entities)和媒体消息的说明文字(检查 CaptionEntities)
  • 拦截包含链接的消息(url 或 text_link 类型的 Entity)
    • 支持纯文字消息(检查 Entities)和媒体消息的说明文字(检查 CaptionEntities)
  • 拦截包含按钮的消息(ReplyMarkup,包括内联键盘按钮和回复键盘)
  • 拦截通过其他 Bot 发送的消息(ViaBot)
  • 拦截外部回复消息的引用内容(ExternalReply + Quote)
    • 当消息回复来自其他聊天或论坛主题的消息时(ExternalReply 存在)
    • 检查引用文本(Quote.Text)中是否包含 @用户名 或链接
    • 优先检查 Quote.Entities,如果没有则使用正则表达式精确匹配

注意事项:

  • 广告拦截只对 Guest 发送的普通消息生效
  • 命令(以 / 开头)不受广告拦截影响
  • 系统消息会被系统消息过滤器处理,不会触发广告拦截
  • 被拦截的消息会向发送者发送通知,说明拦截原因
  • 支持检测纯文字消息和带说明的媒体消息(图片、视频等)
  • 对于外部回复消息(ExternalReply),会检查引用文本(Quote.Text)中的广告内容
  • 广告检测优先使用 Telegram 的 Entity 系统(更准确),如果没有 Entity 则使用正则表达式精确匹配
  • 正则表达式匹配避免误判(如邮箱地址中的 @ 不会被识别为用户名)

禁用广告拦截: 设置 ad_filter.enabled: false 或删除该配置项(默认为 false)。

9. LLM 广告拦截

问题:纯文本广告(VPN、虚拟货币、频道买卖等)绕过了规则拦截怎么办?

解决方案: 启用可选的 LLM 二级过滤——在 config.yaml 配置 llm_ad_filter 块(provider/api_key/model),再由 Superuser 在 ManagerBot 的 /manage → 选 Bot → Enable LLM Ad Filter 中针对具体 ForwarderBot 开启。详见上文「LLM 广告拦截(可选二级过滤)」一节。

常见疑问:

  • 开关在哪? 只有 Superuser 能在 /manage 进入某个 Bot 的详情页看到开关,Manager / Admin 看不到也无法调用。
  • 为什么消息延迟几秒才到? 启用 LLM 拦截的 Bot 会按 batch_window_seconds(默认 5 秒)合并同一 Guest 的消息再统一判断,这是接入 LLM 的固有代价。想降低延迟可调小该值,但抓拆分广告的能力会下降。
  • LLM 服务挂了会怎样? fail-open——超时或报错时消息按正常转发,不会因为 LLM 故障误伤正常用户,只在日志里记 warning。
  • 配了 key 但所有 Bot 都没拦? 检查是否已由 Superuser 对目标 Bot 打开开关(默认全部关闭);全局配了 llm_ad_filter 不等于自动生效。
  • 想换更便宜的模型? Anthropic 用 claude-haiku-4-5-20251001,或用 provider: openai 接自建/第三方 OpenAI 兼容端点(vLLM、ollama 等)。
  • 怎么复盘判定? 查 audit_logs 表,llm_ad_blocked 是拦截记录(含原因与截断文本),llm_ad_filter_toggle 是开关变更记录。

禁用 LLM 广告拦截: 删除或留空 llm_ad_filter 块(provider/api_key/model 都为空)即全局禁用;或保留全局配置、仅由 Superuser 关闭单个 Bot 的开关。

📝 开发指南

代码规范

  • 遵循 Go 官方代码规范
  • 使用 gofmt 格式化代码
  • 使用有意义的变量和函数名
  • 添加必要的注释

添加新功能

  1. 在相应的 service 包中添加业务逻辑
  2. 在 repository 包中添加数据访问方法
  3. 在 models 包中添加数据模型(如需要)
  4. 更新配置结构(如需要)
  5. 添加单元测试

数据库迁移

数据库迁移使用 GORM 的 AutoMigrate,在应用启动时自动执行。

注意:生产环境建议先备份数据库。

🚢 部署

单实例部署

项目设计为单实例部署,ManagerBot 和所有 ForwarderBot 运行在同一进程中。

动态 Bot 管理

系统支持运行时动态管理 ForwarderBot:

  • 添加 Bot:通过 /addbot 命令添加后,Bot 会立即启动,无需重启应用
  • 删除 Bot:通过管理界面删除 Bot 后,Bot 会立即停止并清理资源
  • 自动恢复:应用重启后会自动加载并启动所有已注册的 ForwarderBot

部署步骤

  1. 构建二进制文件
go build -o bot ./cmd/bot
  1. 准备配置文件
cp configs/config.yaml.example configs/config.yaml
# 编辑配置文件
  1. 运行
./bot

使用 systemd(Linux)

创建 /etc/systemd/system/telegram-forwarder-bot.service:

[Unit]
Description=Telegram Forwarder Bot
After=network.target

[Service]
Type=simple
User=your-user
WorkingDirectory=/path/to/go-telegram-forwarder-bot
ExecStart=/path/to/go-telegram-forwarder-bot/bot
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

启动服务:

sudo systemctl enable telegram-forwarder-bot
sudo systemctl start telegram-forwarder-bot

📊 监控和日志

日志级别

  • development:DEBUG 级别,记录所有操作细节
  • production:INFO 级别

日志输出模式

支持三种输出模式:

  • stdout:仅输出到控制台(默认)
  • file:仅输出到文件
  • both:同时输出到控制台和文件

使用场景:

  • stdout:开发环境,方便查看日志
  • file:生产环境,节省控制台输出
  • both:生产环境,既需要查看实时日志,又需要持久化存储

日志内容

系统提供详细的 debug 级别日志,包括:

  • 所有消息接收、转发、发送操作
  • 命令执行和参数
  • Callback 处理和执行结果
  • 错误和重试信息
  • 数据库操作
  • Bot 启动和停止事件

关键错误通知

以下错误会自动通知 Superuser:

  • 数据库连接失败
  • Bot Token 失效(401 错误)
  • Redis 连接失败(如果启用)
  • 系统级错误(panic)

通知防抖:同一错误类型 1 小时内最多通知一次。

🤝 贡献

欢迎提交 Issue 和 Pull Request!

📄 许可证

MIT License

🙏 致谢

  • gotgbot - Telegram Bot API 客户端
  • GORM - Go ORM
  • Viper - 配置管理
  • Zap - 结构化日志

注意:本项目仅供学习和研究使用。使用 Telegram Bot API 时请遵守 Telegram 的服务条款。

About

想实现一个 @LivegramBot 类似的东西。demo:@liki4_forwarder_manager_bot

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages