مشغِّلات Cloud Storage


يمكنك تشغيل دالة استجابةً لتحميل الملفات والمجلدات أو تعديلها أو حذفها في Cloud Storage.

تستند الأمثلة الواردة في هذه الصفحة إلى نموذج دالة يتم تفعيلها عند تحميل ملفّات الصور إلى Cloud Storage. يوضّح نموذج الدالة هذا كيفية الوصول إلى سمات الحدث وكيفية تنزيل ملف إلى مثيل Cloud Functions وغيرها من الأساسيات المتعلّقة بمعالجة أحداث Cloud Storage.

استيراد الوحدات المطلوبة

للبدء، استورِد الوحدة المطلوبة لمعالجة أحداث Cloud Storage :

Node.js

 const {onObjectFinalized} = require("firebase-functions/v2/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
export 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 للغة بايثون، يمكنك إجراء عمليات معالجة على ملفات الصور الرسومية. في ما يلي مثال على كيفية إنشاء صورة مصغّرة لملف صورة تم تحميله:

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.