Работа с файлами и медиа
Библиотека предоставляет обширные возможности для работы с файлами, изображениями и галереями. Вы можете отправлять локальные файлы, передавать потоки данных в реальном времени, а также скачивать файлы и пересылать их по идентификаторам (file_id).
Отправка файлов и изображений
Для отправки медиафайлов используются методы SendFile и SendImage. Вы можете передать файл двумя способами:
- Через путь к локальному файлу (
FilePath) — библиотека сама откроет файл и подготовит его к отправке. - Через поток (
Stream: io.Reader) — удобно, если вы скачиваете файл из интернета, генерируете его в памяти или читаете из облачного хранилища, не сохраняя на диск.
Пример: Отправка локального файла
req := files.SendFileRequest{
ChatID: u.GetChatID(), // Безопасный геттер (важно использовать именно его)
FilePath: "report.txt", // Путь к файлу на диске
Text: "Вот ваш отчет!",
}
// Если ChatID пустой (например, в личных сообщениях), используем Login
if req.ChatID == "" {
req.Login = u.GetFromLogin()
}
resp, err := bot.Files.SendFile(ctx, req)
if err != nil {
log.Println("Ошибка отправки файла:", err)
}
Пример: Отправка изображения из потока
file, err := os.Open("avatar.png")
if err != nil {
return err
}
// Вы должны закрыть локальный файл после использования в своем коде.
defer file.Close()
req := files.SendImageRequest{
ChatID: u.GetChatID(),
Stream: file, // Передаем io.Reader напрямую
Text: "Аватарка из потока",
}
if req.ChatID == "" {
req.Login = u.GetFromLogin()
}
resp, err := bot.Files.SendImage(ctx, req)
Отправка галерей
Для отправки нескольких изображений в одном сообщении используется метод SendGallery. Аналогично одиночным файлам, поддерживаются пути к файлам и потоки. Вы также можете комбинировать их в одном запросе.
req := files.SendGalleryRequest{
ChatID: u.GetChatID(),
FilePaths: []string{
"image1.jpg",
"image2.png",
},
// Можно также передать Streams: []io.Reader{...}
Text: "Фотоотчет о проделанной работе",
}
if req.ChatID == "" {
req.Login = u.GetFromLogin()
}
resp, err := bot.Files.SendGallery(ctx, req)
Пересылка файлов по ID (Share)
Если файл уже был загружен на сервера Яндекса (например, вы его отправили ранее или получили от пользователя), вы можете переслать его с помощью file_id. Это работает намного быстрее, так как не требует повторной загрузки бинарных данных.
Доступные методы: ShareFile, ShareImage, ShareGallery.
Important
Специфика Яндекс Мессенджера для
ShareImageиShareGallery: При повторной отправке картинок поfile_idсервер Яндекса строго требует явного указания полейWidthиHeight(целые числа в пикселях). Если пропустить их, сервер вернет ошибку400 Bad Request.
Пример: ShareFile
req := files.ShareFileRequest{
ChatID: u.GetChatID(),
}
req.File.FileID = "existing_file_id"
resp, err := bot.Files.ShareFile(ctx, req)
Пример: ShareImage
req := files.ShareImageRequest{
ChatID: u.GetChatID(),
Text: "Посмотри на это фото!",
}
// Указываем ID ранее загруженного файла и обязательные размеры!
req.Image.FileID = "some_existing_file_id"
req.Image.Width = 800
req.Image.Height = 600
if req.ChatID == "" {
req.Login = u.GetFromLogin()
}
resp, err := bot.Files.ShareImage(ctx, req)
Скачивание файлов
Когда пользователь присылает файл, в объекте Update заполняется поле File. Вы можете получить содержимое этого файла с помощью метода GetFile.
Метод GetFile возвращает поток io.ReadCloser. Вы должны обязательно закрыть этот поток, вызвав Close(), чтобы избежать утечек ресурсов.
Пример: Скачивание входящего файла
// Проверяем, есть ли прикрепленный файл в сообщении
if update.File != nil && update.File.ID != "" {
// Получаем поток данных файла напрямую по FileID (io.ReadCloser)
stream, err := bot.Files.GetFileByID(ctx, update.File.ID)
if err != nil {
log.Println("Ошибка скачивания файла:", err)
return
}
// ОБЯЗАТЕЛЬНО закрываем поток!
defer stream.Close()
// Сохраняем на локальный диск
out, err := os.Create("downloaded_" + update.File.Name)
if err != nil {
return err
}
defer out.Close()
// Копируем данные из ответа в файл
if _, err := io.Copy(out, stream); err != nil {
log.Println("Ошибка сохранения файла:", err)
} else {
log.Println("Файл успешно скачан и сохранен!")
}
}
Архитектурные защиты (Under the Hood)
В библиотеке реализовано несколько важных механизмов безопасности и оптимизации для надежной работы с медиа:
-
Защита от OOM (Out Of Memory) при логировании: Внутренний middleware логирования HTTP-клиента (
logging_client.go) проверяет заголовокContent-Type. При отправке файлов используетсяmultipart/form-data. Логгер клонирует и читает тело запроса в память (io.ReadAll) только дляapplication/json. Это предотвращает аварийное завершение приложения из-за нехватки оперативной памяти при отправке больших файлов, так как их бинарное содержимое не попадает в буфер логгера. -
Защита от утечек файловых дескрипторов (Resource Leaks): При формировании
multipartзапросов на загрузку файлов (в методеMakeMultipartRequest), библиотека гарантирует безусловное закрытие всех переданных файловых потоков в самом начале обработки (через внутренний механизмdeferи коллекциюopenFiles). Даже если на раннем этапе подготовки запроса (например, при маршалинге JSON) произойдет ошибка и функция прервет выполнение, все открытые файлы и потоки будут гарантированно закрыты.