مشغلات التخزين السحابي


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

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

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

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

Node.js

 const {onObjectFinalized} = require("firebase-functions/v2/storage");

بايثون

 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();

بايثون

 import io
import pathlib

from PIL import Image

from firebase_admin import initialize_app

initialize_app()
from firebase_admin import storage

نطاق وظيفة التخزين السحابي

استخدم النمط التالي لتوسيع نطاق وظيفتك إلى مجموعة تخزين سحابية محددة وتعيين أي خيارات مطلوبة:

Node.js

// 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]):
    # ...

على النقيض من ذلك، يتم تحديد نطاق وظيفة إنشاء الصور المصغرة في المجموعة الافتراضية للمشروع:

Node.js

exports.generateThumbnail = onObjectFinalized({cpu: 2}, async (event) => {
// ...
});

بايثون

@storage_fn.on_object_archived()
def generatethumbnail(event: storage_fn.CloudEvent[storage_fn.StorageObjectData]):
    # ...

ضبط موقع الوظيفة

يمكن أن يؤدي عدم التطابق بين المواقع إلى فشل النشر. كما أن المسافة بين موقع حاوية التخزين السحابي وموقع الوظيفة يمكن أن تؤدي إلى زمن انتقال كبير للشبكة. لتجنب هذه المواقف، حدد موقع الوظيفة بحيث يتطابق مع موقع الحاوية/المشغل بإحدى الطرق التالية:

  • موقع الوظيفة هو نفس موقع الزناد
  • موقع الوظيفة داخل موقع الزناد (عندما تكون منطقة الزناد منطقة مزدوجة/متعددة)
  • قد تكون الوظيفة في أي مكان إذا تم ضبط منطقة التشغيل على us-central1

التعامل مع أحداث التخزين السحابي

تتوفر هذه المعالجات للاستجابة لأحداث Cloud Storage:

Node.js

  • يتم إرسال 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 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.

بايثون

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.");
}

بايثون

# 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 for Node.js و Pillow for 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 في رد الاتصال الخاص بك.

بايثون

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