مشغِّلات 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 للغة 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. فعندما بأداء مهام غير متزامنة، فتأكد من عرض وعد جافا سكريبت في معاودة الاتصال.

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.