Расширьте облачное хранилище с помощью облачных функций

Вы можете запустить функцию в ответ на загрузку, обновление или удаление файлов и папок в Cloud Storage .

Примеры на этой странице основаны на тестовой функции, которая срабатывает при загрузке файлов изображений в Cloud Storage . Эта тестовая функция демонстрирует, как получить доступ к атрибутам события, как загрузить файл в экземпляр Cloud Functions и другие основные принципы обработки событий Cloud Storage .

Импортируйте необходимые модули.

Для начала импортируйте модуль, необходимый для обработки событий Cloud Storage :

Node.js

 const {onObjectFinalized} = require("firebase-functions/storage");

Python

 from firebase_functions import storage_fn

Для создания полноценного примера добавьте также зависимости для Firebase Admin SDK и инструментов обработки изображений:

Node.js

 const {initializeApp} = require("firebase-admin/app");
const {getStorage} = require("firebase-admin/storage");
const logger = require("firebase-functions/logger");
const path = require("path");

// library for image resizing
const sharp = /** @type {SharpConstructor} */ (require("sharp"));

initializeApp();

Python

 import io
import pathlib

from PIL import Image

from firebase_admin import initialize_app

initialize_app()
from firebase_admin import storage

Область применения функции Cloud Storage

Используйте следующий шаблон, чтобы ограничить область действия вашей функции определенным сегментом Cloud Storage и задать необходимые параметры:

Node.js

// scope handler to a specific bucket, using storage options parameter
exports.archivedopts = onObjectArchived({ bucket: "myBucket" }, (event) => {
  //…
});

Python

# Scope handler to a specific bucket using storage options parameter
@storage_fn.on_object_archived(bucket="myBucket")
def archived_bucket(event: storage_fn.CloudEvent[storage_fn.StorageObjectData]):
    # ...

В отличие от этого, пример функции генерации миниатюр ограничен областью действия стандартного сегмента проекта:

Node.js

exports.generateThumbnail = onObjectFinalized({cpu: 2}, async (event) => {
// ...
});

Python

@storage_fn.on_object_archived()
def generatethumbnail(event: storage_fn.CloudEvent[storage_fn.StorageObjectData]):
    # ...

Укажите местоположение функции

Несоответствие местоположений может привести к сбою развертывания. Кроме того, расстояние между местоположением сегмента Cloud Storage и местоположением функции может создавать значительную задержку в сети. Чтобы избежать подобных ситуаций, укажите местоположение функции таким образом, чтобы оно соответствовало местоположению сегмента/триггера одним из следующих способов:

  • Местоположение функции совпадает с местоположением триггера.
  • Местоположение функции находится внутри области срабатывания (когда область срабатывания является двойной/многорегиональной).
  • Функция может находиться в любом месте, если в качестве области запуска задан регион us-central1

Обработка событий Cloud Storage

Для обработки событий в Cloud Storage доступны следующие обработчики:

Node.js

  • Событие onObjectArchived отправляется только в том случае, если в корзине включено версионирование объектов . Это событие указывает на то, что активная версия объекта стала архивной, либо потому что она была заархивирована, либо потому что она была перезаписана при загрузке объекта с тем же именем.
  • onObjectDeleted отправляется, когда объект был безвозвратно удален. Это включает объекты, которые перезаписываются или удаляются в рамках конфигурации жизненного цикла хранилища. Для хранилищ с включенным версионированием объектов это сообщение не отправляется при архивации объекта (см. onArchive ), даже если архивация происходит с помощью метода storage.objects.delete .
  • Событие onObjectFinalized отправляется, когда в хранилище успешно создан новый объект (или новое поколение существующего объекта). Это включает копирование или перезапись существующего объекта. Неудачная загрузка не вызывает это событие.
  • onMetadataUpdated отправляется при изменении метаданных существующего объекта.

Python

  • on_object_archived Only sent when a bucket has enabled object versioning . This event indicates that the live version of an object has become an archived version, either because it was archived or because it was overwritten by the upload of an object of the same name.
  • on_object_deleted отправляется, когда объект был безвозвратно удален. Это включает объекты, которые перезаписываются или удаляются в рамках конфигурации жизненного цикла хранилища. Для хранилищ с включенным версионированием объектов это сообщение не отправляется при архивации объекта (см. onArchive ), даже если архивация происходит с помощью метода storage.objects.delete .
  • Событие on_object_finalized отправляется при успешном создании нового объекта (или нового поколения существующего объекта) в хранилище. Это включает копирование или перезапись существующего объекта. Неудачная загрузка не вызывает это событие.
  • on_metadata_updated — отправляется при изменении метаданных существующего объекта.

Доступ к атрибутам объекта Cloud Storage

Cloud Functions предоставляет доступ к ряду атрибутов объектов Cloud Storage , таких как размер объекта и тип содержимого обновляемого файла. Атрибут metageneration увеличивается при каждом изменении метаданных объекта. Для новых объектов значение metageneration равно 1 .

Node.js

