کد Cloud Functions خود را به عنوان یک افزونه Firebase تغییر دهید

۱. قبل از شروع

یک افزونه فایربیس یک یا مجموعه‌ای از وظایف خاص را در پاسخ به درخواست‌های HTTP یا رویدادهای فعال‌کننده از سایر محصولات فایربیس و گوگل مانند Firebase Cloud Messaging، Cloud Firestore یا Pub/Sub انجام می‌دهد.

آنچه خواهید ساخت

در این آزمایشگاه کد، شما یک افزونه Firebase برای geohashing خواهید ساخت. پس از استقرار، افزونه شما مختصات X و Y را در پاسخ به رویدادهای Firestore یا از طریق فراخوانی توابع قابل فراخوانی به geohashes تبدیل می‌کند. این می‌تواند به عنوان جایگزینی برای پیاده‌سازی کتابخانه geofire در تمام پلتفرم‌های هدف شما برای ذخیره داده‌ها استفاده شود و در زمان شما صرفه‌جویی کند.

افزونه geohash که در کنسول Firebase نمایش داده می‌شود

آنچه یاد خواهید گرفت

  • چگونه کد توابع ابری موجود را گرفته و آن را به یک افزونه فایربیس قابل توزیع تبدیل کنیم
  • نحوه تنظیم فایل extension.yaml
  • نحوه ذخیره رشته‌های حساس (کلیدهای API) در یک افزونه
  • چگونه به توسعه‌دهندگان افزونه اجازه دهیم آن را متناسب با نیازهای خود پیکربندی کنند
  • نحوه آزمایش و استقرار افزونه

آنچه نیاز دارید

۲. آماده شوید

کد را دریافت کنید

هر چیزی که برای این افزونه نیاز دارید در مخزن گیت‌هاب موجود است. برای شروع، کد را دریافت کرده و آن را در محیط توسعه مورد علاقه خود باز کنید.

  1. فایل زیپ دانلود شده را از حالت فشرده خارج کنید.
  2. برای نصب وابستگی‌های مورد نیاز، ترمینال را در دایرکتوری functions باز کنید و دستور npm install را اجرا کنید.

فایربیس را راه‌اندازی کنید

این آزمایشگاه کد، استفاده از شبیه‌سازهای Firebase را اکیداً توصیه می‌کند. اگر می‌خواهید توسعه افزونه‌ها را با یک پروژه واقعی Firebase امتحان کنید، به بخش ایجاد یک پروژه Firebase مراجعه کنید. این آزمایشگاه کد از توابع ابری استفاده می‌کند، بنابراین اگر به جای شبیه‌سازها از یک پروژه واقعی Firebase استفاده می‌کنید، باید به طرح قیمت‌گذاری Blaze ارتقا دهید .

می‌خوای از جلو رد شی؟

می‌توانید نسخه کامل‌شده‌ی codelab را دانلود کنید. اگر در طول مسیر به مشکل برخوردید یا اگر می‌خواهید ببینید که یک افزونه‌ی کامل‌شده چگونه است، به شاخه‌ی codelab-end در مخزن گیت‌هاب مراجعه کنید یا فایل زیپ کامل‌شده را دانلود کنید.

۳. کد را بررسی کنید

  • فایل index.ts را از فایل زیپ باز کنید. توجه داشته باشید که شامل دو اعلان توابع ابری (Cloud Functions) است.

این توابع چه کاری انجام می‌دهند؟

این توابع نمایشی برای 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/ collection نوشته شده است می‌خواند و سپس یک 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 پیکربندی شود، در اینجا گنجانده شده است.

۴. تنظیم فایل extension.yaml

حالا که می‌دانید کد توابع ابری در افزونه شما چه کاری انجام می‌دهد، آماده‌اید تا آن را برای توزیع بسته‌بندی کنید. هر افزونه فایربیس با یک فایل extension.yaml ارائه می‌شود که عملکرد و نحوه رفتار افزونه را شرح می‌دهد.

