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

1. قبل از شروع

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

چیزی که خواهی ساخت

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

پسوند geohash در کنسول Firebase نشان داده می شود

چیزی که یاد خواهید گرفت

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

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

  • Firebase CLI (نصب و ورود به سیستم)
  • یک حساب Google، مانند یک حساب کاربری جیمیل
  • Node.js و npm
  • محیط توسعه مورد علاقه شما

2. راه اندازی شوید

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

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

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

Firebase را راه اندازی کنید

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

آیا می خواهید به جلو بروید؟

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

3. کد را مرور کنید

  • فایل index.ts را از فایل فشرده باز کنید. توجه داشته باشید که شامل دو اعلان عملکرد ابری در آن است.

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

این توابع نمایشی برای geohashing استفاده می شود. آنها یک جفت مختصات را می گیرند و آنها را به قالبی تبدیل می کنند که برای پرس و جوهای جغرافیایی در Firestore بهینه شده است. توابع استفاده از یک فراخوانی API را شبیه‌سازی می‌کنند تا بتوانید درباره مدیریت انواع داده‌های حساس در برنامه‌های افزودنی اطلاعات بیشتری کسب کنید. برای اطلاعات بیشتر، به مستندات مربوط به اجرای جستارهای Geo بر روی داده ها در 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);

ماشه Firestore

اولین تابع در فایل 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 برمی گرداند. اگرچه این تابع مستقیماً در این Codelab فراخوانی نمی شود، اما به عنوان نمونه ای از چیزی برای پیکربندی در افزونه 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. کد توابع ابری را به یک منبع Extensions تبدیل کنید

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

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

  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 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 استفاده کنید.

اسکرین شات فرآیند نصب برنامه افزودنی که نشان می دهد فایل Local هنگام نصب این افزونه برای مخفی کاری استفاده می شود

  1. شبیه سازهای Firebase را با پیکربندی جدید راه اندازی کنید:
firebase emulators:start
  1. پس از اجرای emulators:start ، به تب Firestore در نمای وب شبیه سازها بروید.
  2. سندی را با فیلد شماره xv و فیلد شماره yv به مجموعه users اضافه کنید.

یک کادر محاوره ای که در Firebase Emulators برای شروع مجموعه ای با شناسه مجموعه حاوی عبارت نمایش داده می شود

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

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

برای جلوگیری از درگیری تمیز کنید

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

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

firebase ext:uninstall geohash-ext

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

6. کاربر برنامه افزودنی را قابل تنظیم کنید

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

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

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

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

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

این خیلی قابل درک بود!

  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 ذخیره کنید. این مکان ویژه ای در ابر است که اسرار رمزگذاری شده را ذخیره می کند و از افشای تصادفی آنها جلوگیری می کند. این امر مستلزم پرداخت هزینه برای استفاده از این سرویس از سوی توسعه‌دهنده است، اما یک لایه امنیتی اضافی بر روی کلیدهای 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 ، که برای توصیف عملکرد، پیش نیازهای نصب و پیامدهای صورتحساب احتمالی استفاده می شود، شروع کنید.

PREINSTALL.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 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 پشتیبانی نمی‌شود، از این گردش کار آزمایشی استفاده کنید ( گزینه شبیه‌ساز برنامه‌های افزودنی را ببینید). شبیه‌سازها در حال حاضر از توابع راه‌اندازی شده با درخواست HTTP و توابع راه‌اندازی رویدادهای پس‌زمینه برای Cloud Firestore، پایگاه داده بیدرنگ، و 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
  • از آنجایی که می خواهید مستقیماً در 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 برای افزودن رکورد Firestore

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

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

8. تبریک!

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

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

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

بعدش چی؟