Триггеры облачного хранилища


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

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

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

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

Node.js

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

Питон

 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 = require("sharp");

initializeApp();

Питон

 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
export archivedopts = onObjectArchived({ bucket: "myBucket" }, (event) => {
  //…
});

Питон

# 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) => {
// ...
});

Питон

@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 Отправляется при изменении метаданных существующего объекта.

Питон

  • on_object_archived Отправляется только в том случае, если в сегменте включено управление версиями объекта . Это событие указывает на то, что действующая версия объекта стала архивной версией либо потому, что она была заархивирована, либо потому, что она была перезаписана при загрузке объекта с тем же именем.
  • 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.

Питон

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.");
}

Питон

# 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 в обратном вызове.

Питон

@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 .