فایل extension.yaml به برخی فراداده‌های اولیه در مورد افزونه شما نیاز دارد. هر یک از مراحل زیر به شما کمک می‌کند تا بفهمید که همه فیلدها به چه معناست و چرا به آنها نیاز دارید.

  1. یک فایل extension.yaml در دایرکتوری ریشه پروژه‌ای که قبلاً دانلود کرده‌اید، ایجاد کنید. با اضافه کردن موارد زیر شروع کنید:
name: geohash-ext
version: 0.0.1
specVersion: v1beta  # Firebase Extensions specification version (do not edit)

نام افزونه به عنوان مبنای شناسه نمونه افزونه استفاده می‌شود (کاربران می‌توانند چندین نمونه از یک افزونه را نصب کنند که هر کدام شناسه خاص خود را دارند). سپس فایربیس با استفاده از آن شناسه نمونه، نام حساب‌های سرویس افزونه و منابع مختص افزونه را تولید می‌کند. شماره نسخه، نسخه افزونه شما را نشان می‌دهد. این شماره باید از نسخه‌بندی معنایی پیروی کند و شما باید هر زمان که تغییراتی در عملکرد افزونه ایجاد می‌کنید، آن را به‌روزرسانی کنید. نسخه مشخصات افزونه برای تعیین اینکه کدام مشخصات افزونه‌های فایربیس باید دنبال شود، استفاده می‌شود، در این مورد، 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 همانطور که در 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 برای شناسایی این افزونه را پوشش می‌دهد. برای جزئیات بیشتر در مورد سایر اطلاعات شناسایی که می‌توانید در یک افزونه مشخص کنید، به مستندات مراجعه کنید.

۵. کد توابع ابری را به یک منبع افزونه‌ها تبدیل کنید

منبع افزونه، آیتمی است که فایربیس در طول نصب افزونه در پروژه ایجاد می‌کند. سپس افزونه مالک آن منابع است و یک حساب سرویس خاص دارد که روی آنها کار می‌کند. در این پروژه، این منابع، توابع ابری (Cloud Functions) هستند که باید در فایل extension.yaml تعریف شوند زیرا افزونه به طور خودکار منابع را از کد موجود در پوشه functions ایجاد نمی‌کند. اگر توابع ابری شما به صراحت به عنوان یک منبع اعلام نشده باشند، هنگام استقرار افزونه، نمی‌توانند مستقر شوند.

محل استقرار تعریف شده توسط کاربر

  1. به کاربر اجازه دهید مکانی را که می‌خواهد این افزونه را در آن مستقر کند، مشخص کند و تصمیم بگیرد که آیا بهتر است افزونه را در نزدیکی کاربران نهایی خود یا نزدیک‌تر به پایگاه داده خود میزبانی کند. در فایل extension.yaml ، گزینه انتخاب مکان را قرار دهید.

پسوند.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 از 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 ، یک منبع جدید در زیر ویژگی resources ایجاد کنید. این ویژگی‌ها مختص یک تابع قابل فراخوانی هستند:
  - name: callableHash
    type: firebaseextensions.v1beta.function
    properties:
      httpsTrigger: {}

اگرچه منبع قبلی از eventTrigger استفاده می‌کرد، در اینجا از httpsTrigger استفاده می‌کنید که هم توابع قابل فراخوانی و هم توابع HTTPS را پوشش می‌دهد.

بررسی کد

این پیکربندی زیادی بود تا extension.yaml شما با هر کاری که توسط کد در فایل index.ts شما انجام می‌شود، مطابقت داشته باشد. فایل extension.yaml تکمیل شده در حال حاضر باید به این شکل باشد:

پسوند.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 در پوشه functions پروژه افزونه‌های دانلود شده فراخوانی کنید.
  2. یک دایرکتوری جدید روی سیستم میزبان خود ایجاد کنید و آن دایرکتوری را با استفاده از firebase init به پروژه Firebase خود متصل کنید.
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 نمایش داده می‌شود تا مجموعه‌ای را با شناسه مجموعه حاوی عبارت زیر شروع کند.

  1. اگر در نصب افزونه موفق باشید، افزونه یک فیلد جدید به نام hash در سند ایجاد می‌کند.

