אפשר להפעיל פונקציה בתגובה להעלאה, לעדכון או למחיקה של קבצים ותיקיות ב-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 {typeof import("sharp")} */ (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מתרחש רק אם האפשרות object versioning מופעלת בקטגוריה. האירוע הזה מציין שהגרסה הפעילה של אובייקט הועברה לארכיון – בגלל שהיא הועברה לארכיון או כי העלאה של אובייקט באותו שם החליפה את האובייקט הקיים. onObjectDeletedמתרחש כשאובייקט נמחק באופן סופי. זה כולל גם אובייקטים שמוחלפים או נמחקים כחלק מהגדרות מחזור החיים של הקטגוריה. בקטגוריות שבהן מופעלת האפשרות object versioning, האירוע הזה לא מתרחש כשאובייקט מועבר לארכיון (ראוonArchive), גם אם ההעברה לארכיון מתבצעת באמצעות השיטהstorage.objects.delete.onObjectFinalizedמתרחש כשנוצר אובייקט חדש בקטגוריה (או כשאובייקט קיים נוצר מחדש). זה כולל העתקה או שכתוב של אובייקט קיים. האירוע הזה לא יופעל במקרה של העלאה שנכשלה.onMetadataUpdatedמתרחש כשהמטא-נתונים של אובייקט קיים משתנים.
Python
-
on_object_archivedמתרחש רק אם האפשרות object versioning מופעלת בקטגוריה. האירוע הזה מציין שהגרסה הפעילה של אובייקט הועברה לארכיון – בגלל שהיא הועברה לארכיון או כי העלאה של אובייקט באותו שם החליפה את האובייקט הקיים. on_object_deletedמתרחש כשאובייקט נמחק באופן סופי. זה כולל גם אובייקטים שמוחלפים או נמחקים כחלק מהגדרות מחזור החיים של הקטגוריה. בקטגוריות שבהן מופעלת האפשרות object versioning, האירוע הזה לא מתרחש כשאובייקט מועבר לארכיון (ראו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 promise.
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.