general cleanup - removed old comments, enforced naming conventions etc
Some checks are pending
check / check (push) Waiting to run
Some checks are pending
check / check (push) Waiting to run
This commit is contained in:
122
backend/internal/notifications/telegram.go
Normal file
122
backend/internal/notifications/telegram.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TelegramNotifier sends alert notifications via Telegram.
|
||||
type TelegramNotifier struct {
|
||||
BotToken string
|
||||
ChatID string
|
||||
}
|
||||
|
||||
// Send implements Notifier for Telegram.
|
||||
func (t *TelegramNotifier) Send(_ context.Context, message string, meta AlertMetadata) error {
|
||||
_, err := SendTelegramNotification(t.BotToken, t.ChatID, message, meta)
|
||||
return err
|
||||
}
|
||||
|
||||
const telegramHTTPTimeoutSeconds = 10
|
||||
|
||||
var telegramHTTPClient = &http.Client{ //nolint:gochecknoglobals
|
||||
Timeout: telegramHTTPTimeoutSeconds * time.Second,
|
||||
}
|
||||
|
||||
type telegramPayload struct {
|
||||
ChatID string `json:"chat_id"`
|
||||
Text string `json:"text"`
|
||||
ParseMode string `json:"parse_mode"`
|
||||
}
|
||||
|
||||
func SendTelegramNotification(botToken, chatID, message string, meta AlertMetadata) (bool, error) {
|
||||
text := fmt.Sprintf("*Koin Ping Alert*\n\n%s\n\n*Address:* %s\n`%s`",
|
||||
escapeMarkdown(message), escapeMarkdown(meta.AddressLabel), meta.Address)
|
||||
|
||||
if meta.TxHash != "" {
|
||||
text += fmt.Sprintf("\n\n[View on Etherscan](https://etherscan.io/tx/%s)", meta.TxHash)
|
||||
}
|
||||
|
||||
payload := telegramPayload{
|
||||
ChatID: chatID,
|
||||
Text: text,
|
||||
ParseMode: "Markdown",
|
||||
}
|
||||
|
||||
body, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("marshal telegram payload: %w", err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", botToken)
|
||||
|
||||
resp, err := telegramHTTPClient.Post(url, "application/json", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
log.Printf("Failed to send Telegram notification: %v", err)
|
||||
return false, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
log.Printf("Telegram API failed: HTTP %d", resp.StatusCode)
|
||||
return false, fmt.Errorf("telegram API failed: HTTP %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func TestTelegramWebhook(botToken, chatID string) (bool, error) {
|
||||
payload := telegramPayload{
|
||||
ChatID: chatID,
|
||||
Text: "Koin Ping test notification — Your Telegram alerts are configured correctly!",
|
||||
ParseMode: "Markdown",
|
||||
}
|
||||
|
||||
body, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", botToken)
|
||||
|
||||
resp, err := telegramHTTPClient.Post(url, "application/json", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
log.Printf("Telegram test failed: %v", err)
|
||||
return false, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return resp.StatusCode >= 200 && resp.StatusCode < 300, nil
|
||||
}
|
||||
|
||||
func escapeMarkdown(s string) string {
|
||||
replacer := []struct{ old, new string }{
|
||||
{"_", "\\_"}, {"*", "\\*"}, {"[", "\\["}, {"]", "\\]"},
|
||||
{"(", "\\("}, {")", "\\)"}, {"~", "\\~"}, {"`", "\\`"},
|
||||
{">", "\\>"}, {"#", "\\#"}, {"+", "\\+"}, {"-", "\\-"},
|
||||
{"=", "\\="}, {"|", "\\|"}, {"{", "\\{"}, {"}", "\\}"},
|
||||
{".", "\\."}, {"!", "\\!"},
|
||||
}
|
||||
result := s
|
||||
for _, r := range replacer {
|
||||
result = replaceAll(result, r.old, r.new)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func replaceAll(s, old, new string) string {
|
||||
out := ""
|
||||
for i := 0; i < len(s); i++ {
|
||||
if string(s[i]) == old {
|
||||
out += new
|
||||
} else {
|
||||
out += string(s[i])
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user