Gatilhos do Cloud Storage


Você pode acionar uma função em resposta ao upload, à atualização ou à exclusão de arquivos e pastas no Cloud Storage.

Os exemplos desta página são baseados em uma função de amostra acionada com o upload de arquivos de imagem no Cloud Storage. Essa função demonstra como acessar atributos de eventos, como fazer o download de um arquivo para uma instância do Cloud Functions e outros princípios básicos do gerenciamento de eventos do Cloud Storage.

Importar os módulos necessários

Para começar, importe o módulo necessário para processar eventos do Cloud Storage:

Node.js

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

Python (pré-lançamento)

 from firebase_functions import storage_fn

Para criar a amostra completa, adicione também as dependências do SDK Admin do Firebase e das ferramentas de processamento de imagens:

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();

Python (pré-lançamento)

 import io
import pathlib

from PIL import Image

from firebase_admin import initialize_app

initialize_app()
from firebase_admin import storage

Definir o escopo de uma função do Cloud Storage

Use o seguinte padrão para definir o escopo da sua função para um bucket específico do Cloud Storage e definir as opções pretendidas:

Node.js

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

Python (pré-lançamento)

# 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]):
    # ...

Em contrapartida, a função de gerador de miniaturas neste exemplo é dimensionada de acordo com o bucket padrão do projeto:

Node.js

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

Python (pré-lançamento)

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

Definir o local da função

Uma incompatibilidade entre locais pode resultar em falha na implantação. Além disso, a distância entre o local de um bucket do Cloud Storage e o local da função pode criar uma latência de rede significativa. Para evitar essas situações, especifique o local da função para que corresponda ao local do bucket/acionador de uma das seguintes maneiras:

  • O local da função é igual ao local do gatilho
  • O local da função está dentro do local do gatilho (quando a região do gatilho é dual/multirregional)
  • A função poderá estar em qualquer local se a região do gatilho estiver definida como us-central1

Processar eventos do Cloud Storage

Estes gerenciadores para responder a eventos do Cloud Storage estão disponíveis:

Node.js

  • onObjectArchived: enviado apenas depois que o controle de versões do objeto é ativado no bucket. Este evento indica que a versão ativa de um objeto se tornou uma versão arquivada, podendo ter sido arquivada ou substituída pelo upload de um objeto de mesmo nome.
  • onObjectDeleted: enviado quando um objeto é excluído permanentemente. Isso inclui objetos que são substituídos ou excluídos como parte da configuração do ciclo de vida do bucket. Nos buckets com o controle de versões de objetos ativado, ele não é enviado quando um objeto é arquivado (ver onArchive), mesmo que o arquivamento ocorra pelo método storage.objects.delete.
  • onObjectFinalized: enviado quando um novo objeto ou nova geração de um objeto é criada com sucesso no bucket. Isso inclui copiar ou reescrever um objeto. Um upload com falha não aciona esse evento.
  • onMetadataUpdated: enviado quando os metadados de um objeto são modificados.

Python (pré-lançamento)

  • on_object_archived: enviado apenas depois que o controle de versões do objeto é ativado no bucket. Este evento indica que a versão ativa de um objeto se tornou uma versão arquivada, podendo ter sido arquivada ou substituída pelo upload de um objeto de mesmo nome.
  • on_object_deleted: enviado quando um objeto é excluído permanentemente. Isso inclui objetos que são substituídos ou excluídos como parte da configuração do ciclo de vida do bucket. Nos buckets com o controle de versões de objetos ativado, ele não é enviado quando um objeto é arquivado (ver onArchive), mesmo que o arquivamento ocorra pelo método storage.objects.delete.
  • on_object_finalized: enviado quando um novo objeto ou nova geração de um objeto é criada com sucesso no bucket. Isso inclui copiar ou reescrever um objeto. Um upload com falha não aciona esse evento.
  • on_metadata_updated: enviado quando os metadados de um objeto são alterados.

Acessar atributos de objetos do Cloud Storage

O Cloud Functions fornece ao arquivo atualizado diversos atributos de objetos do Cloud Storage, como o tamanho e o tipo de conteúdo do arquivo atualizado. O atributo metageneration será incrementado sempre que houver uma alteração nos metadados do objeto. Para novos objetos, o valor de 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 (pré-lançamento)

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

A amostra de geração de miniaturas usa alguns desses atributos para detectar casos de saída em que a função retorna:

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 (pré-lançamento)

# 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

Fazer o download, transformar e fazer upload de um arquivo

Para alguns casos, pode não ser necessário fazer o download de arquivos do Cloud Storage. Mas, para executar tarefas intensivas, como gerar uma imagem de miniatura usando um arquivo armazenado no Cloud Storage, é necessário fazer o download dos arquivos para a instância das funções, ou seja, para a máquina virtual que executa seu código.

Ao usar o Cloud Functions com programas de processamento de imagens como o sharp para Node.js e a Pillow para Python, é possível fazer manipulações em arquivos de imagens gráficas. Veja abaixo um exemplo de como criar uma imagem em miniatura para um arquivo de imagem:

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

Faça o download do arquivo para um diretório temporário na sua instância do Cloud Functions. Nesse local, é possível processar o arquivo conforme necessário e depois fazer o upload para o Cloud Storage. Ao executar tarefas assíncronas, retorne uma promessa de JavaScript na callback.

Python (pré-lançamento)

@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"
    )


Esse código cria uma miniatura de 200x200 para a imagem salva em um diretório temporário e, em seguida, faz o upload dela de volta ao Cloud Storage.