مجموعه کاربران با یک سند کاربر که دارای فیلدهای xv، yv و hash است.

برای جلوگیری از درگیری، پاکسازی کنید

  • پس از اتمام آزمایش، افزونه را حذف نصب کنید - شما قصد دارید کد افزونه را به‌روزرسانی کنید و نمی‌خواهید بعداً با افزونه فعلی تداخل داشته باشد.

افزونه‌ها امکان نصب چندین نسخه از یک افزونه را به طور همزمان فراهم می‌کنند، بنابراین با حذف نصب، مطمئن می‌شوید که هیچ تداخلی با افزونه‌های نصب شده قبلی وجود ندارد.

firebase ext:uninstall geohash-ext

راه حل فعلی کار می‌کند، اما همانطور که در ابتدای پروژه ذکر شد، یک کلید API کد شده برای شبیه‌سازی ارتباط با یک سرویس وجود دارد. چگونه می‌توانید از کلید API کاربر نهایی به جای کلید اصلی ارائه شده استفاده کنید؟ برای فهمیدن این موضوع، ادامه مطلب را بخوانید.

۶. افزونه را برای کاربر قابل پیکربندی کنید

در این مرحله از کد، شما یک افزونه دارید که برای استفاده با تنظیمات دلخواه توابعی که قبلاً نوشته‌اید پیکربندی شده است، اما اگر کاربر شما بخواهد از طول و عرض جغرافیایی به جای y و x برای فیلدهای نشان دهنده موقعیت مکانی در صفحه دکارتی استفاده کند، چه می‌شود؟ همچنین، چگونه می‌توانید کاربر نهایی را وادار کنید که کلید API خود را ارائه دهد، به جای اینکه اجازه دهید کلید API ارائه شده را مصرف کند؟ شما می‌توانید به سرعت سهمیه آن API را افزایش دهید. در این حالت، پارامترها را تنظیم و استفاده می‌کنید.

پارامترهای اساسی را در فایل extension.yaml تعریف کنید

با تبدیل مواردی که توسعه‌دهندگان ممکن است پیکربندی سفارشی برای آنها داشته باشند، شروع کنید. اولین مورد، پارامترهای XFIELD و YFIELD هستند.

  1. در فایل extension.yaml ، کد زیر را اضافه کنید که از پارامترهای فیلد XFIELD و YFIELD استفاده می‌کند. این پارامترها درون ویژگی YAML مربوط به params که قبلاً تعریف شده است، قرار دارند:

پسوند.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
  • param پارامتر را به گونه‌ای نامگذاری می‌کند که برای شما، تولیدکننده افزونه، قابل مشاهده باشد. از این مقدار بعداً هنگام تعیین مقادیر پارامتر استفاده کنید.
  • برچسب یک شناسه قابل خواندن توسط انسان برای توسعه‌دهنده است تا به آنها اطلاع دهد که پارامتر چه کاری انجام می‌دهد.
  • توضیحات، شرح مفصلی از مقدار ارائه می‌دهد. از آنجایی که این گزینه از markdown پشتیبانی می‌کند، می‌تواند به مستندات اضافی پیوند دهد یا کلماتی را که ممکن است برای توسعه‌دهنده مهم باشند، برجسته کند.
  • نوع، مکانیزم ورودی برای نحوه تنظیم مقدار پارامتر توسط کاربر را تعریف می‌کند. انواع زیادی از جمله string ، select ، multiSelect ، selectResource و secret وجود دارد. برای کسب اطلاعات بیشتر در مورد هر یک از این گزینه‌ها، به مستندات مراجعه کنید.
  • validationRegex ورودی توسعه‌دهنده را به یک مقدار regex خاص محدود می‌کند (در این مثال، بر اساس دستورالعمل‌های ساده نام فیلد موجود در اینجا است)؛ و اگر این روش جواب نداد...
  • validationErrorMessage به توسعه‌دهنده در مورد مقدار شکست هشدار می‌دهد.
  • مقدار پیش‌فرض ، مقداری است که اگر توسعه‌دهنده هیچ متنی وارد نکند، خواهد بود.
  • مورد نیاز به این معنی است که توسعه‌دهنده ملزم به وارد کردن هیچ متنی نیست.
  • immutable به توسعه‌دهنده اجازه می‌دهد تا این افزونه را به‌روزرسانی کند و این مقدار را تغییر دهد. در این حالت، توسعه‌دهنده باید بتواند نام فیلدها را با تغییر الزامات خود تغییر دهد.
  • این مثال ایده‌ای از اینکه یک ورودی معتبر چگونه می‌تواند باشد، ارائه می‌دهد.

