أعد استخدام كود Cloud Functions الخاص بك كملحق Firebase

1. قبل أن تبدأ

ينفذ ملحق Firebase مهمة محددة أو مجموعة من المهام استجابة إما لطلبات HTTP أو تشغيل الأحداث من منتجات Firebase وGoogle الأخرى مثل Firebase Cloud Messaging أو Cloud Firestore أو Pub/Sub.

ما سوف تبنيه

في هذا الدرس التطبيقي حول التعليمات البرمجية، ستقوم بإنشاء ملحق Firebase للتقطيع الجغرافي . بمجرد النشر، يقوم الامتداد الخاص بك بعد ذلك بتحويل إحداثيات X وY إلى تجزئة جغرافية استجابةً لأحداث Firestore أو من خلال استدعاءات الوظائف القابلة للاستدعاء. يمكن استخدام هذا كبديل لتنفيذ مكتبة Geofire عبر جميع الأنظمة الأساسية المستهدفة لتخزين البيانات، مما يوفر لك الوقت.

يظهر امتداد Geohash في وحدة تحكم Firebase

ما ستتعلمه

  • كيفية أخذ رمز Cloud Functions الموجود وتحويله إلى ملحق Firebase قابل للتوزيع
  • كيفية إعداد ملف extension.yaml
  • كيفية تخزين السلاسل الحساسة (مفاتيح API) في الامتداد
  • كيفية السماح لمطوري الامتداد بتكوينه ليناسب احتياجاتهم
  • كيفية اختبار ونشر الامتداد

ماذا ستحتاج

  • Firebase CLI (التثبيت وتسجيل الدخول)
  • حساب Google، مثل حساب Gmail
  • Node.js و npm
  • بيئة التطوير المفضلة لديك

2. قم بالإعداد

احصل على الرمز

كل ما تحتاجه لهذا الامتداد موجود في GitHub repo. للبدء، احصل على الكود وافتحه في بيئة التطوير المفضلة لديك.

  1. قم بفك ضغط الملف المضغوط الذي تم تنزيله.
  2. لتثبيت التبعيات المطلوبة، افتح الوحدة الطرفية في دليل functions وقم بتشغيل أمر npm install .

قم بإعداد Firebase

يشجع هذا الدرس التطبيقي حول البرمجة بشدة على استخدام محاكيات Firebase. إذا كنت تريد تجربة تطوير الملحقات باستخدام مشروع Firebase حقيقي، فراجع إنشاء مشروع Firebase . يستخدم هذا الدرس التطبيقي للبرمجة وظائف السحابة، لذا إذا كنت تستخدم مشروع Firebase حقيقيًا بدلاً من المحاكيات، فستحتاج إلى الترقية إلى خطة تسعير Blaze .

هل تريد التخطي للأمام؟

يمكنك تنزيل نسخة مكتملة من Codelab. إذا واجهتك مشكلة على طول الطريق أو إذا كنت تريد رؤية الشكل الذي يبدو عليه الامتداد المكتمل، فراجع فرع codelab-end لمستودع GitHub أو قم بتنزيل الملف المضغوط المكتمل.

3. قم بمراجعة الكود

  • افتح ملف index.ts من الملف المضغوط. لاحظ أنه يحتوي على إعلانين للوظائف السحابية بداخله.

ماذا تفعل هذه الوظائف؟

تُستخدم هذه الوظائف التجريبية في عملية Geohashing. يأخذون زوجًا إحداثيًا ويحولونه إلى تنسيق مُحسّن للاستعلامات الجغرافية في Firestore. تحاكي الوظائف استخدام استدعاء واجهة برمجة التطبيقات (API) حتى تتمكن من معرفة المزيد حول التعامل مع أنواع البيانات الحساسة في الامتدادات. لمزيد من المعلومات، راجع الوثائق المتعلقة بتشغيل الاستعلامات الجغرافية على البيانات في Firestore .

ثوابت الدالة

يتم الإعلان عن الثوابت مبكرًا، في الجزء العلوي من ملف index.ts . تتم الإشارة إلى بعض هذه الثوابت في مشغلات الامتداد المحددة.

Index.ts

import {firestore} from "firebase-functions";
import {initializeApp} from "firebase-admin/app";
import {GeoHashService, ResultStatusCode} from "./fake-geohash-service";
import {onCall} from "firebase-functions/v1/https";
import {fieldValueExists} from "./utils";

const documentPath = "users/{uid}";
const xField = "xv";
const yField = "yv";
const apiKey = "1234567890";
const outputField = "hash";

initializeApp();

const service = new GeoHashService(apiKey);

مشغل الحريق

تبدو الوظيفة الأولى في ملف index.ts كما يلي:

