telegram

package
v0.5.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 18, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsSafeSplitPosition

func IsSafeSplitPosition(pos int, codeBlocks []CodeBlock) bool

IsSafeSplitPosition checks if a position is safe for splitting (not inside code blocks)

func SplitMessageSmart

func SplitMessageSmart(text string, limit int) []string

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 BotAPI

type BotAPI interface {
	SendMessage(ctx context.Context, req SendMessageRequest) (*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

func NewExtendedClient(token, proxyURL string) (BotAPI, error)

type BotCommand

type BotCommand struct {
	Command     string `json:"command"`
	Description string `json:"description"`
}

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.

func (*Chat) Format

func (c *Chat) Format() string

Format formats chat information for display.

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) "занимал" соединения из общего пула на длительное время. При высокой нагрузке или сетевых задержках другие запросы не могли получить свободное соединение и таймаутились.

Решение:

  1. httpClient - для коротких API-вызовов (sendMessage, sendChatAction и т.д.) с таймаутом 15 секунд и retry-логикой
  2. longPollingClient - для getUpdates с бесконечным таймаутом (контролируется через context), изолированный пул соединений

Дополнительно отключён HTTP/2 (ForceAttemptHTTP2=false), так как мультиплексирование запросов через одно соединение усугубляло проблему с конкуренцией за ресурсы.

func NewClient

func NewClient(token, proxyURL string) (*Client, error)

NewClient creates a new Telegram API client.

Создаёт два изолированных HTTP-клиента с разными настройками: - httpClient: таймаут 30s, retry-логика, для sendMessage/sendChatAction - longPollingClient: без таймаута (контроль через context), для getUpdates

func (*Client) GetFile

func (c *Client) GetFile(ctx context.Context, req GetFileRequest) (*File, error)

GetFile returns a File object with a file_path that can be used to download the file.

func (*Client) GetUpdates

func (c *Client) GetUpdates(ctx context.Context, req GetUpdatesRequest) ([]Update, error)

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) SendMessage

func (c *Client) SendMessage(ctx context.Context, req SendMessageRequest) (*Message, error)

SendMessage sends a text 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

type CodeBlock struct {
	Start int
	End   int
}

CodeBlock represents a code block with its start and end positions

func FindCodeBlocks

func FindCodeBlocks(text string) []CodeBlock

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 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

func (d *HTTPFileDownloader) DownloadFile(ctx context.Context, fileID string) ([]byte, error)

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 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"`
	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

type ReactionType struct {
	Type  string `json:"type"`
	Emoji string `json:"emoji,omitempty"`
}

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 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 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 Update

type Update struct {
	UpdateID int      `json:"update_id"`
	Message  *Message `json:"message,omitempty"`
}

Update represents an incoming update.

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.

func (*User) Format

func (u *User) Format() string

Format formats user information for display, including their username if available.

type Voice

type Voice struct {
	FileID       string `json:"file_id"`
	FileUniqueID string `json:"file_unique_id"`
	Duration     int    `json:"duration"`
	MimeType     string `json:"mime_type,omitempty"`
	FileSize     int    `json:"file_size,omitempty"`
}

Voice represents a voice note.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL