yao/integrations/telegram/webhook.go
Max ea9e070f29 Enhance robot integration with Telegram and improve event handling
- Add Telegram integration support by introducing a dispatcher for handling Telegram events and messages.
- Implement event notifications for robot configuration changes (creation, update, deletion) to facilitate integration with external services.
- Refactor the robot initialization process to load robots into cache and start the dispatcher, improving the overall system setup.
- Update the delivery event structure to include additional metadata for better context during message handling.
- Enhance logging capabilities for better observability during robot execution and event processing.
2026-03-01 22:03:25 +08:00

82 lines
2.4 KiB
Go

package telegram
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/go-telegram/bot"
"github.com/go-telegram/bot/models"
)
// SetWebhook registers a webhook URL with Telegram. The configured
// secret_token (if any) is sent along so Telegram includes it in every
// webhook request header for verification.
func (b *Bot) SetWebhook(ctx context.Context, url string, allowedUpdates []string) error {
sdk, err := b.sdk()
if err != nil {
return err
}
params := &bot.SetWebhookParams{
URL: url,
AllowedUpdates: allowedUpdates,
SecretToken: b.secretToken,
}
if _, err := sdk.SetWebhook(ctx, params); err != nil {
return fmt.Errorf("setWebhook: %w", err)
}
return nil
}
// DeleteWebhook removes the webhook configuration from Telegram.
func (b *Bot) DeleteWebhook(ctx context.Context, dropPending bool) error {
sdk, err := b.sdk()
if err != nil {
return err
}
if _, err := sdk.DeleteWebhook(ctx, &bot.DeleteWebhookParams{
DropPendingUpdates: dropPending,
}); err != nil {
return fmt.Errorf("deleteWebhook: %w", err)
}
return nil
}
// ParseWebhookPayload reads and parses a Telegram webhook request body,
// verifies the secret header, and returns a ConvertedMessage ready for use.
// Returns nil message (no error) if the update contains no processable message.
// When groups is non-nil, media attachments are automatically resolved.
func (b *Bot) ParseWebhookPayload(ctx context.Context, r *http.Request, groups []string) (*ConvertedMessage, error) {
update, err := b.ParseRawWebhookPayload(r)
if err != nil {
return nil, err
}
cm := ConvertUpdate(update)
if cm != nil && groups != nil && cm.HasMedia() {
b.ResolveMedia(ctx, cm, groups)
}
return cm, nil
}
// ParseRawWebhookPayload reads and parses a Telegram webhook request body
// into a raw models.Update. It also verifies the X-Telegram-Bot-Api-Secret-Token
// header when a secret is configured.
func (b *Bot) ParseRawWebhookPayload(r *http.Request) (*models.Update, error) {
if !b.VerifyWebhook(r.Header.Get("X-Telegram-Bot-Api-Secret-Token")) {
return nil, fmt.Errorf("webhook secret mismatch")
}
body, err := io.ReadAll(r.Body)
if err != nil {
return nil, fmt.Errorf("read body: %w", err)
}
defer r.Body.Close()
var update models.Update
if err := json.Unmarshal(body, &update); err != nil {
return nil, fmt.Errorf("unmarshal update: %w", err)
}
return &update, nil
}