Index.ts

export const locationUpdate = firestore.document(documentPath)
  .onWrite((change) => {
    // item deleted
    if (change.after == null) {
      return 0;
    }
    // double check that both values exist for computation
    if (
      !fieldValueExists(change.after.data(), xField) ||
      !fieldValueExists(change.after.data(), yField)
    ) {
      return 0;
    }
    const x: number = change.after.data()![xField];
    const y: number = change.after.data()![yField];
    const hash = service.convertToHash(x, y);
    // This is to check whether the hash value has changed. If
    // it hasn't, you don't want to write to the document again as it
    // would create a recursive write loop.
    if (fieldValueExists(change.after.data(), outputField)
      && change.after.data()![outputField] == hash) {
      return 0;
    }
    return change.after.ref
      .update(
        {
          [outputField]: hash.hash,
        }
      );
  });

هذه الوظيفة عبارة عن مشغل Firestore . عند حدوث حدث كتابة في قاعدة البيانات، تتفاعل الوظيفة مع هذا الحدث من خلال البحث عن حقل xv وحقل yv ، وإذا كان كلا هذين الحقلين موجودين، فإنها تحسب Geohash وتكتب الإخراج إلى موقع إخراج مستند محدد. يتم تعريف مستند الإدخال بواسطة ثابت users/{uid} ، مما يعني أن الوظيفة تقرأ كل مستند مكتوب إلى users/ المجموعة ثم تقوم بمعالجة Geohash لتلك المستندات. ثم يقوم بإخراج التجزئة إلى حقل التجزئة في نفس المستند.

وظائف قابلة للاستدعاء

تبدو الوظيفة التالية في ملف index.ts كما يلي:

Index.ts

export const callableHash = onCall((data, context) => {
  if (context.auth == undefined) {
    return {error: "Only authorized users are allowed to call this endpoint"};
  }
  const x = data[xField];
  const y = data[yField];
  if (x == undefined || y == undefined) {
    return {error: "Either x or y parameter was not declared"};
  }
  const result = service.convertToHash(x, y);
  if (result.status != ResultStatusCode.ok) {
    return {error: `Something went wrong ${result.message}`};
  }
  return {result: result.hash};
});

لاحظ وظيفة onCall . ويشير إلى أن هذه الوظيفة هي وظيفة قابلة للاستدعاء ، والتي يمكن استدعاؤها من داخل رمز تطبيق العميل الخاص بك. تأخذ هذه الوظيفة القابلة للاستدعاء معلمات x و y وتقوم بإرجاع Geohash. على الرغم من أن هذه الوظيفة لن يتم استدعاؤها مباشرة في هذا الدرس التطبيقي حول التعليمات البرمجية، إلا أنها مدرجة هنا كمثال لشيء يجب تهيئته في ملحق Firebase.

4. قم بإعداد ملف Extension.yaml

الآن بعد أن عرفت ما يفعله كود وظائف السحابة في ملحقك، فأنت جاهز لتجميعه للتوزيع. يأتي كل ملحق Firebase مزودًا بملف extension.yaml الذي يصف ما يفعله الامتداد وكيف يتصرف.

يتطلب ملف extension.yaml بعض البيانات الوصفية الأولية حول الامتداد الخاص بك. تساعدك كل خطوة من الخطوات التالية على فهم معنى جميع الحقول وسبب حاجتك إليها.

  1. قم بإنشاء ملف extension.yaml في الدليل الجذر للمشروع الذي قمت بتنزيله مسبقًا. ابدأ بإضافة ما يلي:
name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

يتم استخدام اسم الامتداد كأساس لمعرف مثيل الامتداد (يمكن للمستخدمين تثبيت مثيلات متعددة للامتداد، كل منها بمعرف خاص بها). يقوم Firebase بعد ذلك بإنشاء اسم حسابات خدمة الامتداد والموارد الخاصة بالامتداد باستخدام معرف المثيل هذا. يشير رقم الإصدار إلى إصدار الامتداد الخاص بك. يجب أن يتبع الإصدار الدلالي ، وتحتاج إلى تحديثه كلما قمت بإجراء تغييرات على وظيفة الامتداد. يتم استخدام إصدار مواصفات الامتداد لتحديد مواصفات امتدادات Firebase التي يجب اتباعها، وفي هذه الحالة، يتم استخدام v1beta .

  1. أضف بعض التفاصيل سهلة الاستخدام إلى ملف YAML:
...

displayName: Latitude and longitude to GeoHash converter
description: A converter for changing your Latitude and longitude coordinates to geohashes.