const fileBucket = event.data.bucket; // Storage bucket containing the file.
const filePath = event.data.name; // File path in the bucket.
const contentType = event.data.contentType; // File content type.

Python

bucket_name = event.data.bucket
file_path = pathlib.PurePath(event.data.name)
content_type = event.data.content_type

В примере генерации миниатюр используются некоторые из этих атрибутов для определения случаев выхода из функции, когда она возвращает значение:

Node.js

// Exit if this is triggered on a file that is not an image.
if (!contentType.startsWith("image/")) {
  return logger.log("This is not an image.");
}
// Exit if the image is already a thumbnail.
const fileName = path.basename(filePath);
if (fileName.startsWith("thumb_")) {
  return logger.log("Already a Thumbnail.");
}

Python

# Exit if this is triggered on a file that is not an image.
if not content_type or not content_type.startswith("image/"):
    print(f"This is not an image. ({content_type})")
    return

# Exit if the image is already a thumbnail.
if file_path.name.startswith("thumb_"):
    print("Already a thumbnail.")
    return

Скачать, преобразовать и загрузить файл

В некоторых случаях загрузка файлов из Cloud Storage может быть необязательной. Однако для выполнения ресурсоемких задач, таких как создание миниатюрного изображения из файла, хранящегося в Cloud Storage , необходимо загрузить файлы в экземпляр функции — то есть в виртуальную машину, на которой выполняется ваш код.

Используя Cloud Functions совместно с программами обработки изображений, такими как sharp для Node.js и Pillow для Python, вы можете выполнять манипуляции с графическими файлами изображений. Ниже приведен пример создания миниатюры для загруженного файла изображения:

Node.js

/**
 * When an image is uploaded in the Storage bucket,
 * generate a thumbnail automatically using sharp.
 */
exports.generateThumbnail = onObjectFinalized({cpu: 2}, async (event) => {

  const fileBucket = event.data.bucket; // Storage bucket containing the file.
  const filePath = event.data.name; // File path in the bucket.
  const contentType = event.data.contentType; // File content type.

  // Exit if this is triggered on a file that is not an image.
  if (!contentType.startsWith("image/")) {
    return logger.log("This is not an image.");
  }
  // Exit if the image is already a thumbnail.
  const fileName = path.basename(filePath);
  if (fileName.startsWith("thumb_")) {
    return logger.log("Already a Thumbnail.");
  }

  // Download file into memory from bucket.
  const bucket = getStorage().bucket(fileBucket);
  const downloadResponse = await bucket.file(filePath).download();
  const imageBuffer = downloadResponse[0];
  logger.log("Image downloaded!");

  // Generate a thumbnail using sharp.
  const thumbnailBuffer = await sharp(imageBuffer).resize({
    width: 200,
    height: 200,
    withoutEnlargement: true,
  }).toBuffer();
  logger.log("Thumbnail created");

  // Prefix 'thumb_' to file name.
  const thumbFileName = `thumb_${fileName}`;
  const thumbFilePath = path.join(path.dirname(filePath), thumbFileName);

  // Upload the thumbnail.
  const metadata = {contentType: contentType};
  await bucket.file(thumbFilePath).save(thumbnailBuffer, {
    metadata: metadata,
  });
  return logger.log("Thumbnail uploaded!");
});

Загрузите файл во временную директорию вашего экземпляра Cloud Functions . В этом месте вы можете обработать файл по мере необходимости, а затем загрузить его в Cloud Storage . При выполнении асинхронных задач убедитесь, что вы возвращаете промис JavaScript в функции обратного вызова.

Python

@storage_fn.on_object_finalized()
def generatethumbnail(event: storage_fn.CloudEvent[storage_fn.StorageObjectData]):
    """When an image is uploaded in the Storage bucket, generate a thumbnail
    automatically using Pillow."""

    bucket_name = event.data.bucket
    file_path = pathlib.PurePath(event.data.name)
    content_type = event.data.content_type

    # Exit if this is triggered on a file that is not an image.
    if not content_type or not content_type.startswith("image/"):
        print(f"This is not an image. ({content_type})")
        return

    # Exit if the image is already a thumbnail.
    if file_path.name.startswith("thumb_"):
        print("Already a thumbnail.")
        return

    bucket = storage.bucket(bucket_name)

    image_blob = bucket.blob(str(file_path))
    image_bytes = image_blob.download_as_bytes()
    image = Image.open(io.BytesIO(image_bytes))

    image.thumbnail((200, 200))
    thumbnail_io = io.BytesIO()
    image.save(thumbnail_io, format="png")
    thumbnail_path = file_path.parent / pathlib.PurePath(f"thumb_{file_path.stem}.png")
    thumbnail_blob = bucket.blob(str(thumbnail_path))
    thumbnail_blob.upload_from_string(thumbnail_io.getvalue(), content_type="image/png")

Этот код создает миниатюру размером 200x200 пикселей для изображения, сохраненного во временной директории, а затем загружает ее обратно в Cloud Storage .