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 (veronArchive
), mesmo que o arquivamento ocorra pelo métodostorage.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 (veronArchive
), mesmo que o arquivamento ocorra pelo métodostorage.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.