يعد اسم العرض تمثيلاً مألوفًا لاسم ملحقك عندما يتفاعل المطورون مع ملحقك. يقدم الوصف نظرة عامة موجزة عما يفعله الامتداد. عندما يتم نشر الامتداد على Extensions.dev ، يبدو كما يلي:

امتداد Geohash Converter كما هو موضح في Extensions.dev

  1. حدد الترخيص للكود الموجود في ملحقك.
...

license: Apache-2.0  # The license you want for the extension
  1. وضح من كتب الامتداد وما إذا كان يلزم الفوترة لتثبيته أم لا:
...

author:
  authorName: AUTHOR_NAME
  url: https://github.com/Firebase

billingRequired: true

يتم استخدام قسم author للسماح للمستخدمين بمعرفة من يجب عليهم التواصل معه في حالة مواجهتهم مشكلات مع الامتداد أو رغبتهم في الحصول على مزيد من المعلومات حوله. تعتبر billingRequired معلمة مطلوبة ويجب ضبطها على true نظرًا لأن جميع الملحقات تعتمد على Cloud Functions، الأمر الذي يتطلب خطة Blaze.

يغطي هذا الحد الأدنى لعدد الحقول المطلوبة في ملف extension.yaml لتحديد هذا الامتداد. لمزيد من التفاصيل حول معلومات التعريف الأخرى التي يمكنك تحديدها في الامتداد، راجع الوثائق .

5. قم بتحويل كود وظائف السحابة إلى مورد ملحقات

مورد الامتداد هو عنصر ينشئه Firebase في المشروع أثناء تثبيت الامتداد. يمتلك الامتداد بعد ذلك هذه الموارد ولديه حساب خدمة محدد يعمل عليها. في هذا المشروع، هذه الموارد هي وظائف السحابة، والتي يجب تعريفها في ملف extension.yaml لأن الامتداد لن يقوم تلقائيًا بإنشاء موارد من التعليمات البرمجية في مجلد الوظائف. إذا لم يتم الإعلان عن وظائف السحابة الخاصة بك بشكل صريح كمورد، فلا يمكن نشرها عند نشر الامتداد.

موقع النشر المحدد من قبل المستخدم

  1. اسمح للمستخدم بتحديد الموقع الذي يريد نشر هذا الامتداد فيه وتحديد ما إذا كان من الأفضل استضافة الامتداد بالقرب من المستخدمين النهائيين أو بالقرب من قاعدة البيانات الخاصة به. في ملف extension.yaml ، قم بتضمين خيار اختيار الموقع.

Extension.yaml

أنت الآن جاهز لكتابة التكوين لمورد الوظيفة.

  1. في الملف extension.yaml ، قم بإنشاء كائن مورد لوظيفة locationUpdate . قم بإلحاق ما يلي بالملف extension.yaml :
resources:
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}

يمكنك تحديد name كاسم الوظيفة المحددة في ملف index.ts الخاص بالمشروع. أنت تحدد type الوظيفة التي يتم نشرها، والتي يجب أن تكون دائمًا firebaseextensions.v1beta.function في الوقت الحالي. ثم، يمكنك تحديد properties هذه الوظيفة. الخاصية الأولى التي تحددها هي eventTrigger المرتبطة بهذه الوظيفة. لعكس ما يدعمه الامتداد حاليًا، يمكنك استخدام eventType of providers/cloud.firestore/eventTypes/document.write ، الموجود في Write Cloud Functions لوثائق الامتداد الخاصة بك . يمكنك تحديد resource كموقع للمستندات. نظرًا لأن هدفك الحالي هو عكس ما هو موجود في الكود، فإن مسار المستند يستمع إلى users/{uid} ، مع موقع قاعدة البيانات الافتراضي الذي يسبقه.

  1. يحتاج الامتداد إلى أذونات القراءة والكتابة لقاعدة بيانات Firestore. في نهاية ملف extension.yaml ، حدد أدوار IAM التي يجب أن يكون للامتداد حق الوصول إليها للعمل مع قاعدة البيانات في مشروع Firebase الخاص بالمطور.
roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

يأتي دور datastore.user من قائمة أدوار IAM المدعومة للامتدادات . وبما أن الامتداد سيكون للقراءة والكتابة، فإن دور datastore.user مناسب هنا.

  1. يجب إضافة الدالة القابلة للاستدعاء أيضًا. في الملف extension.yaml ، قم بإنشاء مورد جديد ضمن خاصية الموارد. هذه الخصائص خاصة بوظيفة قابلة للاستدعاء:
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

على الرغم من أن المورد السابق استخدم eventTrigger ، إلا أنك هنا تستخدم httpsTrigger ، والذي يغطي كلاً من الوظائف القابلة للاستدعاء ووظائف HTTPS.

فحص الكود

