FILE / ScuroNeko/Laniakea

tgapi/methods.go

Исходный файл и его история в репозитории.
FILE v1.2.0
Files
Laniakea/tgapi/methods.go
T
ScuroNeko 24040fe164
Golang lint / lint (push) Successful in 58s
Golang lint / lint (pull_request) Successful in 13m10s
(new): expand runtime APIs
(fix): harden concurrent lifecycle
(tests): add regression coverage
(doc): update v1.2 guidance
2026-08-20 11:08:45 +03:00

353 lines
15 KiB
Go

package tgapi
import (
"context"
"fmt"
"io"
"math"
"net/http"
"git.scuroneko.dev/scuroneko/laniakea/utils"
)
// UpdateParams holds parameters for the getUpdates method.
// See https://core.telegram.org/bots/api#getupdates
type UpdateParams struct {
// Offset Optional. Identifier of the first update to be returned. Must be greater by one than the highest
// among the identifiers of previously received updates. By default, updates starting with the earliest
// unconfirmed update are returned. An update is considered confirmed as soon as getUpdates is called with
// an offset higher than its update_id. The negative offset can be specified to retrieve updates starting
// from -offset update from the end of the updates queue. All previous updates will be forgotten.
Offset *int `json:"offset,omitempty"`
// Limit Optional. Limits the number of updates to be retrieved. Values between 1-100 are accepted. Defaults
// to 100.
Limit *int `json:"limit,omitempty"`
// Timeout Optional. Timeout in seconds for long polling. Defaults to 0, i.e. usual short polling. Should be
// positive, short polling should be used for testing purposes only.
Timeout *int `json:"timeout,omitempty"`
// AllowedUpdates Optional. A JSON-serialized list of the update types you want your bot to receive. For
// example, specify ["message", "edited_channel_post", "callback_query"] to only receive updates of these
// types. See Update for a complete list of available update types. Specify an empty list to receive all
// update types except chat_member, message_reaction, and message_reaction_count (default). If not
// specified, the previous setting will be used. Please note that this parameter doesn't affect updates
// created before the call to getUpdates, so unwanted updates may be received for a short period of time.
AllowedUpdates []UpdateType `json:"allowed_updates,omitempty"`
}
// GetMe returns basic information about the bot.
// See https://core.telegram.org/bots/api#getme
func (api *API) GetMe() (User, error) {
req := NewRequest[User]("getMe", NoParams)
return req.Do(api)
}
// GetMeWithContext is the context-aware variant of GetMe.
// It executes the same request but uses ctx for cancellation and deadlines.
// See https://core.telegram.org/bots/api#getme
func (api *API) GetMeWithContext(ctx context.Context) (User, error) {
req := NewRequest[User]("getMe", NoParams)
return req.DoWithContext(ctx, api)
}
// GetManagedBotToken holds parameters for the getManagedBotToken method.
// See https://core.telegram.org/bots/api#getmanagedbottoken
type GetManagedBotToken struct {
// UserID Required. User identifier of the managed bot whose token will be returned
UserID int64 `json:"user_id"`
}
// GetManagedBotToken returns the current token of a managed bot.
// See https://core.telegram.org/bots/api#getmanagedbottoken
func (api *API) GetManagedBotToken(params GetManagedBotToken) (string, error) {
req := NewRequest[string]("getManagedBotToken", params)
return req.Do(api)
}
// GetManagedBotTokenWithContext is the context-aware variant of GetManagedBotToken.
// It executes the same request but uses ctx for cancellation and deadlines.
// See https://core.telegram.org/bots/api#getmanagedbottoken
func (api *API) GetManagedBotTokenWithContext(ctx context.Context, params GetManagedBotToken) (string, error) {
req := NewRequest[string]("getManagedBotToken", params)
return req.DoWithContext(ctx, api)
}
// ReplaceManagedBotToken holds parameters for the replaceManagedBotToken method.
// See https://core.telegram.org/bots/api#replacemanagedbottoken
type ReplaceManagedBotToken struct {
// UserID Required. User identifier of the managed bot whose token will be replaced
UserID int64 `json:"user_id"`
}
// ReplaceManagedBotToken replaces and returns the token of a managed bot.
// See https://core.telegram.org/bots/api#replacemanagedbottoken
func (api *API) ReplaceManagedBotToken(params ReplaceManagedBotToken) (string, error) {
req := NewRequest[string]("replaceManagedBotToken", params)
return req.Do(api)
}
// ReplaceManagedBotTokenWithContext is the context-aware variant of ReplaceManagedBotToken.
// It executes the same request but uses ctx for cancellation and deadlines.
// See https://core.telegram.org/bots/api#replacemanagedbottoken
func (api *API) ReplaceManagedBotTokenWithContext(ctx context.Context, params ReplaceManagedBotToken) (string, error) {
req := NewRequest[string]("replaceManagedBotToken", params)
return req.DoWithContext(ctx, api)
}
// LogOut logs the bot out from the cloud Bot API server.
// Returns true on success.
// See https://core.telegram.org/bots/api#logout
func (api *API) LogOut() (bool, error) {
req := NewRequest[bool]("logOut", NoParams)
return req.Do(api)
}
// LogOutWithContext is the context-aware variant of LogOut.
// It executes the same request but uses ctx for cancellation and deadlines.
// See https://core.telegram.org/bots/api#logout
func (api *API) LogOutWithContext(ctx context.Context) (bool, error) {
req := NewRequest[bool]("logOut", NoParams)
return req.DoWithContext(ctx, api)
}
// CloseRemote closes the bot instance on the local server.
// Returns true on success.
// See https://core.telegram.org/bots/api#close
func (api *API) CloseRemote() (bool, error) {
req := NewRequest[bool]("close", NoParams)
return req.Do(api)
}
// CloseRemoteWithContext is the context-aware variant of CloseRemote.
// It executes the same request but uses ctx for cancellation and deadlines.
// See https://core.telegram.org/bots/api#close
func (api *API) CloseRemoteWithContext(ctx context.Context) (bool, error) {
req := NewRequest[bool]("close", NoParams)
return req.DoWithContext(ctx, api)
}
// GetUpdates receives incoming updates using long polling.
// See https://core.telegram.org/bots/api#getupdates
func (api *API) GetUpdates(params UpdateParams) ([]Update, error) {
req := NewRequest[[]Update]("getUpdates", params)
return req.Do(api)
}
// GetUpdatesWithContext is the context-aware variant of GetUpdates.
// It executes the same request but uses ctx for cancellation and deadlines.
// See https://core.telegram.org/bots/api#getupdates
func (api *API) GetUpdatesWithContext(ctx context.Context, params UpdateParams) ([]Update, error) {
req := NewRequest[[]Update]("getUpdates", params)
return req.DoWithContext(ctx, api)
}
// SetWebhook holds parameters for the setWebhook method.
// To upload a self-signed certificate, use Uploader.SetWebhook.
// See https://core.telegram.org/bots/api#setwebhook
type SetWebhook struct {
// URL Required. HTTPS URL to send updates to. Use an empty string to remove webhook integration.
URL string `json:"url"`
// IPAddress Optional. The fixed IP address which will be used to send webhook requests instead of the IP
// address resolved through DNS
IPAddress string `json:"ip_address,omitempty"`
// MaxConnections Optional. The maximum allowed number of simultaneous HTTPS connections to the webhook for
// update delivery, 1-100. Defaults to 40. Use lower values to limit the load on your bot's server, and
// higher values to increase your bot's throughput.
MaxConnections int8 `json:"max_connections,omitempty"`
// AllowedUpdates Optional. A JSON-serialized list of the update types you want your bot to receive. For
// example, specify ["message", "edited_channel_post", "callback_query"] to only receive updates of these
// types. See Update for a complete list of available update types. Specify an empty list to receive all
// update types except chat_member, message_reaction, and message_reaction_count (default). If not
// specified, the previous setting will be used. Please note that this parameter doesn't affect updates
// created before the call to the setWebhook, so unwanted updates may be received for a short period of
// time.
AllowedUpdates []UpdateType `json:"allowed_updates,omitempty"`
// DropPendingUpdates Optional. Pass True to drop all pending updates
DropPendingUpdates bool `json:"drop_pending_updates,omitempty"`
// SecretToken Optional. A secret token to be sent in a header “X-Telegram-Bot-Api-Secret-Token” in
// every webhook request, 1-256 characters. Only characters A-Z, a-z, 0-9, _ and - are allowed. The header
// is useful to ensure that the request comes from a webhook set by you.
SecretToken string `json:"secret_token,omitempty"`
}
// SetWebhook sets a webhook URL for incoming updates.
// For certificate upload, use Uploader.SetWebhook.
// Returns true on success.
// See https://core.telegram.org/bots/api#setwebhook
func (api *API) SetWebhook(params SetWebhook) (bool, error) {
req := NewRequest[bool]("setWebhook", params)
return req.Do(api)
}
// SetWebhookWithContext is the context-aware variant of SetWebhook.
// It executes the same request but uses ctx for cancellation and deadlines.
// For certificate upload, use Uploader.SetWebhook.
// See https://core.telegram.org/bots/api#setwebhook
func (api *API) SetWebhookWithContext(ctx context.Context, params SetWebhook) (bool, error) {
req := NewRequest[bool]("setWebhook", params)
return req.DoWithContext(ctx, api)
}
// DeleteWebhook holds parameters for the deleteWebhook method.
// See https://core.telegram.org/bots/api#deletewebhook
type DeleteWebhook struct {
// DropPendingUpdates Optional. Pass True to drop all pending updates
DropPendingUpdates bool `json:"drop_pending_updates,omitempty"`
}
// DeleteWebhook removes the current webhook integration.
// Returns true on success.
// See https://core.telegram.org/bots/api#deletewebhook
func (api *API) DeleteWebhook(params DeleteWebhook) (bool, error) {
req := NewRequest[bool]("deleteWebhook", params)
return req.Do(api)
}
// DeleteWebhookWithContext is the context-aware variant of DeleteWebhook.
// It executes the same request but uses ctx for cancellation and deadlines.
// See https://core.telegram.org/bots/api#deletewebhook
func (api *API) DeleteWebhookWithContext(ctx context.Context, params DeleteWebhook) (bool, error) {
req := NewRequest[bool]("deleteWebhook", params)
return req.DoWithContext(ctx, api)
}
// GetWebhookInfo returns the current webhook status.
// See https://core.telegram.org/bots/api#getwebhookinfo
func (api *API) GetWebhookInfo() (WebhookInfo, error) {
req := NewRequest[WebhookInfo]("getWebhookInfo", NoParams)
return req.Do(api)
}
// GetWebhookInfoWithContext is the context-aware variant of GetWebhookInfo.
// It executes the same request but uses ctx for cancellation and deadlines.
// See https://core.telegram.org/bots/api#getwebhookinfo
func (api *API) GetWebhookInfoWithContext(ctx context.Context) (WebhookInfo, error) {
req := NewRequest[WebhookInfo]("getWebhookInfo", NoParams)
return req.DoWithContext(ctx, api)
}
// GetFile holds parameters for the getFile method.
// See https://core.telegram.org/bots/api#getfile
type GetFile struct {
// FileID Required. File identifier to get information about
FileID string `json:"file_id"`
}
// GetFile returns basic information about a file and prepares it for downloading.
// See https://core.telegram.org/bots/api#getfile
func (api *API) GetFile(params GetFile) (File, error) {
req := NewRequest[File]("getFile", params)
return req.Do(api)
}
// GetFileWithContext is the context-aware variant of GetFile.
// It executes the same request but uses ctx for cancellation and deadlines.
// See https://core.telegram.org/bots/api#getfile
func (api *API) GetFileWithContext(ctx context.Context, params GetFile) (File, error) {
req := NewRequest[File]("getFile", params)
return req.DoWithContext(ctx, api)
}
// GetFileByLink downloads a file from Telegram's file server using the provided file link.
// The link is usually obtained from File.FilePath.
// For large files, prefer OpenFileByLink or OpenFileByLinkWithContext to stream the response body.
// This unbounded helper is retained for v1 compatibility and is subject to change in v2;
// prefer GetFileByLinkLimit for untrusted or potentially large files.
// See https://core.telegram.org/bots/api#file
func (api *API) GetFileByLink(link string) ([]byte, error) {
return api.getFileByLink(context.Background(), link)
}
// GetFileByLinkWithContext is the context-aware variant of GetFileByLink.
// It executes the same request but uses ctx for cancellation and deadlines.
// For large files, prefer OpenFileByLinkWithContext to stream the response body.
// See https://core.telegram.org/bots/api#file
func (api *API) GetFileByLinkWithContext(ctx context.Context, link string) ([]byte, error) {
return api.getFileByLink(ctx, link)
}
// GetFileByLinkLimit downloads at most maxBytes from Telegram's file server.
// It returns ErrFileTooLarge when the response exceeds the limit.
func (api *API) GetFileByLinkLimit(link string, maxBytes int64) ([]byte, error) {
return api.GetFileByLinkLimitWithContext(context.Background(), link, maxBytes)
}
// GetFileByLinkLimitWithContext is the context-aware variant of GetFileByLinkLimit.
func (api *API) GetFileByLinkLimitWithContext(ctx context.Context, link string, maxBytes int64) ([]byte, error) {
if maxBytes < 0 {
return nil, fmt.Errorf("maximum file size must not be negative: %d", maxBytes)
}
body, err := api.openFileByLink(ctx, link)
if err != nil {
return nil, err
}
defer func() { _ = body.Close() }()
readLimit := maxBytes
if readLimit < math.MaxInt64 {
readLimit++
}
data, err := io.ReadAll(io.LimitReader(body, readLimit))
if err != nil {
return nil, err
}
if int64(len(data)) > maxBytes {
return nil, ErrFileTooLarge
}
return data, nil
}
// OpenFileByLink opens a streaming response body for a file hosted on Telegram's file server.
// The caller must close the returned ReadCloser.
// See https://core.telegram.org/bots/api#file
func (api *API) OpenFileByLink(link string) (io.ReadCloser, error) {
return api.openFileByLink(context.Background(), link)
}
// OpenFileByLinkWithContext is the context-aware variant of OpenFileByLink.
// The caller must close the returned ReadCloser.
// See https://core.telegram.org/bots/api#file
func (api *API) OpenFileByLinkWithContext(ctx context.Context, link string) (io.ReadCloser, error) {
return api.openFileByLink(ctx, link)
}
func (api *API) getFileByLink(ctx context.Context, link string) ([]byte, error) {
body, err := api.openFileByLink(ctx, link)
if err != nil {
return nil, err
}
defer func() {
_ = body.Close()
}()
return io.ReadAll(body)
}
func (api *API) openFileByLink(ctx context.Context, link string) (io.ReadCloser, error) {
methodPrefix := ""
if api.useTestServer {
methodPrefix = "/test"
}
u := fmt.Sprintf("%s/file/bot%s%s/%s", api.apiURL, api.token, methodPrefix, link)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", fmt.Sprintf("Laniakea/%s", utils.VersionString))
res, err := api.client.Do(req)
if err != nil {
return nil, redactHTTPError(err, api.token)
}
if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusMultipleChoices {
defer func() {
_ = res.Body.Close()
}()
body, readErr := io.ReadAll(io.LimitReader(res.Body, 4<<10))
if readErr != nil {
return nil, fmt.Errorf("unexpected status %d", res.StatusCode)
}
return nil, fmt.Errorf("unexpected status %d: %s", res.StatusCode, string(body))
}
return res.Body, nil
}