X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/3cdbd017da9ae7a7045f4272f16d4b262fd01c79..d73a88b9e0835b1d7f0711e02db56555101a7830:/telegram_api.go diff --git a/telegram_api.go b/telegram_api.go index 508010e..f53d8d5 100644 --- a/telegram_api.go +++ b/telegram_api.go @@ -35,11 +35,11 @@ const ( // its own, because the long poll of getUpdates needs a longer limit. telegramSendTimeout = 30 * time.Second - // telegramFileLookupTimeout is the longest wait for image file details. + // telegramFileLookupTimeout is the longest wait for media file details. telegramFileLookupTimeout = 30 * time.Second - // telegramImageDownloadTimeout is the longest wait for image bytes. - telegramImageDownloadTimeout = 30 * time.Second + // telegramFileDownloadTimeout is the longest wait for image bytes. + telegramFileDownloadTimeout = 30 * time.Second // telegramTypingTimeout is the longest wait to show the typing action. telegramTypingTimeout = 30 * time.Second @@ -109,9 +109,10 @@ func (b *TelegramAPI) GetUpdates(ctx context.Context, offset int64) ([]TelegramU return updates, err } -// GetImage downloads a file through the authenticated file endpoint. Errors -// never include its token or URL, and the body is limited before storage. -func (b *TelegramAPI) GetImage(ctx context.Context, id string) (data []byte, err error) { +// GetFile downloads bounded media through the authenticated file endpoint. +// Errors never include its token or URL, and the body is limited before +// storage. +func (b *TelegramAPI) GetFile(ctx context.Context, id string, limit int64, tooLarge error) (data []byte, err error) { var file struct { Path string `json:"file_path"` Size int64 `json:"file_size"` @@ -119,34 +120,34 @@ func (b *TelegramAPI) GetImage(ctx context.Context, id string) (data []byte, err err = b.call(ctx, telegramFileLookupTimeout, "getFile", map[string]any{"file_id": id}, &file) if err != nil { - return nil, fmt.Errorf("get image file: %w", err) + return nil, fmt.Errorf("get media file: %w", err) } - if file.Size > imageMaxBytes { - return nil, errImageSize + if file.Size > limit { + return nil, tooLarge } if file.Path == "" || path.Clean(file.Path) != file.Path || strings.HasPrefix(file.Path, "/") || strings.HasPrefix(file.Path, "../") || strings.ContainsAny(file.Path, "?%#\\") { - return nil, errors.New("invalid image file path") + return nil, errors.New("invalid media file path") } - ctx, cancel := context.WithTimeout(ctx, telegramImageDownloadTimeout) + ctx, cancel := context.WithTimeout(ctx, telegramFileDownloadTimeout) defer cancel() request, err := http.NewRequestWithContext(ctx, http.MethodGet, b.base+"/file/bot"+b.token+"/"+file.Path, nil) if err != nil { - return nil, fmt.Errorf("make image request: %s", b.redact(err)) + return nil, fmt.Errorf("make media request: %s", b.redact(err)) } response, err := b.http.Do(request) if err != nil { - return nil, b.networkError("image download failed", err, telegramImageDownloadTimeout) + return nil, b.networkError("media download failed", err, telegramFileDownloadTimeout) } defer func() { closeErr := response.Body.Close() if closeErr != nil { - err = errors.Join(err, b.networkError("close image download", closeErr, telegramImageDownloadTimeout)) + err = errors.Join(err, b.networkError("close media download", closeErr, telegramFileDownloadTimeout)) } }() @@ -157,13 +158,13 @@ func (b *TelegramAPI) GetImage(ctx context.Context, id string) (data []byte, err } } - data, err = io.ReadAll(io.LimitReader(response.Body, imageMaxBytes+1)) + data, err = io.ReadAll(io.LimitReader(response.Body, limit+1)) if err != nil { - return nil, b.networkError("image cut off", err, telegramImageDownloadTimeout) + return nil, b.networkError("media cut off", err, telegramFileDownloadTimeout) } - if len(data) > imageMaxBytes { - return nil, errImageSize + if int64(len(data)) > limit { + return nil, tooLarge } return data, nil @@ -430,6 +431,13 @@ type TelegramMessage struct { Caption string `json:"caption"` Photo []TelegramPhoto `json:"photo"` Document *TelegramDocument `json:"document"` + Voice *TelegramVoice `json:"voice"` +} + +// TelegramVoice identifies a voice note in the authenticated file API. +type TelegramVoice struct { + FileID string `json:"file_id"` + FileSize int64 `json:"file_size"` } // TelegramPhoto is one supplied size of a photo.