لقد كان ذلك يتطلب الكثير من التكوين لجعل extension.yaml الخاص بك يطابق كل ما يتم تنفيذه بواسطة الكود الموجود في ملف index.ts الخاص بك. هذا هو الشكل الذي يجب أن يبدو عليه ملف extension.yaml المكتمل في الوقت الحالي:

Extension.yaml

name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

displayName: Latitude and Longitude to GeoHash converter
description: A converter for changing your Latitude and Longitude coordinates to geohashes.

license: Apache-2.0  # The license you want for the extension

author:
  authorName: Sparky
  url: https://github.com/Firebase

billingRequired: true

resources:
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

التحقق من الحالة

في هذه المرحلة، تم إعداد الأجزاء الوظيفية الأولية للامتداد، بحيث يمكنك تجربته بالفعل باستخدام محاكيات Firebase!

  1. إذا لم تكن قد قمت بذلك بالفعل، فاتصل بـ npm run build في مجلد الوظائف الخاص بمشروع الإضافات الذي تم تنزيله.
  2. قم بإنشاء دليل جديد على نظامك المضيف وقم بتوصيل هذا الدليل بمشروع Firebase الخاص بك باستخدام firebase init .
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
    This command creates a `firebase.json` file in the directory. In the following steps, you push the configuration specified in this file to Firebase.
  1. من نفس الدليل، قم بتشغيل firebase ext:install . استبدل /path/to/extension بالمسار المطلق للدليل الذي يحتوي على ملف extension.yaml الخاص بك.
firebase ext:install /path/to/extension
    This command does two things:
  • ويطالبك بتحديد التكوين لمثيل الامتداد، ويقوم بإنشاء ملف *.env يحتوي على معلومات التكوين للمثيل.
  • يقوم بإضافة مثيل الامتداد إلى قسم extensions في firebase.json الخاص بك. يعمل هذا كخريطة لمعرف المثيل لإصدار الملحق.
  • نظرًا لأنك تنشر المشروع محليًا، يمكنك تحديد رغبتك في استخدام ملف محلي بدلاً من Google Cloud Secret Manager.

لقطة شاشة لعملية تثبيت الامتداد توضح أنه يتم استخدام الملف المحلي للأسرار عند تثبيت هذا الامتداد

  1. ابدأ تشغيل محاكيات Firebase بالتكوين الجديد:
firebase emulators:start
  1. بعد تشغيل emulators:start ، انتقل إلى علامة التبويب Firestore في عرض الويب الخاص بالمحاكيات.
  2. أضف مستندًا إلى مجموعة users باستخدام حقل رقم xv وحقل رقم yv .

يظهر مربع حوار في Firebase Emulators لبدء مجموعة بمعرف المجموعة الذي يحتوي على العبارة

  1. إذا نجحت في تثبيت الامتداد، فسيقوم الامتداد بإنشاء حقل جديد يسمى hash في المستند.

مجموعة المستخدمين مع مستند المستخدم الذي يحتوي على حقل xv، وyv، وتجزئة.

تنظيف لتجنب الصراعات

  • بمجرد الانتهاء من الاختبار، قم بإلغاء تثبيت الامتداد — ستقوم بتحديث رمز الامتداد ولا تريد أن يتعارض مع الامتداد الحالي لاحقًا.

تسمح الإضافات بتثبيت إصدارات متعددة من نفس الإضافة مرة واحدة، لذلك من خلال إلغاء التثبيت، فإنك تضمن عدم وجود تعارضات مع الإضافة المثبتة مسبقًا.

firebase ext:uninstall geohash-ext

يعمل الحل الحالي، ولكن كما ذكرنا في بداية المشروع، يوجد مفتاح API مشفر لمحاكاة الاتصال بالخدمة. كيف يمكنك استخدام مفتاح API الخاص بالمستخدم النهائي بدلاً من المفتاح الذي تم توفيره في الأصل؟ تابع القراءة لمعرفة ذلك.

6. اجعل مستخدم الامتداد قابلاً للتكوين

في هذه المرحلة من الدرس التطبيقي حول التعليمات البرمجية، يكون لديك ملحق تم تكوينه للاستخدام مع الإعداد المختار للوظائف التي كتبتها بالفعل، ولكن ماذا لو أراد المستخدم استخدام خط الطول والعرض بدلاً من y و x للحقول التي تشير إلى موقع على متن الطائرة الديكارتية؟ وأيضًا، كيف يمكنك إقناع المستخدم النهائي بتوفير مفتاح واجهة برمجة التطبيقات (API) الخاص به، بدلاً من السماح له باستهلاك مفتاح واجهة برمجة التطبيقات (API) المقدم؟ يمكنك تجاوز الحصة النسبية لواجهة برمجة التطبيقات هذه بسرعة. في هذه الحالة، يمكنك إعداد المعلمات واستخدامها.

