Files
nofx/logger/telegram_sender.go
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
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 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()
})
}