يمكنك تشغيل دالة استجابةً لتحميل الملفات والمجلدات أو تعديلها أو حذفها في Cloud Storage.
تستند الأمثلة الواردة في هذه الصفحة إلى وظيفة نموذجية يتم تشغيلها عند تحميل ملفات الصور إلى Cloud Storage. توضّح هذه الدالة النموذجية كيفية الوصول إلى سمات الأحداث، وكيفية تنزيل ملف إلى مثيل Cloud Functions، وغير ذلك من الأساسيات المتعلقة بمعالجة أحداث Cloud Storage.
استيراد الوحدات المطلوبة
للبدء، استورِد الوحدة المطلوبة لمعالجة أحداث Cloud Storage:
const {onObjectFinalized} = require("firebase-functions/v2/storage");
from firebase_functions import storage_fn
لإنشاء العيّنة الكاملة، أضِف أيضًا التبعيات الخاصة بأدوات Firebase Admin SDK ومعالجة الصور:
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 معيّنة وضبط أي خيارات مطلوبة:
// 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]):
# ...
في المقابل، يتم تحديد نطاق دالة إنشاء الصور المصغّرة في المثال على مستوى الحزمة التلقائية للمشروع:
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 التالية:
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
.
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
يستخدم نموذج إنشاء الصور المصغّرة بعض هذه السمات لرصد حالات الخروج التي تعرض فيها الدالة ما يلي:
// 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،
يمكنك إجراء
تعديلات على ملفات الصور الرسومية. في ما يلي مثال على كيفية إنشاء صورة مصغّرة لملف صورة تم تحميله:
/**
* 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")
ينشئ هذا الرمز صورة مصغّرة بحجم 200×200 للصورة المحفوظة في دليل مؤقت، ثم يحمّلها مرة أخرى إلى Cloud Storage.