حدد المعلمات الأساسية في ملف extension.yaml

ابدأ بتحويل العناصر التي من المحتمل أن يكون للمطورين تكوين مخصص لها. الأول سيكون معلمات XFIELD و YFIELD .

  1. في الملف extension.yaml ، أضف التعليمة البرمجية التالية، التي تستخدم معلمات الحقل XFIELD و YFIELD . تعيش هذه المعلمات داخل params YAML المحددة مسبقًا:

Extension.yaml

params:
  - param: XFIELD
    label: The X Field Name
    description: >-
      The X Field is also known as the **longitude** value. What does
      your Firestore instance refer to as the X value or the longitude
      value. If no value is specified, the extension searches for
      field 'xv'.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: xv
    required: false
    immutable: false
    example: xv
  - param: YFIELD
    label: The Y Field Name
    description: >-
      The Y Field is also known as the **latitude** value. What does
      your Firestore instance refer to as the Y value or the latitude
      value. If no value is specified, the extension searches for
      field 'yv'.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: yv
    required: false
    immutable: false
    example: yv
  • تقوم المعلمة بتسمية المعلمة بطريقة مرئية لك، أنت منتج الامتداد. استخدم هذه القيمة لاحقًا عند تحديد قيم المعلمات.
  • label هو معرف يمكن قراءته بواسطة الإنسان للمطور لإعلامه بما تفعله المعلمة.
  • وصف يعطي وصفا تفصيليا للقيمة. نظرًا لأن هذا يدعم تخفيض السعر، فيمكنه الارتباط بوثائق إضافية، أو يمكنه تمييز الكلمات التي قد تكون مهمة للمطور.
  • يحدد النوع آلية الإدخال لكيفية قيام المستخدم بتعيين قيمة المعلمة. هناك العديد من الأنواع الموجودة، بما في ذلك string و select و multiSelect و selectResource و secret . لمعرفة المزيد حول كل خيار من هذه الخيارات، راجع الوثائق .
  • يقيد validationRegex إدخال المطور إلى قيمة regex معينة (في المثال يعتمد على إرشادات اسم الحقل البسيطة الموجودة هنا )؛ وإذا فشل ذلك...
  • ينبه validationErrorMessage المطور إلى قيمة الفشل.
  • الافتراضي هو القيمة التي ستكون إذا لم يقوم المطور بإدخال أي نص.
  • مطلوب يعني أن المطور غير مطالب بإدخال أي نص.
  • غير قابل للتغيير يسمح للمطور بتحديث هذا الامتداد وتغيير هذه القيمة. في هذه الحالة، يجب أن يكون المطور قادرًا على تغيير أسماء الحقول مع تغير متطلباته.
  • يقدم المثال فكرة عما قد يبدو عليه الإدخال الصالح.

كان هذا كثيرًا لفهمه!

  1. لديك ثلاث معلمات أخرى لإضافتها إلى ملف extension.yaml قبل إضافة معلمة خاصة.
  - param: INPUTPATH
    label: The input document to listen to for changes
    description: >-
      This is the document where you write an x and y value to. Once
      that document has received a value, it notifies the extension to
      calculate a geohash and store that in an output document in a certain
      field. This accepts function [wildcard parameters](https://firebase.google.com/docs/functions/firestore-events#wildcards-parameters)
    type: string
    validationRegex: ^[^/]+(/[^/]*/[^/]*)*/[^/]+$
    validationErrorMessage: >-
      This must point to a document path, not a collection path from the root
      of the database. It must also not start or end with a '/' character.
    required: true
    immutable: false
    example: users/{uid}
  - param: OUTPUTFIELD
    label: Geohash field
    description: >-
      This specifies the field in the output document to store the geohash in.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    required: false
    default: hash
    immutable: false
    example: hash

تحديد المعلمات الحساسة

أنت الآن بحاجة إلى إدارة مفتاح API الذي يحدده المستخدم. هذه سلسلة حساسة لا ينبغي تخزينها في نص عادي في الوظيفة. بدلاً من ذلك، قم بتخزين هذه القيمة في Cloud Secret Manager . هذا موقع خاص في السحابة يقوم بتخزين الأسرار المشفرة، ويمنع تسربها عن طريق الخطأ. يتطلب هذا من المطور أن يدفع مقابل استخدام هذه الخدمة، ولكنه يضيف طبقة إضافية من الأمان على مفاتيح واجهة برمجة التطبيقات (API) الخاصة به ويحتمل أن يحد من النشاط الاحتيالي. تنبه وثائق المستخدم المطور إلى أنها خدمة مدفوعة، بحيث لا تكون هناك أي مفاجآت في الفواتير. بشكل عام، الاستخدام مشابه لموارد السلسلة الأخرى المذكورة أعلاه. والفرق الوحيد هو النوع الذي يسمى secret .

  • في ملف extension.yaml ، أضف الكود التالي:

Extension.yaml

  - param: APIKEY
    label: GeohashService API Key
    description: >-
      Your geohash service API Key. Since this is a demo, and not a real
      service, you can use : 1234567890.
    type: secret
    required: true
    immutable: false

قم بتحديث سمات resource لاستخدام المعلمات

كما ذكرنا سابقًا، يحدد المورد (وليس الوظيفة) كيفية ملاحظة المورد، لذلك يحتاج مورد locationUpdate إلى التحديث لاستخدام المعلمة الجديدة.

  • في ملف extension.yaml ، أضف الكود التالي:

Extension.yaml

## Change from this
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}]

