Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Работа с файлами и медиа

Библиотека предоставляет обширные возможности для работы с файлами, изображениями и галереями. Вы можете отправлять локальные файлы, передавать потоки данных в реальном времени, а также скачивать файлы и пересылать их по идентификаторам (file_id).

Отправка файлов и изображений

Для отправки медиафайлов используются методы SendFile и SendImage. Вы можете передать файл двумя способами:

  1. Через путь к локальному файлу (FilePath) — библиотека сама откроет файл и подготовит его к отправке.
  2. Через поток (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)

В библиотеке реализовано несколько важных механизмов безопасности и оптимизации для надежной работы с медиа:

  1. Защита от OOM (Out Of Memory) при логировании: Внутренний middleware логирования HTTP-клиента (logging_client.go) проверяет заголовок Content-Type. При отправке файлов используется multipart/form-data. Логгер клонирует и читает тело запроса в память (io.ReadAll) только для application/json. Это предотвращает аварийное завершение приложения из-за нехватки оперативной памяти при отправке больших файлов, так как их бинарное содержимое не попадает в буфер логгера.

  2. Защита от утечек файловых дескрипторов (Resource Leaks): При формировании multipart запросов на загрузку файлов (в методе MakeMultipartRequest), библиотека гарантирует безусловное закрытие всех переданных файловых потоков в самом начале обработки (через внутренний механизм defer и коллекцию openFiles). Даже если на раннем этапе подготовки запроса (например, при маршалинге JSON) произойдет ошибка и функция прервет выполнение, все открытые файлы и потоки будут гарантированно закрыты.