Acionadores 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 nesta página são baseados em uma função de amostra que é acionada quando os arquivos de imagem são enviados para o Cloud Storage. Este exemplo de função demonstra como acessar atributos de eventos, como fazer download de um arquivo para uma instância do Cloud Functions e outros princípios básicos do tratamento de eventos do Cloud Storage.

Importe os módulos necessários

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

Node.js

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

Pitão

 from firebase_functions import storage_fn

Para criar o exemplo completo, adicione também as dependências do SDK Admin do Firebase e das ferramentas de processamento de imagem:

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

Pitão

 import io
import pathlib

from PIL import Image

from firebase_admin import initialize_app

initialize_app()
from firebase_admin import storage

Escopo de uma função do Cloud Storage

Use o padrão a seguir para definir o escopo da função para um intervalo específico do Cloud Storage e definir as opções desejadas:

Node.js

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

Pitão

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

Por outro lado, a função geradora de miniaturas de exemplo tem como escopo o bucket padrão do projeto:

Node.js

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

Pitão

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

Defina 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/gatilho de uma destas maneiras:

  • A localização da função é igual à localização do gatilho
  • A localização da função está dentro do local do trigger (quando a região do trigger é dupla/multi-região)
  • A função pode estar em qualquer local se a região de disparo estiver definida como us-central1

Lidar com eventos do Cloud Storage

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

Node.js

  • onObjectArchived Enviado somente quando um bucket ativou o versionamento de objetos . Este evento indica que a versão ativa de um objeto se tornou uma versão arquivada, seja porque foi arquivada ou porque foi substituída pelo upload de um objeto de mesmo nome.
  • onObjectDeleted Enviado quando um objeto foi 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 . Para buckets com controle de versão de objeto habilitado, isso não é enviado quando um objeto é arquivado (consulte onArchive ), mesmo que o arquivamento ocorra por meio do método storage.objects.delete .
  • onObjectFinalized Enviado quando um novo objeto (ou uma nova geração de um objeto existente) é criado com sucesso no bucket. Isto inclui copiar ou reescrever um objeto existente. Um upload com falha não aciona esse evento.
  • onMetadataUpdated Enviado quando os metadados de um objeto existente são alterados.

Pitão

  • on_object_archived Enviado somente quando um bucket ativou o versionamento de objetos . Este evento indica que a versão ativa de um objeto se tornou uma versão arquivada, seja porque foi arquivada ou porque foi substituída pelo upload de um objeto de mesmo nome.
  • on_object_deleted Enviado quando um objeto foi 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 . Para buckets com controle de versão de objeto habilitado, isso não é enviado quando um objeto é arquivado (consulte onArchive ), mesmo que o arquivamento ocorra por meio do método storage.objects.delete .
  • on_object_finalized Enviado quando um novo objeto (ou uma nova geração de um objeto existente) é criado com sucesso no bucket. Isto inclui copiar ou reescrever um objeto existente. Um upload com falha não aciona esse evento.
  • on_metadata_updated Enviado quando os metadados de um objeto existente são alterados.

Acessar atributos de objetos do Cloud Storage

O Cloud Functions expõe vários atributos de objetos do Cloud Storage, como o tamanho do objeto e o tipo de conteúdo do arquivo atualizado. O atributo metageneration é incrementado sempre que há uma alteração nos metadados do objeto. Para novos objetos, o valor 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.

Pitão

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

O exemplo de geração de miniaturas usa alguns destes atributos para detectar casos de saída nos quais 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.");
}

Pitão

# 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

Baixe, transforme e carregue um arquivo

Em alguns casos, pode não ser necessário baixar arquivos do Cloud Storage. No entanto, para realizar tarefas intensivas, como gerar uma imagem em miniatura de um arquivo armazenado no Cloud Storage, você precisa fazer download dos arquivos para a instância de funções, ou seja, a máquina virtual que executa seu código.

Usando o Cloud Functions junto com programas de processamento de imagens como sharp para Node.js e Pillow para Python, você pode realizar manipulações em arquivos de imagens gráficas. A seguir está um exemplo de como criar uma imagem em miniatura para um arquivo de imagem carregado:

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 download do arquivo em um diretório temporário na instância do Cloud Functions. Nesse local, você pode processar o arquivo conforme necessário e depois fazer upload para o Cloud Storage. Ao executar tarefas assíncronas, certifique-se de retornar uma promessa JavaScript em seu retorno de chamada.

Pitão

@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 200 x 200 para a imagem salva em um diretório temporário e depois faz upload dela de volta para o Cloud Storage.