Files
nofx/logger/telegram_sender.go
T
icy 7d58f56e49 feat: implement hybrid database architecture and frontend encryption
- Add PostgreSQL + SQLite hybrid database support with automatic switching
- Implement frontend AES-GCM + RSA-OAEP encryption for sensitive data
- Add comprehensive DatabaseInterface with all required methods
- Fix compilation issues with interface consistency
- Update all database method signatures to use DatabaseInterface
- Add missing UpdateTraderInitialBalance method to PostgreSQL implementation
- Integrate RSA public key distribution via /api/config endpoint
- Add frontend crypto service with proper error handling
- Support graceful degradation between encrypted and plaintext transmission
- Add directory creation for RSA keys and PEM parsing fixes
- Test both SQLite and PostgreSQL modes successfully
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
2025-11-06 01:50:06 +08:00

121 lines
2.6 KiB
Go

package logger
import (
"fmt"
"sync"
"time"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)
// TelegramSender Telegram消息发送器(异步)
type TelegramSender struct {
bot *tgbotapi.BotAPI
chatID int64
msgChan chan string
retryCount int
retryInterval time.Duration
wg sync.WaitGroup
stopChan chan struct{}
once sync.Once
}
// NewTelegramSender 创建Telegram发送器(使用默认参数)
func NewTelegramSender(botToken string, chatID int64) (*TelegramSender, error) {
bot, err := tgbotapi.NewBotAPI(botToken)
if err != nil {
return nil, fmt.Errorf("创建telegram bot失败: %w", err)
}
// 设置为静默模式(不打印bot信息)
bot.Debug = false
sender := &TelegramSender{
bot: bot,
chatID: chatID,
msgChan: make(chan string, 20), // 固定缓冲区大小: 20
retryCount: 3, // 固定重试次数: 3
retryInterval: 3 * time.Second, // 固定重试间隔: 3秒
stopChan: make(chan struct{}),
}
// 启动异步发送协程
sender.Start()
return sender, nil
}
// Start 启动异步发送协程
func (s *TelegramSender) Start() {
s.wg.Add(1)
go s.listenAndSend()
}
// SendAsync 异步发送消息(非阻塞)
func (s *TelegramSender) SendAsync(message string) {
select {
case s.msgChan <- message:
// 成功写入缓冲区
default:
// 缓冲区满,丢弃消息(不阻塞主流程)
fmt.Printf("[Telegram] 消息缓冲区已满,消息被丢弃\n")
}
}
// listenAndSend 监听channel并发送消息
func (s *TelegramSender) listenAndSend() {
defer s.wg.Done()
for {
select {
case msg := <-s.msgChan:
s.sendWithRetry(msg)
case <-s.stopChan:
// 清空缓冲区后退出
for len(s.msgChan) > 0 {
msg := <-s.msgChan
s.sendWithRetry(msg)
}
return
}
}
}
// sendWithRetry 发送消息(带重试)
func (s *TelegramSender) sendWithRetry(message string) {
var err error
for i := 0; i < s.retryCount; i++ {
err = s.send(message)
if err == nil {
return // 发送成功
}
// 重试前等待
if i < s.retryCount-1 {
time.Sleep(s.retryInterval)
}
}
// 所有重试都失败
if err != nil {
fmt.Printf("[Telegram] 发送消息失败(已重试%d次): %v\n", s.retryCount, err)
}
}
// send 发送单条消息
func (s *TelegramSender) send(message string) error {
msg := tgbotapi.NewMessage(s.chatID, message)
msg.ParseMode = tgbotapi.ModeMarkdown
_, err := s.bot.Send(msg)
return err
}
// Stop 停止发送器(优雅关闭)
func (s *TelegramSender) Stop() {
s.once.Do(func() {
close(s.stopChan)
s.wg.Wait()
})
}