## To this
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/${INPUTPATH}

تحقق من الملف extension.yaml

  • قم بمراجعة ملف extension.yaml . يجب أن يبدو مثل هذا:

Extension.yaml

name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

displayName: Latitude and Longitude to GeoHash converter
description: A converter for changing your Latitude and Longitude coordinates to geohashes.

license: Apache-2.0  # The license you want to use for the extension

author:
  authorName: Sparky
  url: https://github.com/Firebase

billingRequired: true

params:
  - param: XFIELD
    label: The X Field Name
    description: >-
      The X Field is also known as the **longitude** value. What does
      your Firestore instance refer to as the X value or the longitude
      value. If you don't provide a value for this field, the extension will use 'xv' as the default value.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: xv
    required: false
    immutable: false
    example: xv
  - param: YFIELD
    label: The Y Field Name
    description: >-
      The Y Field is also known as the **latitude** value. What does
      your Firestore instance refer to as the Y value or the latitude
      Value. If you don't provide a value for this field, the extension will use 'yv' as the default value.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    default: yv
    required: false
    immutable: false
    example: yv
  - param: INPUTPATH
    label: The input document to listen to for changes
    description: >-
      This is the document where you write an x and y value to. Once
      that document has been modified, it notifies the extension to
      compute a geohash and store that in an output document in a certain
      field. This accepts function [wildcard parameters](https://firebase.google.com/docs/functions/firestore-events#wildcards-parameters)
    type: string
    validationRegex: ^[^/]+(/[^/]*/[^/]*)*/[^/]+$
    validationErrorMessage: >-
      This must point to a document path, not a collection path from the root
      of the database. It must also not start or end with a '/' character.
    required: true
    immutable: false
    example: users/{uid}
  - param: OUTPUTFIELD
    label: Geohash field
    description: >-
      This specifies the field in the output document to store the geohash in.
    type: string
    validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
    validationErrorMessage: >-
      The field can only contain uppercase or lowercase letter, numbers,
      _, and . characters and must be less than 1500 bytes long. The field
      must also not start with a number.
    required: false
    default: hash
    immutable: false
    example: hash
  - param: APIKEY
    label: GeohashService API Key
    description: >-
      Your geohash service API Key. Since this is a demo, and not a real
      service, you can use : 1234567890.
    type: secret
    required: true
    immutable: false

resources:
  - name: locationUpdate
    type: firebaseextensions.v1beta.function
    properties:
      eventTrigger:
        eventType: providers/cloud.firestore/eventTypes/document.write
        resource: projects/${PROJECT_ID}/databases/(default)/documents/${INPUTPATH}
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

roles:
  - role: datastore.user
    reason: Allows the extension to read / write to your Firestore instance.

الوصول إلى المعلمات في التعليمات البرمجية

الآن بعد أن تم تكوين كافة المعلمات في ملف extension.yaml ، قم بإضافتها إلى ملف index.ts .

  • في ملف index.ts ، استبدل القيم الافتراضية بـ process.env.PARAMETER_NAME ، الذي يجلب قيم المعلمات المناسبة ويملأها في رمز الوظيفة المنشور في مشروع Firebase الخاص بالمطور.

Index.ts

// Replace this:
const documentPath = "users/{uid}";
const xField = "xv";
const yField = "yv";
const apiKey = "1234567890";
const outputField = "hash";

// with this:
const documentPath = process.env.INPUTPATH!; // this value is ignored since its read from the resource
const xField = process.env.XFIELD!;
const yField = process.env.YFIELD!;
const apiKey = process.env.APIKEY!;
const outputField = process.env.OUTPUTFIELD!;

عادةً، تريد إجراء عمليات فحص فارغة لقيم متغيرات البيئة، ولكن في هذه الحالة، أنت تثق في أن قيم المعلمات قد تم نسخها بشكل صحيح. تم الآن تكوين الكود للعمل مع معلمات الامتداد.

7. إنشاء وثائق المستخدم

قبل اختبار التعليمات البرمجية على المحاكيات أو في سوق ملحقات Firebase، يجب توثيق الامتداد حتى يعرف المطورون ما سيحصلون عليه عند استخدام الامتداد.

  1. ابدأ بإنشاء ملف PREINSTALL.md ، والذي يُستخدم لوصف الوظيفة وأي متطلبات أساسية للتثبيت والتأثيرات المحتملة على الفواتير.

التثبيت المسبق.md

Use this extension to automatically convert documents with a latitude and
longitude to a geohash in your database. Additionally, this extension includes a callable function that allows users to make one-time calls
to convert an x,y coordinate into a geohash.

Geohashing is supported for latitudes between 90 and -90 and longitudes
between 180 and -180.

#### Third Party API Key

This extension uses a fictitious third-party API for calculating the
geohash. You need to supply your own API keys. (Since it's fictitious,
you can use 1234567890 as an API key).

#### Additional setup

Before installing this extension, make sure that you've [set up a Cloud
Firestore database](https://firebase.google.com/docs/firestore/quickstart) in your Firebase project.

After installing this extension, you'll need to:

- Update your client code to point to the callable geohash function if you
want to perform arbitrary geohashes.

Detailed information for these post-installation tasks are provided after
you install this extension.

#### Billing
To install an extension, your project must be on the [Blaze (pay as you
go) plan](https://firebase.google.com/pricing)

- This extension uses other Firebase and Google Cloud Platform services,
which have associated charges if you exceed the service's no-cost tier:
 - Cloud Firestore
 - Cloud Functions (Node.js 16+ runtime. [See
FAQs](https://firebase.google.com/support/faq#extensions-pricing))
 - [Cloud Secret Manager](https://cloud.google.com/secret-manager/pricing)
  1. لتوفير الوقت في كتابة README.md لهذا المشروع، استخدم الطريقة الملائمة:
firebase ext:info . --markdown > README.md

يجمع هذا محتويات ملف PREINSTALL.md الخاص بك وتفاصيل إضافية حول ملحقك من ملف extension.yaml الخاص بك.

وأخيرًا، أبلغ مطور الامتداد ببعض التفاصيل الإضافية المتعلقة بالامتداد الذي تم تثبيته للتو. قد يحصل المطور على بعض الإرشادات والمعلومات الإضافية بعد إكمال التثبيت وقد يحصل على بعض المهام التفصيلية بعد التثبيت مثل إعداد رمز العميل هنا.

  1. قم بإنشاء ملف POSTINSTALL.md ، ثم قم بتضمين معلومات التثبيت اللاحقة التالية:

POSTINSTALL.md

Congratulations on installing the geohash extension!

#### Function information

* **Firestore Trigger** - ${function:locationUpdate.name} was installed
and is invoked when both an x field (${param:XFIELD}) and y field
(${param:YFIELD}) contain a value.

* **Callable Trigger** - ${function:callableHash.name} was installed and
can be invoked by writing the following client code:
 ```javascript
import { getFunctions, httpsCallable } from "firebase/functions";
const functions = getFunctions();
const geoHash = httpsCallable(functions, '${function:callableHash.name}');
geoHash({ ${param:XFIELD}: -122.0840, ${param:YFIELD}: 37.4221 })
  .then((result) => {
    // Read result of the Cloud Function.
    /** @type {any} */
    const data = result.data;
    const error = data.error;
    if (error != null) {
        console.error(`callable error : ${error}`);
    }
    const result = data.result;
    console.log(result);
  });

يراقب

كأفضل الممارسات، يمكنك مراقبة نشاط الامتداد المثبت لديك، بما في ذلك التحقق من صحته واستخدامه وسجلاته.

The output rendering looks something like this when it's deployed:

<img src="img/82b54a5c6ca34b3c.png" alt="A preview of the latitude and longitude geohash converter extension in the firebase console"  width="957.00" />


## Test the extension with the full configuration
Duration: 03:00


It's time to make sure that the user-configurable extension is working the way it is intended.

* Change into the functions folder and ensure that the latest compiled version of the extensions exists. In the extensions project functions directory, call:

```console
npm run build

يؤدي هذا إلى إعادة ترجمة الوظائف بحيث يكون أحدث كود المصدر جاهزًا للنشر جنبًا إلى جنب مع الامتداد عند نشره على محاكي أو إلى Firebase مباشرة.

بعد ذلك، قم بإنشاء دليل جديد لاختبار الامتداد منه. نظرًا لأنه تم تطوير الامتداد من الوظائف الموجودة، فلا تختبر من المجلد الذي تم تكوين الامتداد فيه حيث يحاول ذلك أيضًا نشر الوظائف وقواعد Firebase بجانبه.

التثبيت والاختبار باستخدام محاكيات Firebase

  1. قم بإنشاء دليل جديد على نظامك المضيف وقم بتوصيل هذا الدليل بمشروع Firebase الخاص بك باستخدام firebase init .
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. من هذا الدليل، قم بتشغيل firebase ext:install لتثبيت الامتداد. استبدل /path/to/extension بالمسار المطلق للدليل الذي يحتوي على ملف extension.yaml الخاص بك. يؤدي هذا إلى بدء عملية تثبيت ملحقك وإنشاء ملف .env يحتوي على التكوينات الخاصة بك قبل دفع التكوين إلى Firebase أو إلى المحاكيات.
firebase ext:install /path/to/extension
  • نظرًا لأنك تقوم بنشر المشروع محليًا، حدد أنك ترغب في استخدام ملف محلي بدلاً من Google Cloud Secret Manager.

da928c65ffa8ce15.png

  1. ابدأ مجموعة المحاكي المحلية:
firebase emulators:start

التثبيت والاختبار باستخدام مشروع Firebase حقيقي

يمكنك تثبيت الامتداد الخاص بك في مشروع Firebase فعلي. يوصى باستخدام مشروع اختبار للاختبار الخاص بك. استخدم سير عمل الاختبار هذا إذا كنت تريد اختبار التدفق الشامل لامتدادك أو إذا كان مشغل الامتداد الخاص بك غير مدعوم حتى الآن بواسطة مجموعة محاكي Firebase (راجع خيار محاكي الامتدادات ). تدعم المحاكيات حاليًا وظائف تشغيل طلب HTTP ووظائف تشغيل أحداث الخلفية لـ Cloud Firestore، وRealtime Database، وPub/Sub.

  1. قم بإنشاء دليل جديد على نظامك المضيف وقم بتوصيل هذا الدليل بمشروع Firebase الخاص بك باستخدام firebase init .
cd ..
mkdir sample-proj
cd sample-proj
firebase init --project=projectID-or-alias
  1. ثم، من هذا الدليل، قم بتشغيل firebase ext:install لتثبيت الامتداد. استبدل /path/to/extension بالمسار المطلق للدليل الذي يحتوي على ملف extension.yaml الخاص بك. يؤدي هذا إلى بدء عملية تثبيت ملحقك وإنشاء ملف .env يحتوي على التكوينات الخاصة بك قبل دفع التكوين إلى Firebase أو إلى المحاكيات.
firebase ext:install /path/to/extension
  • نظرًا لأنك تريد النشر إلى Firebase مباشرةً، وترغب في استخدام Google Cloud Secret Manager، فأنت بحاجة إلى تنشيط Secret Manager API قبل تثبيت الامتداد.
  1. نشر إلى مشروع Firebase الخاص بك.
firebase deploy

اختبر الامتداد

  1. بعد تشغيل firebase deploy أو firebase emulators:start ، انتقل إلى علامة التبويب Firestore الخاصة بوحدة تحكم Firebase أو عرض الويب الخاص بالمحاكيات، حسب الاقتضاء.
  2. أضف مستندًا إلى المجموعة المحددة بواسطة الحقل x والحقل y . في هذه الحالة، توجد المستندات المحدثة في u/{uid} مع حقل x بقيمة xv وحقل y بقيمة yv .

شاشة Firebase Emulators لإضافة سجل Firestore

  1. إذا نجحت في تثبيت الامتداد، فسيقوم الامتداد بإنشاء حقل جديد يسمى hash في المستند بعد حفظ الحقلين.

شاشة قاعدة بيانات Firestore من المحاكي تظهر التجزئة المضافة

8. تهانينا!

لقد نجحت في تحويل وظيفة السحابة الأولى الخاصة بك إلى ملحق Firebase!

لقد قمت بإضافة ملف extension.yaml وقمت بتكوينه حتى يتمكن المطورون من تحديد الطريقة التي يريدون نشر ملحقك بها. قمت بعد ذلك بإنشاء وثائق المستخدم التي توفر إرشادات حول ما يجب على مطوري الامتداد فعله قبل إعداد الامتداد والخطوات التي قد يتعين عليهم اتخاذها بعد تثبيت الامتداد بنجاح.

أنت تعرف الآن الخطوات الأساسية المطلوبة لتحويل وظيفة Firebase إلى ملحق Firebase قابل للتوزيع.

ماذا بعد؟