Documentation
¶
Index ¶
- Variables
- func IsSafeSplitPosition(pos int, codeBlocks []CodeBlock) bool
- func SplitMessageSmart(text string, limit int) []string
- type APIResponse
- type Audio
- type BotAPI
- type BotCommand
- type Chat
- type Client
- func (c *Client) EditMessageText(ctx context.Context, req EditMessageTextRequest) (*Message, error)
- func (c *Client) GetFile(ctx context.Context, req GetFileRequest) (*File, error)
- func (c *Client) GetUpdates(ctx context.Context, req GetUpdatesRequest) ([]Update, error)
- func (c *Client) SendChatAction(ctx context.Context, req SendChatActionRequest) error
- func (c *Client) SendDocument(ctx context.Context, req SendDocumentRequest) (*Message, error)
- func (c *Client) SendMediaGroup(ctx context.Context, req SendMediaGroupRequest) ([]Message, error)
- func (c *Client) SendMediaGroupDocuments(ctx context.Context, req SendMediaGroupDocumentsRequest) ([]Message, error)
- func (c *Client) SendMessage(ctx context.Context, req SendMessageRequest) (*Message, error)
- func (c *Client) SendPhoto(ctx context.Context, req SendPhotoRequest) (*Message, error)
- func (c *Client) SetMessageReaction(ctx context.Context, req SetMessageReactionRequest) error
- func (c *Client) SetMyCommands(ctx context.Context, req SetMyCommandsRequest) error
- func (c *Client) SetWebhook(ctx context.Context, req SetWebhookRequest) error
- type CodeBlock
- type Document
- type EditMessageTextRequest
- type ExtendedClient
- type File
- type FileDownloader
- type GetFileRequest
- type GetUpdatesRequest
- type HTTPFileDownloader
- type InputMediaDocument
- type InputMediaPhoto
- type MediaType
- type Message
- type MessageOrigin
- type PhotoSize
- type ReactionType
- type SendChatActionRequest
- type SendDocumentRequest
- type SendMediaGroupDocumentsRequest
- type SendMediaGroupRequest
- type SendMessageRequest
- type SendPhotoRequest
- type SetMessageReactionRequest
- type SetMyCommandsRequest
- type SetWebhookRequest
- type Update
- type User
- type VideoNote
- type Voice
Constants ¶
This section is empty.
Variables ¶
var ErrMessageNotModified = errors.New("telegram: message is not modified")
ErrMessageNotModified is returned by EditMessageText when Telegram rejects an edit because the new text and entities are identical to the current message. Callers should treat this as a successful no-op.
Functions ¶
func IsSafeSplitPosition ¶
IsSafeSplitPosition checks if a position is safe for splitting (not inside code blocks)
func SplitMessageSmart ¶
SplitMessageSmart splits a long message into chunks that are safe for Telegram's message length limit. It preserves markdown structure by avoiding splits inside code blocks and other markdown constructs.
Types ¶
type APIResponse ¶
type APIResponse struct {
Ok bool `json:"ok"`
Result json.RawMessage `json:"result,omitempty"`
Description string `json:"description,omitempty"`
ErrorCode int `json:"error_code,omitempty"`
}
APIResponse represents a response from the Telegram API.
type Audio ¶ added in v0.6.0
type Audio struct {
FileID string `json:"file_id"`
FileUniqueID string `json:"file_unique_id"`
Duration int `json:"duration"`
Performers string `json:"performer,omitempty"`
Title string `json:"title,omitempty"`
FileName string `json:"file_name,omitempty"`
MimeType string `json:"mime_type,omitempty"`
FileSize int `json:"file_size,omitempty"`
}
Audio represents an audio file (MP3, etc.).
type BotAPI ¶
type BotAPI interface {
SendMessage(ctx context.Context, req SendMessageRequest) (*Message, error)
EditMessageText(ctx context.Context, req EditMessageTextRequest) (*Message, error)
SendPhoto(ctx context.Context, req SendPhotoRequest) (*Message, error)
SendDocument(ctx context.Context, req SendDocumentRequest) (*Message, error)
SendMediaGroup(ctx context.Context, req SendMediaGroupRequest) ([]Message, error)
SendMediaGroupDocuments(ctx context.Context, req SendMediaGroupDocumentsRequest) ([]Message, error)
SetMyCommands(ctx context.Context, req SetMyCommandsRequest) error
SetWebhook(ctx context.Context, req SetWebhookRequest) error
SendChatAction(ctx context.Context, req SendChatActionRequest) error
GetFile(ctx context.Context, req GetFileRequest) (*File, error)
SetMessageReaction(ctx context.Context, req SetMessageReactionRequest) error
GetUpdates(ctx context.Context, req GetUpdatesRequest) ([]Update, error)
GetToken() string
}
BotAPI defines the interface for the Telegram Bot API methods we use. This allows for easier mocking in tests.
func NewExtendedClient ¶
type BotCommand ¶
BotCommand represents a bot command.
type Chat ¶
type Chat struct {
ID int64 `json:"id"`
Type string `json:"type"`
Title string `json:"title,omitempty"`
Username string `json:"username,omitempty"`
}
Chat represents a chat.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a client for the Telegram Bot API.
АРХИТЕКТУРНОЕ РЕШЕНИЕ: Два отдельных HTTP-клиента
Проблема: При использовании одного HTTP-клиента для всех запросов возникали спорадические ошибки "context deadline exceeded (Client.Timeout exceeded while awaiting headers)" для sendMessage, sendChatAction и getUpdates.
Причина: Long polling (getUpdates с Timeout=25s) "занимал" соединения из общего пула на длительное время. При высокой нагрузке или сетевых задержках другие запросы не могли получить свободное соединение и таймаутились.
Решение:
- httpClient - для коротких API-вызовов (sendMessage, sendChatAction и т.д.) с таймаутом 15 секунд и retry-логикой
- longPollingClient - для getUpdates с бесконечным таймаутом (контролируется через context), изолированный пул соединений
Дополнительно отключён HTTP/2 (ForceAttemptHTTP2=false), так как мультиплексирование запросов через одно соединение усугубляло проблему с конкуренцией за ресурсы.
func NewClient ¶
NewClient creates a new Telegram API client.
Создаёт два изолированных HTTP-клиента с разными настройками: - httpClient: таймаут 30s, retry-логика, для sendMessage/sendChatAction - longPollingClient: без таймаута (контроль через context), для getUpdates
func (*Client) EditMessageText ¶ added in v0.9.0
EditMessageText edits the text of a message. Used by the streaming sink to progressively reveal the bot's reply.
Special-case error: when Telegram rejects the edit because the new text equals the existing one (HTTP 400 "message is not modified"), this method returns the typed sentinel ErrMessageNotModified so callers can ignore it without string-matching API descriptions.
func (*Client) GetFile ¶
GetFile returns a File object with a file_path that can be used to download the file.
func (*Client) GetUpdates ¶
GetUpdates receives incoming updates using long polling.
ВАЖНО: Использует отдельный longPollingClient с Timeout=0.
Long polling работает так: Telegram держит соединение открытым до req.Timeout секунд, ожидая новые сообщения. Если сообщения приходят раньше - возвращает их сразу. Если нет - возвращает пустой массив по истечении таймаута.
Почему отдельный клиент: - httpClient имеет таймаут 15s, что меньше типичного req.Timeout (25s) - Использование общего пула соединений создавало конкуренцию с короткими запросами - Изолированный transport гарантирует, что long polling не влияет на sendMessage
Таймаут контролируется через context: req.Timeout + 10 секунд на сетевые задержки.
Метрики: записывает время выполнения, статус long polling и количество updates.
func (*Client) SendChatAction ¶
func (c *Client) SendChatAction(ctx context.Context, req SendChatActionRequest) error
SendChatAction tells the user that something is happening on the bot's side.
func (*Client) SendDocument ¶ added in v0.8.0
SendDocument uploads a file (preserving original bytes — no recompression) and returns the resulting message.
func (*Client) SendMediaGroup ¶ added in v0.8.0
SendMediaGroup uploads 2–10 photos as an album and returns the resulting messages (one per photo). For a single photo, use SendPhoto instead.
func (*Client) SendMediaGroupDocuments ¶ added in v0.8.0
func (c *Client) SendMediaGroupDocuments(ctx context.Context, req SendMediaGroupDocumentsRequest) ([]Message, error)
SendMediaGroupDocuments uploads 2–10 documents as a grouped album. Unlike SendMediaGroup (photos), Telegram does not recompress documents.
func (*Client) SendMessage ¶
SendMessage sends a text message.
func (*Client) SendPhoto ¶ added in v0.8.0
SendPhoto uploads a photo via multipart and returns the resulting message.
func (*Client) SetMessageReaction ¶
func (c *Client) SetMessageReaction(ctx context.Context, req SetMessageReactionRequest) error
SetMessageReaction sets a reaction on a message.
func (*Client) SetMyCommands ¶
func (c *Client) SetMyCommands(ctx context.Context, req SetMyCommandsRequest) error
SetMyCommands changes the list of the bot's commands.
func (*Client) SetWebhook ¶
func (c *Client) SetWebhook(ctx context.Context, req SetWebhookRequest) error
SetWebhook specifies a URL and receives incoming updates via an outgoing webhook.
type CodeBlock ¶
CodeBlock represents a code block with its start and end positions
func FindCodeBlocks ¶
FindCodeBlocks finds all code blocks in the text and returns their positions
type Document ¶
type Document struct {
FileID string `json:"file_id"`
FileUniqueID string `json:"file_unique_id"`
FileName string `json:"file_name,omitempty"`
MimeType string `json:"mime_type,omitempty"`
FileSize int `json:"file_size,omitempty"`
}
Document represents a general file (as opposed to photos, voice messages and audio files).
type EditMessageTextRequest ¶ added in v0.9.0
type EditMessageTextRequest struct {
ChatID int64 `json:"chat_id"`
MessageID int `json:"message_id"`
Text string `json:"text"`
ParseMode string `json:"parse_mode,omitempty"`
}
EditMessageTextRequest represents the parameters for the editMessageText method. MessageThreadID is not editable (Telegram derives it from MessageID), so it is omitted here. Used by the streaming sink to update an in-flight reply.
type ExtendedClient ¶
type ExtendedClient struct {
*Client
}
Wrapper for telegram.Client to implement BotAPI interface
func (*ExtendedClient) GetToken ¶
func (c *ExtendedClient) GetToken() string
type File ¶
type File struct {
FileID string `json:"file_id"`
FileUniqueID string `json:"file_unique_id"`
FileSize int `json:"file_size,omitempty"`
FilePath string `json:"file_path,omitempty"`
}
File represents a file ready to be downloaded.
type FileDownloader ¶
type FileDownloader interface {
DownloadFile(ctx context.Context, fileID string) ([]byte, error)
DownloadFileAsBase64(ctx context.Context, fileID string) (string, error)
}
FileDownloader defines an interface for downloading files from Telegram.
type GetFileRequest ¶
type GetFileRequest struct {
FileID string `json:"file_id"`
}
GetFileRequest represents the parameters for the getFile method.
type GetUpdatesRequest ¶
type GetUpdatesRequest struct {
Offset int `json:"offset,omitempty"`
Limit int `json:"limit,omitempty"`
Timeout int `json:"timeout,omitempty"`
AllowedUpdates []string `json:"allowed_updates,omitempty"`
}
GetUpdatesRequest represents the parameters for the getUpdates method.
type HTTPFileDownloader ¶
type HTTPFileDownloader struct {
// contains filtered or unexported fields
}
HTTPFileDownloader is a concrete implementation of FileDownloader using HTTP.
func NewHTTPFileDownloader ¶
func NewHTTPFileDownloader(api BotAPI, fileBaseURL, proxyURL string) (*HTTPFileDownloader, error)
NewHTTPFileDownloader creates a new HTTPFileDownloader.
HTTP client configured with: - 60s timeout for large file downloads - DisableKeepAlives to avoid connection pool issues - Reasonable timeouts for dial/TLS/headers - Proxy support (uses proxyURL if provided, otherwise falls back to environment)
func (*HTTPFileDownloader) DownloadFile ¶
DownloadFile downloads a file from Telegram.
func (*HTTPFileDownloader) DownloadFileAsBase64 ¶
func (d *HTTPFileDownloader) DownloadFileAsBase64(ctx context.Context, fileID string) (string, error)
DownloadFileAsBase64 downloads a file and encodes it as a Base64 string.
type InputMediaDocument ¶ added in v0.8.0
InputMediaDocument is one entry of a document-type sendMediaGroup.
type InputMediaPhoto ¶ added in v0.8.0
type InputMediaPhoto struct {
// Data holds the raw image bytes; the corresponding media JSON entry will
// reference "attach://photo_<index>".
Data []byte
Filename string // e.g. "generated_1.png"
Caption string // optional; only the first item's caption is shown on the group
// ParseMode applies to Caption; uses "HTML" by default when empty.
ParseMode string
}
InputMediaPhoto is one entry of a sendMediaGroup request.
type MediaType ¶ added in v0.8.0
type MediaType string
MediaType distinguishes media-group entry types. Telegram forbids mixing types within a single group.
type Message ¶
type Message struct {
MessageID int `json:"message_id"`
MessageThreadID int `json:"message_thread_id,omitempty"`
From *User `json:"from,omitempty"`
Chat *Chat `json:"chat"`
Date int `json:"date"`
Text string `json:"text,omitempty"`
Caption string `json:"caption,omitempty"`
Photo []PhotoSize `json:"photo,omitempty"`
Document *Document `json:"document,omitempty"`
Voice *Voice `json:"voice,omitempty"`
Audio *Audio `json:"audio,omitempty"`
VideoNote *VideoNote `json:"video_note,omitempty"`
ForwardOrigin *MessageOrigin `json:"forward_origin,omitempty"`
}
Message represents a message.
func (*Message) BuildContent ¶
func (m *Message) BuildContent(translator *i18n.Translator, lang string) string
BuildContent constructs the full text content for a message, including prefixes for user, time, and forwarding.
func (*Message) BuildPrefix ¶ added in v0.2.0
func (m *Message) BuildPrefix(translator *i18n.Translator, lang string) string
BuildPrefix constructs the prefix for a message (user info or forwarding info).
type MessageOrigin ¶
type MessageOrigin struct {
Type string `json:"type"`
Date int `json:"date"`
SenderUser *User `json:"sender_user,omitempty"`
SenderUserName string `json:"sender_user_name,omitempty"`
SenderChat *Chat `json:"sender_chat,omitempty"`
AuthorSignature string `json:"author_signature,omitempty"`
}
MessageOrigin represents the origin of a message.
func (*MessageOrigin) Format ¶
func (mo *MessageOrigin) Format(forwardedBy *User, translator *i18n.Translator, lang string) string
Format formats the forward origin information for display.
type PhotoSize ¶
type PhotoSize struct {
FileID string `json:"file_id"`
FileUniqueID string `json:"file_unique_id"`
Width int `json:"width"`
Height int `json:"height"`
FileSize int `json:"file_size,omitempty"`
}
PhotoSize represents one size of a photo or a file / sticker thumbnail.
type ReactionType ¶
ReactionType represents a reaction type.
type SendChatActionRequest ¶
type SendChatActionRequest struct {
ChatID int64 `json:"chat_id"`
MessageThreadID *int `json:"message_thread_id,omitempty"`
Action string `json:"action"`
}
SendChatActionRequest represents the parameters for the sendChatAction method. См. комментарий к SendMessageRequest о причине использования *int для MessageThreadID.
type SendDocumentRequest ¶ added in v0.8.0
type SendDocumentRequest struct {
ChatID int64
MessageThreadID *int
Data []byte
Filename string
Caption string
ParseMode string
ReplyToMessageID int
}
SendDocumentRequest represents the parameters for sendDocument. Use this for images whose full resolution must be preserved (2K / 4K) — unlike sendPhoto, Telegram does not recompress documents.
type SendMediaGroupDocumentsRequest ¶ added in v0.8.0
type SendMediaGroupDocumentsRequest struct {
ChatID int64
MessageThreadID *int
Media []InputMediaDocument
ReplyToMessageID int
}
SendMediaGroupDocumentsRequest sends 2–10 documents as a single album. Telegram groups them visually while preserving full file resolution (no recompression), which SendMediaGroup with photos does not do.
type SendMediaGroupRequest ¶ added in v0.8.0
type SendMediaGroupRequest struct {
ChatID int64
MessageThreadID *int
Media []InputMediaPhoto
ReplyToMessageID int
}
SendMediaGroupRequest represents the parameters for sendMediaGroup. Media slice must have 2–10 entries; 1 item should use SendPhoto instead.
type SendMessageRequest ¶
type SendMessageRequest struct {
ChatID int64 `json:"chat_id"`
MessageThreadID *int `json:"message_thread_id,omitempty"`
Text string `json:"text"`
ParseMode string `json:"parse_mode,omitempty"`
ReplyToMessageID int `json:"reply_to_message_id,omitempty"`
}
SendMessageRequest represents the parameters for the sendMessage method.
ВАЖНО: MessageThreadID использует *int вместо int, чтобы omitempty корректно работал для нулевого значения. Telegram API интерпретирует message_thread_id: 0 как попытку отправить в топик с ID=0, что вызывает ошибку "Bad Request: invalid topic identifier specified" в обычных чатах (не форумах). При использовании указателя nil не сериализуется в JSON вообще.
type SendPhotoRequest ¶ added in v0.8.0
type SendPhotoRequest struct {
ChatID int64
MessageThreadID *int
PhotoData []byte
PhotoFilename string // e.g. "generated.png"
Caption string // optional, ≤1024 UTF-16 chars
ParseMode string // "HTML" or "MarkdownV2" or ""
ReplyToMessageID int
}
SendPhotoRequest represents the parameters for sendPhoto. PhotoData holds the raw image bytes to upload; PhotoFilename is used as the multipart field filename (Telegram uses it for the stored photo name).
NOTE: Telegram ALWAYS downscales and recompresses photos sent via sendPhoto (target ~1280 px on the long side). For originals > ~2 MB or higher than 2K resolution, use SendDocument instead to preserve quality.
type SetMessageReactionRequest ¶
type SetMessageReactionRequest struct {
ChatID int64 `json:"chat_id"`
MessageID int `json:"message_id"`
Reaction []ReactionType `json:"reaction,omitempty"`
IsBig bool `json:"is_big,omitempty"`
}
SetMessageReactionRequest represents the parameters for the setMessageReaction method.
type SetMyCommandsRequest ¶
type SetMyCommandsRequest struct {
Commands []BotCommand `json:"commands"`
}
SetMyCommandsRequest represents the parameters for the setMyCommands method.
type SetWebhookRequest ¶
type SetWebhookRequest struct {
URL string `json:"url"`
SecretToken string `json:"secret_token,omitempty"`
}
SetWebhookRequest represents the parameters for the setWebhook method.
type User ¶
type User struct {
ID int64 `json:"id"`
IsBot bool `json:"is_bot"`
FirstName string `json:"first_name"`
LastName string `json:"last_name,omitempty"`
Username string `json:"username,omitempty"`
}
User represents a Telegram user or bot.
type VideoNote ¶ added in v0.6.0
type VideoNote struct {
FileID string `json:"file_id"`
FileUniqueID string `json:"file_unique_id"`
Length int `json:"length"` // Video width and height (diameter of the video message)
Duration int `json:"duration"` // Duration of the video in seconds
Thumbnail *PhotoSize `json:"thumbnail,omitempty"`
FileSize int `json:"file_size,omitempty"`
}
VideoNote represents a video message (video circle).