Skip to content
This repository has been archived by the owner on May 29, 2024. It is now read-only.

Commit

Permalink
Implement Telegram alert client
Browse files Browse the repository at this point in the history
  • Loading branch information
richardgreg committed Feb 19, 2024
1 parent a692c87 commit c960e5b
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 1 deletion.
2 changes: 1 addition & 1 deletion internal/client/slack.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type slackClient struct {
// NewSlackClient ... Initializer
func NewSlackClient(cfg *SlackConfig, name string) SlackClient {
if cfg.URL == "" {
logging.NoContext().Warn("No Slack webhook URL not provided")
logging.NoContext().Warn("No Slack webhook URL provided")
}

return &slackClient{
Expand Down
112 changes: 112 additions & 0 deletions internal/client/telegram.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package client

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"

"github.com/base-org/pessimism/internal/core"
"github.com/base-org/pessimism/internal/logging"
)

// TelegramConfig stores configuration for the Telegram bot
type TelegramConfig struct {
Token string // Bot token received from BotFather
ChatID string // Chat ID where messages will be sent
}

// TelegramClient interface for sending alerts
type TelegramClient interface {
AlertClient
}

// telegramClient implementation of TelegramClient
type telegramClient struct {
token string
chatID string
client *http.Client
}

// NewTelegramClient initializes a new Telegram client with given config
func NewTelegramClient(cfg *TelegramConfig) TelegramClient {
if cfg.Token == "" {
logging.NoContext().Warn("No Telegram token provided")
}

return &telegramClient{
token: cfg.Token,
chatID: cfg.ChatID,
client: &http.Client{},
}
}

// TelegramPayload structure for the message payload
type TelegramPayload struct {
ChatID string `json:"chat_id"`
Text string `json:"text"`
}

// PostEvent sends an alert message to the specified Telegram chat
func (tc *telegramClient) PostEvent(ctx context.Context, data *AlertEventTrigger) (*AlertAPIResponse, error) {
payload := TelegramPayload{
ChatID: tc.chatID,
Text: data.Message,
}

payloadBytes, err := json.Marshal(payload)
if err != nil {
return nil, err
}

url := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", tc.token)
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(payloadBytes))

Check failure on line 65 in internal/client/telegram.go

View workflow job for this annotation

GitHub Actions / lint

"POST" can be replaced by http.MethodPost (usestdlibvars)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")

resp, err := tc.client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

respBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("telegram API returned bad status code %d: %s", resp.StatusCode, string(respBytes))
}

// Simplified handling
var apiResp struct {
Ok bool `json:"ok"`
Result json.RawMessage `json:"result"`
Error string `json:"description"`
}
if err = json.Unmarshal(respBytes, &apiResp); err != nil {
return nil, fmt.Errorf("could not unmarshal telegram response: %w", err)
}

if !apiResp.Ok {
return &AlertAPIResponse{
Status: core.FailureStatus,
Message: apiResp.Error,
}, nil
}

return &AlertAPIResponse{
Status: core.SuccessStatus,
Message: "Message sent successfully",
}, nil
}

// GetName returns the name of the Telegram client
func (tc telegramClient) GetName() string {
return "TelegramClient"
}

0 comments on commit c960e5b

Please sign in to comment.