خیلی چیزا بود که باید میفهمیدم!

  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 ، کد زیر را اضافه کنید:

پسوند.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 ، کد زیر را اضافه کنید:

پسوند.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 را بررسی کنید. باید چیزی شبیه به این باشد:

پسوند.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!;

معمولاً شما می‌خواهید بررسی‌های null را با مقادیر متغیرهای محیطی انجام دهید، اما در این مورد، شما به کپی صحیح مقادیر پارامترها اعتماد دارید. اکنون کد برای کار با پارامترهای افزونه پیکربندی شده است.

۷. ایجاد مستندات کاربر

قبل از آزمایش کد روی شبیه‌سازها یا در بازار افزونه‌های فایربیس، افزونه باید مستندسازی شود تا توسعه‌دهندگان بدانند هنگام استفاده از افزونه چه چیزی دریافت می‌کنند.

  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/docs/functions/faq-and-troubleshooting#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 ایجاد کنید و سپس اطلاعات نصب پس از نصب زیر را در آن قرار دهید:

نصب پست.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 init به پروژه Firebase خود متصل کنید.
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 پشتیبانی نمی‌شود ( به گزینه شبیه‌ساز Extensions مراجعه کنید)، از این گردش کار آزمایشی استفاده کنید. شبیه‌سازها در حال حاضر از توابع فعال‌شده توسط درخواست HTTP و توابع فعال‌شده توسط رویداد پس‌زمینه برای Cloud Firestore، Realtime Database و Pub/Sub پشتیبانی می‌کنند.

  1. یک دایرکتوری جدید روی سیستم میزبان خود ایجاد کنید و آن دایرکتوری را با استفاده از firebase init به پروژه Firebase خود متصل کنید.
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
  1. به پروژه Firebase خود منتقل کنید.
firebase deploy

افزونه را امتحان کنید

  1. پس از اجرای firebase deploy یا firebase emulators:start ، به برگه Firestore در کنسول Firebase یا نمای وب شبیه‌سازها، بسته به مورد، بروید.
  2. یک سند را به مجموعه مشخص شده توسط فیلد x و فیلد y اضافه کنید. در این حالت، اسناد به‌روزرسانی شده در u/{uid} با فیلد x برابر با xv و فیلد y برابر با yv قرار دارند.

صفحه شبیه‌سازهای فایربیس برای اضافه کردن رکورد فایراستور

  1. اگر در نصب افزونه موفق باشید، افزونه پس از ذخیره دو فیلد، فیلد جدیدی به نام hash در سند ایجاد می‌کند.

صفحه پایگاه داده Firestore از یک شبیه‌ساز که نشان می‌دهد هش اضافه شده است

۸. تبریک می‌گویم!

شما با موفقیت اولین تابع ابری خود را به یک افزونه فایربیس تبدیل کردید!

شما یک فایل extension.yaml اضافه کردید و آن را پیکربندی کردید تا توسعه‌دهندگان بتوانند نحوه‌ی استقرار افزونه‌ی شما را انتخاب کنند. سپس مستندات کاربری ایجاد کردید که راهنمایی‌هایی را در مورد کارهایی که توسعه‌دهندگان افزونه باید قبل از راه‌اندازی افزونه انجام دهند و مراحلی که ممکن است پس از نصب موفقیت‌آمیز افزونه لازم باشد، ارائه می‌دهد.

اکنون مراحل کلیدی مورد نیاز برای تبدیل یک تابع Firebase به یک افزونه Firebase قابل توزیع را می‌دانید.

بعدش چی؟