مشغِّلات Cloud Storage

يمكنك تفعيل دالة استجابةً لتحميل الملفات والمجلدات أو تعديلها أو حذفها في 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 = 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 لا يتم إرسال هذا الحدث إلا عندما تكون ميزة تتبُّع إصدارات العناصر مفعّلة في المجموعة. يشير هذا الحدث إلى أنّ الإصدار المباشر من أحد العناصر أصبح إصدارًا مؤرشفًا، إما لأنّه تم أرشفته أو لأنّه تم استبداله بتحميل عنصر يحمل الاسم نفسه.
  • onObjectDeleted يتم إرسال هذا الحدث عند حذف عنصر نهائيًا. يشمل ذلك العناصر التي يتم استبدالها أو حذفها كجزء من إعدادات دورة حياة الحزمة. بالنسبة إلى المجموعات التي تكون فيها ميزة تتبُّع إصدارات العناصر مفعّلة، لا يتم إرسال هذا الحدث عند أرشفة عنصر (راجِع onArchive)، حتى إذا حدثت الأرشفة من خلال طريقة storage.objects.delete.
  • onObjectFinalized يتم إرسال هذا الحدث عند إنشاء عنصر جديد (أو إصدار جديد من عنصر حالي) بنجاح في المجموعة. ويشمل ذلك نسخ عنصر حالي أو إعادة كتابته. لا يؤدي التحميل غير الناجح إلى تفعيل هذا الحدث.
  • onMetadataUpdated يتم إرسال هذا الحدث عند تغيير بيانات وصفية لعنصر حالي.

Python

  • 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.

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 في معاودة الاتصال.

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

ينشئ هذا الرمز صورة مصغّرة بحجم 200×200 للصورة المحفوظة في دليل مؤقت، ثم يعيد تحميلها إلى Cloud Storage.