yao/integrations/telegram/polling.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

81 lines
2.3 KiB
Go

package telegram
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/go-telegram/bot/models"
)
// GetUpdates fetches new updates via long polling and returns them as
// ConvertedMessages ready for consumption. Non-message updates (e.g.
// callback_query without a message) are silently skipped.
// When groups is non-nil, media attachments are automatically downloaded
// and stored via DownloadAndStore, filling each MediaItem.Wrapper.
func (b *Bot) GetUpdates(ctx context.Context, offset int64, timeout int, groups []string) ([]*ConvertedMessage, error) {
raw, err := b.GetRawUpdates(ctx, offset, timeout)
if err != nil {
return nil, err
}
var msgs []*ConvertedMessage
for i := range raw {
if cm := ConvertUpdate(&raw[i]); cm != nil {
if groups != nil && cm.HasMedia() {
b.ResolveMedia(ctx, cm, groups)
}
msgs = append(msgs, cm)
}
}
return msgs, nil
}
// GetRawUpdates fetches raw Telegram updates without conversion.
// Use this when you need access to the original models.Update (e.g. for
// offset tracking). Uses raw HTTP because the SDK keeps getUpdates private.
func (b *Bot) GetRawUpdates(ctx context.Context, offset int64, timeout int) ([]models.Update, error) {
params := map[string]interface{}{
"offset": offset,
"timeout": timeout,
"limit": 100,
}
body, err := json.Marshal(params)
if err != nil {
return nil, fmt.Errorf("marshal params: %w", err)
}
req, err := http.NewRequestWithContext(ctx, "POST", b.botURL()+"/getUpdates", bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
resp, err := b.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("read response: %w", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("telegram API error status=%d body=%s", resp.StatusCode, string(respBody))
}
var result struct {
OK bool `json:"ok"`
Result []models.Update `json:"result"`
}
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, fmt.Errorf("unmarshal response: %w", err)
}
if !result.OK {
return nil, fmt.Errorf("telegram API returned ok=false")
}
return result.Result, nil
}