Files
ops-assistant/internal/bot/telegram.go
T

105 lines
2.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package bot
import (
"context"
"fmt"
"log"
"strings"
"time"
"ops-assistant/internal/core/ops"
"ops-assistant/models"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
"gorm.io/gorm"
)
// DefaultUserID 统一用户ID
const DefaultUserID int64 = 1
type TGBot struct {
api *tgbotapi.BotAPI
db *gorm.DB
opsSvc *ops.Service
}
func NewTGBot(db *gorm.DB, token string, opsSvc *ops.Service) (*TGBot, error) {
bot, err := tgbotapi.NewBotAPI(token)
if err != nil {
return nil, err
}
return &TGBot{api: bot, db: db, opsSvc: opsSvc}, nil
}
func (b *TGBot) Start(ctx context.Context) {
u := tgbotapi.NewUpdate(0)
u.Timeout = 60
updates := b.api.GetUpdatesChan(u)
log.Println("🚀 Telegram Bot 已启动")
for {
select {
case <-ctx.Done():
log.Println("⏳ Telegram Bot 正在停止...")
b.api.StopReceivingUpdates()
return
case update, ok := <-updates:
if !ok {
return
}
if update.Message == nil || update.Message.Text == "" {
continue
}
eventID := fmt.Sprintf("tg:%d", update.UpdateID)
if b.isDuplicate(eventID) {
continue
}
log.Printf("📩 inbound platform=telegram event=%s chat=%d user=%d text=%q", eventID, update.Message.Chat.ID, update.Message.From.ID, strings.TrimSpace(update.Message.Text))
b.handleMessage(update.Message)
}
}
}
func (b *TGBot) isDuplicate(eventID string) bool {
if b.db == nil || strings.TrimSpace(eventID) == "" {
return false
}
var existed models.MessageDedup
if err := b.db.Where("platform = ? AND event_id = ?", "telegram", eventID).First(&existed).Error; err == nil {
return true
}
_ = b.db.Create(&models.MessageDedup{Platform: "telegram", EventID: eventID, ProcessedAt: time.Now()}).Error
return false
}
func (b *TGBot) handleMessage(msg *tgbotapi.Message) {
text := msg.Text
chatID := msg.Chat.ID
if b.opsSvc != nil {
if handled, out := b.opsSvc.Handle(DefaultUserID, text); handled {
m := tgbotapi.NewMessage(chatID, out)
if _, err := b.api.Send(m); err != nil {
log.Printf("发送OPS消息失败 chat=%d: %v", chatID, err)
}
return
}
}
reply := ""
switch text {
case "/start":
reply = "🛠️ 欢迎使用 Ops-Assistant!\n\n模块化运维命令助手,支持:\n• /cpa - CPA 管理\n• /cf - Cloudflare 管理\n• /cfdav - cfdav 管理\n• /sub - 订阅管理\n• /mail - 邮箱管理\n\n/help - 使用说明"
case "/help":
reply = "📖 使用说明:\n\n直接发送 OPS 命令即可,例如:\n• /cpa status\n• /cf zones\n• /cf dns list <zone_id>\n• /cfdav users\n• /sub list\n\n模块入口默认关闭,可在 Web 后台「模块设置」中启用。"
default:
reply = "❓ 无法识别,输入 /help 查看支持的命令"
}
m := tgbotapi.NewMessage(chatID, reply)
if _, err := b.api.Send(m); err != nil {
log.Printf("发送消息失败 chat=%d: %v", chatID, err)
}
}