// Package service — Telegram 通知 Provider。 package service import ( "context" "fmt" "strings" "time" ) // TelegramProvider 通过 Telegram Bot API 发送通知。 type TelegramProvider struct{} // Send 发送 Telegram 消息。 func (p *TelegramProvider) Send(ctx context.Context, cfg map[string]string, event NotifyEvent) error { botToken := cfg["bot_token"] chatIDs := telegramTargetChatIDs(cfg) parseMode := cfg["parse_mode"] if parseMode == "" { parseMode = "HTML" } if botToken == "" || len(chatIDs) == 0 { return fmt.Errorf("telegram: bot_token and group_chat_id/channel_chat_id are required") } text := formatTelegramMessage(event, parseMode) var firstErr error for _, chatID := range chatIDs { payload := map[string]string{ "chat_id": chatID, "text": text, "parse_mode": parseMode, } if err := telegramPostJSON(ctx, cfg, "sendMessage", payload, 15*time.Second); err != nil && firstErr == nil { firstErr = err } } return firstErr } // ValidateConfig 验证 Telegram 配置。 func (p *TelegramProvider) ValidateConfig(cfg map[string]string) error { if cfg["bot_token"] == "" { return fmt.Errorf("telegram: bot_token is required") } if len(telegramTargetChatIDs(cfg)) == 0 { return fmt.Errorf("telegram: group_chat_id or channel_chat_id is required") } return nil } // formatTelegramMessage 格式化消息内容。 func formatTelegramMessage(event NotifyEvent, parseMode string) string { var sb strings.Builder sb.WriteString(fmt.Sprintf("%s\n\n", escapeHTML(event.Title))) sb.WriteString(escapeHTML(event.Message)) if len(event.Data) > 0 { sb.WriteString("\n\n") for k, v := range event.Data { sb.WriteString(fmt.Sprintf("• %s: %v\n", escapeHTML(k), v)) } } if parseMode != "HTML" { // Markdown 模式 result := sb.String() result = strings.ReplaceAll(result, "", "**") result = strings.ReplaceAll(result, "", "**") result = strings.ReplaceAll(result, "<", "<") result = strings.ReplaceAll(result, ">", ">") result = strings.ReplaceAll(result, "&", "&") return result } return sb.String() }