На этой странице описаны шаги, необходимые для создания простого расширения Firebase, которое вы можете установить в свои проекты или поделиться с другими. Этот простой пример расширения Firebase будет отслеживать сообщения в вашей базе данных реального времени и преобразовывать их в верхний регистр.
1. Настройте среду и инициализируйте проект.
Прежде чем вы сможете приступить к созданию расширения, вам необходимо настроить среду сборки с необходимыми инструментами.
Установите Node.js 16 или новее. Один из способов установки Node — использование nvm (или nvm-windows ).
Установите или обновите Firebase CLI до последней версии. Чтобы установить или обновить с помощью
npm
, выполните следующую команду:npm install -g firebase-tools
Теперь используйте Firebase CLI для инициализации нового проекта расширения:
Создайте каталог для вашего расширения и
cd
в него:mkdir rtdb-uppercase-messages && cd rtdb-uppercase-messages
Запустите команду
ext:dev:init
Firebase CLI:firebase ext:dev:init
При появлении запроса выберите JavaScript в качестве языка для функций (но учтите, что вы также можете использовать TypeScript при разработке собственного расширения) и на вопрос об установке зависимостей ответьте «да». (Для любых других параметров примите значения по умолчанию.) Эта команда создаст скелетную кодовую базу для нового расширения, на основе которой вы сможете начать разработку своего расширения.
Используйте firebase ext:dev:init
для инициализации нового каталога расширений.
2. Попробуйте пример расширения с помощью эмулятора.
Когда интерфейс командной строки Firebase инициализировал новый каталог расширений, он создал простой пример функции и каталог integration-tests
, содержащий файлы, необходимые для запуска расширения с помощью набора эмуляторов Firebase.
Попробуйте запустить пример расширения в эмуляторе:
Перейдите в каталог
integration-tests
:cd functions/integration-tests
Запустите эмулятор с демо-проектом:
firebase emulators:start --project=demo-test
Эмулятор загружает расширение в предопределённый «пустой» проект (
demo-test
). На данный момент расширение состоит из единственной функции, вызываемой HTTP,greetTheWorld
, которая при доступе возвращает сообщение «Hello World».Пока эмулятор все еще работает, попробуйте функцию
greetTheWorld
расширения, посетив URL-адрес, который он напечатал при запуске.Ваш браузер отображает сообщение «Hello World от Welcome-the-World».
Исходный код этой функции находится в каталоге
functions
расширения. Откройте исходный код в редакторе или IDE по вашему выбору:функции/index.js
const functions = require("firebase-functions/v1"); exports.greetTheWorld = functions.https.onRequest((req, res) => { // Here we reference a user-provided parameter // (its value is provided by the user during installation) const consumerProvidedGreeting = process.env.GREETING; // And here we reference an auto-populated parameter // (its value is provided by Firebase after installation) const instanceId = process.env.EXT_INSTANCE_ID; const greeting = `${consumerProvidedGreeting} World from ${instanceId}`; res.send(greeting); });
Во время работы эмулятора он автоматически перезагрузит любые изменения, внесенные вами в код функций. Попробуйте внести небольшое изменение в функцию
greetTheWorld
:функции/index.js
const greeting = `${consumerProvidedGreeting} everyone, from ${instanceId}`;
Сохраните изменения. Эмулятор перезагрузит ваш код, и теперь, когда вы посетите URL-адрес функции, вы увидите обновленное приветствие.
Использование эмулятора расширений может ускорить разработку, позволяя быстро тестировать и повторять код.
Дополнительная информация
Узнайте больше об использовании эмулятора расширений .
3. Добавьте основную информацию в файл Extension.yaml.
Теперь, когда у вас настроена среда разработки и запущен эмулятор расширений, вы можете приступить к написанию собственного расширения.
В качестве скромного первого шага отредактируйте метаданные предопределенного расширения, чтобы они отражали расширение, которое вы хотите написать вместо greet-the-world
. Эти метаданные хранятся в файле extension.yaml
.
Откройте
extension.yaml
в своем редакторе и замените все содержимое файла следующим:name: rtdb-uppercase-messages version: 0.0.1 specVersion: v1beta # Firebase Extensions specification version; don't change # Friendly display name for your extension (~3-5 words) displayName: Convert messages to upper case # Brief description of the task your extension performs (~1 sentence) description: >- Converts messages in RTDB to upper case author: authorName: Your Name url: https://your-site.example.com license: Apache-2.0 # Required license # Public URL for the source code of your extension sourceUrl: https://github.com/your-name/your-repo
Обратите внимание на соглашение об именах, используемое в поле
name
: официальные расширения Firebase называются с префиксом, указывающим основной продукт Firebase, на котором работает расширение, за которым следует описание того, что делает расширение. Вы должны использовать то же соглашение в своих собственных расширениях.Поскольку вы изменили имя своего расширения, вам также следует обновить конфигурацию эмулятора, указав новое имя:
- В файле
functions/integration-tests/firebase.json
изменитеgreet-the-world
наrtdb-uppercase-messages
. - Переименуйте
functions/integration-tests/extensions/greet-the-world.env
вfunctions/integration-tests/extensions/rtdb-uppercase-messages.env
.
- В файле
В вашем коде расширения еще остались некоторые остатки расширения greet-the-world
, но пока оставьте их. Вы обновите их в следующих нескольких разделах.
Файл
extension.yaml
содержит метаданные о вашем расширении. Самыми основными из этих метаданных является имя вашего расширения и описание того, что оно делает.Назовите свои расширения в следующем формате:
<firebase-product>-<description-of-tasks-performed>
.
Дополнительная информация
Ссылка extension.yaml
содержит полную спецификацию файла; однако в этой документации будут обсуждаться конкретные варианты использования этого файла по мере необходимости.
4. Напишите облачную функцию и объявите ее как ресурс расширения.
Теперь вы можете приступить к написанию кода. На этом этапе вы напишете облачную функцию, которая будет выполнять основную задачу вашего расширения, а именно отслеживать сообщения в базе данных реального времени и преобразовывать их в верхний регистр.
Откройте исходный код функций расширения (в каталоге
functions
расширения) в редакторе или IDE по вашему выбору. Замените его содержимое следующим:функции/index.js
import { database, logger } from "firebase-functions/v1"; const app = initializeApp(); // Listens for new messages added to /messages/{pushId}/original and creates an // uppercase version of the message to /messages/{pushId}/uppercase // for all databases in 'us-central1' export const makeuppercase = database .ref("/messages/{pushId}/uppercase") .onCreate(async (snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); // Convert it to upper case. logger.log("Uppercasing", context.params.pushId, original); const uppercase = original.toUpperCase(); // Setting an "uppercase" sibling in the Realtime Database. const upperRef = snapshot.ref.parent.child("upper"); await upperRef.set(uppercase); });
Старая функция, которую вы заменили, запускалась по протоколу HTTP и запускалась при доступе к конечной точке HTTP. Новая функция запускается событиями базы данных в реальном времени: она отслеживает новые элементы по определенному пути и, когда они обнаруживаются, записывает версию значения в верхнем регистре обратно в базу данных.
Кстати, в этом новом файле используется синтаксис модуля ECMAScript (
import
иexport
) вместо CommonJS (require
). Чтобы использовать модули ES в Node, укажите"type": "module"
вfunctions/package.json
:{ "name": "rtdb-uppercase-messages", "main": "index.js", "type": "module", … }
Каждая функция вашего расширения должна быть объявлена в файле
extension.yaml
. Расширение в качестве примераgreetTheWorld
качестве единственной облачнойфункциирасширения; теперь, когда вы заменили его наmakeuppercase
, вам также необходимо обновить его объявление.Откройте
extension.yaml
и добавьте полеresources
:resources: - name: makeuppercase type: firebaseextensions.v1beta.function properties: eventTrigger: eventType: providers/google.firebase.database/eventTypes/ref.create # DATABASE_INSTANCE (project's default instance) is an auto-populated # parameter value. You can also specify an instance. resource: projects/_/instances/${DATABASE_INSTANCE}/refs/messages/{pushId}/original runtime: "nodejs18"
Поскольку ваше расширение теперь использует базу данных реального времени в качестве триггера, вам необходимо обновить конфигурацию эмулятора, чтобы запускать эмулятор RTDB вместе с эмулятором облачных функций:
Если эмулятор все еще работает, остановите его, нажав Ctrl-C.
В каталоге
functions/integration-tests
выполните следующую команду:firebase init emulators
При появлении запроса пропустите настройку проекта по умолчанию, затем выберите «Эмуляторы функций и базы данных». Примите порты по умолчанию и разрешите средству установки загружать все необходимые файлы.
Перезапустите эмулятор:
firebase emulators:start --project=demo-test
Попробуйте обновленное расширение:
Откройте пользовательский интерфейс эмулятора базы данных, используя ссылку, которую эмулятор напечатал при его запуске.
Отредактируйте корневой узел базы данных:
- Поле:
messages
- Тип:
json
- Значение:
{"11": {"original": "recipe"}}
Если все настроено правильно, то при сохранении изменений в базе данных должна сработать функция
makeuppercase
расширения и добавить в сообщение 11 дочернюю запись с содержимым"upper": "RECIPE"
. Просмотрите журналы и вкладки базы данных пользовательского интерфейса эмулятора, чтобы подтвердить ожидаемые результаты.- Поле:
Попробуйте добавить еще несколько дочерних элементов в узел
messages
({"original":"any text"}
). Всякий раз, когда вы добавляете новую запись, расширение должно добавлять полеuppercase
содержащее содержимоеoriginal
поля в верхнем регистре.
Теперь у вас есть законченное, хотя и простое расширение, работающее с экземпляром RTDB. В следующих разделах вы улучшите это расширение, добавив некоторые дополнительные функции. Затем вы получите расширение, готовое к распространению среди других, и, наконец, узнаете, как опубликовать свое расширение в Extensions Hub.
- Функции, составляющие логику вашего расширения, должны быть определены как код облачных функций и объявлены как ресурс расширения в файле
extension.yaml
. - Вы можете написать функции, которые срабатывают при доступе к конечным точкам HTTP или в ответ на события, создаваемые продуктами Firebase, продуктами Google Cloud и другими расширениями.
Дополнительная информация
- Узнайте больше о написании облачных функций для расширений , в том числе о поддерживаемых триггерах событий.
- Ссылка
extension.yaml
содержит полную спецификацию файла; однако в этой документации будут обсуждаться конкретные варианты использования этого файла по мере необходимости. - В документации по облачным функциям для Firebase содержится общая информация об использовании облачных функций, не относящаяся к расширениям Firebase.
5. Объявите API и роли
Firebase предоставляет каждому экземпляру установленного расширения ограниченный доступ к проекту и его данным, используя учетную запись службы для каждого экземпляра. Каждая учетная запись имеет минимальный набор разрешений, необходимых для работы. По этой причине вы должны явно объявить все роли IAM, которые требуются вашему расширению; когда пользователи устанавливают ваше расширение, Firebase создает учетную запись службы с предоставленными этими ролями и использует ее для запуска расширения.
Вам не нужно объявлять роли, чтобы инициировать события продукта, но вам нужно объявить роль, чтобы иным образом взаимодействовать с ним. Поскольку функция, которую вы добавили на последнем шаге, записывает данные в базу данных реального времени, вам необходимо добавить следующее объявление в extension.yaml
:
roles:
- role: firebasedatabase.admin
reason: Allows the extension to write to RTDB.
Аналогичным образом вы объявляете API Google, которые использует расширение, в поле apis
. Когда пользователи установят ваше расширение, им будет задан вопрос, хотят ли они автоматически включить эти API для своего проекта. Обычно это необходимо только для API Google, отличных от Firebase, и не требуется для данного руководства.
- Объявите любую роль IAM, необходимую вашему расширению, в поле
roles
файлаextensions.yaml
. После установки расширения автоматически получают эти роли. - Укажите все API Google, необходимые вашему расширению, в поле
apis
файлаextensions.yaml
. Когда пользователи устанавливают ваше расширение, они могут выбрать автоматическое включение этих API для своего проекта. - В целях документации объявите все API-интерфейсы, не относящиеся к Google, которые нужны вашему расширению, в поле
externalServices
файлаextensions.yaml
.
Дополнительная информация
- Узнайте больше о настройке соответствующего доступа для расширения .
- Ссылка
extension.yaml
содержит полную спецификацию файла; однако в этой документации будут обсуждаться конкретные варианты использования этого файла по мере необходимости.
6. Определите настраиваемые пользователем параметры.
Функция, которую вы создали на последних двух шагах, отслеживала определенное местоположение RTDB на предмет входящих сообщений. Иногда просмотр определенного местоположения действительно является тем, что вам нужно, например, когда ваше расширение работает со структурой базы данных, которую вы используете исключительно для своего расширения. Однако в большинстве случаев вам захочется сделать эти значения доступными для настройки пользователями, которые устанавливают ваше расширение в свои проекты. Таким образом, пользователи смогут использовать ваше расширение для работы с существующей настройкой базы данных.
Сделайте путь, по которому расширение отслеживает новые сообщения, настраиваемым пользователем:
В файле
extension.yaml
добавьте разделparams
:- param: MESSAGE_PATH label: Message path description: >- What is the path at which the original text of a message can be found? type: string default: /messages/{pushId}/original required: true immutable: false
Это определяет новый строковый параметр, который пользователям будет предложено установить при установке вашего расширения.
Продолжая работать в файле
extension.yaml
, вернитесь к объявлениюmakeuppercase
и измените полеresource
на следующее:resource: projects/_/instances/${DATABASE_INSTANCE}/refs/${param:MESSAGE_PATH}
Токен
${param:MESSAGE_PATH}
— это ссылка на только что определенный вами параметр. При запуске вашего расширения этот токен будет заменен любым значением, настроенным пользователем для этого параметра, в результате чего функцияmakeuppercase
будет прослушивать путь, указанный пользователем. Вы можете использовать этот синтаксис для ссылки на любой пользовательский параметр в любом месте файлаextension.yaml
(и вPOSTINSTALL.md
— подробнее об этом позже).Вы также можете получить доступ к пользовательским параметрам из кода вашей функции.
В функции, которую вы написали в последнем разделе, вы жестко запрограммировали путь для отслеживания изменений. Измените определение триггера, чтобы вместо этого оно ссылалось на определяемое пользователем значение:
функции/index.js
export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate
Обратите внимание, что в расширениях Firebase это изменение сделано исключительно ради документации: когда облачная функция развертывается как часть расширения, она использует определение триггера из файла
extension.yaml
и игнорирует значение, указанное в определении функции. Тем не менее, рекомендуется задокументировать в коде, откуда берется это значение.Возможно, вас разочарует внесение изменений в код, не оказывающих влияния на время выполнения, но важный урок, который следует усвоить, заключается в том, что вы можете получить доступ к любому определяемому пользователем параметру в коде функции и использовать его как обычное значение в логике функции. В качестве намека на эту возможность добавьте следующий оператор журнала, чтобы продемонстрировать, что вы действительно получаете доступ к значению, определенному пользователем:
функции/index.js
export const makeuppercase = database.ref(process.env.MESSAGE_PATH).onCreate( async (snapshot, context) => { logger.log("Found new message at ", snapshot.ref); // Grab the current value of what was written to the Realtime Database. ...
Обычно пользователям предлагается указать значения параметров при установке расширения. Однако когда вы используете эмулятор для тестирования и разработки, вы пропускаете процесс установки, поэтому вместо этого вы предоставляете значения для пользовательских параметров, используя файл
env
.Откройте
functions/integration-tests/extensions/rtdb-uppercase-messages.env
и замените определениеGREETING
следующим:MESSAGE_PATH=/msgs/{pushId}/original
Обратите внимание, что указанный выше путь отличается от пути по умолчанию и от пути, который вы определили ранее; это просто для того, чтобы доказать себе, когда вы попробуете обновленное расширение, что ваше определение вступает в силу.
Теперь перезапустите эмулятор и еще раз посетите пользовательский интерфейс эмулятора базы данных.
Отредактируйте корневой узел базы данных, используя путь, определенный выше:
- Поле:
msgs
- Тип:
json
- Значение:
{"11": {"original": "recipe"}}
Когда вы сохраняете изменения в базе данных, функция
makeuppercase
расширения должна срабатывать, как и раньше, но теперь она также должна печатать определяемый пользователем параметр в журнал консоли.- Поле:
- Вы можете предоставить пользователям возможность настраивать ваше расширение в соответствии со своими потребностями, объявив определяемые пользователем параметры в файле
extension.yaml
. Пользователям предлагается определить эти значения при установке вашего расширения. - Вы можете ссылаться на значения пользовательских параметров в файле
extension.yaml
и в файлеPOSTINSTALL.md
, используя следующий синтаксис:${param:PARAMETER_NAME}
- Вы можете получить доступ к значениям пользовательских параметров в коде облачных функций в виде переменных среды:
process.env.PARAMETER_NAME
- При тестировании с использованием эмулятора определите пользовательские параметры в файле
<extension-name>.env
.
Дополнительная информация
Узнайте больше о настройке и использовании параметров в вашем расширении .
7. Обеспечьте перехватчики событий для пользовательской логики.
Как автор расширения вы уже видели, как продукт Firebase может активировать вашу логику, предоставляемую расширением: создание новых записей в базе данных реального времени запускает вашу функцию makeuppercase
. Ваше расширение может иметь аналогичные отношения с пользователями, которые устанавливают ваше расширение: ваше расширение может запускать логику, определяемую пользователем .
Расширение может предоставлять синхронные перехватчики , асинхронные перехватчики или и то, и другое. Синхронные перехватчики дают пользователям возможность выполнять задачи, которые блокируют выполнение одной из функций расширения. Это может быть полезно, например, чтобы дать пользователям возможность выполнить пользовательскую предварительную обработку до того, как расширение выполнит свою работу.
В этом руководстве вы добавите асинхронный перехватчик в свое расширение, который позволит пользователям определять свои собственные этапы обработки, которые будут выполняться после того, как ваше расширение запишет сообщение в верхнем регистре в базу данных реального времени. Асинхронные перехватчики используют Eventarc для запуска пользовательских функций. Расширения объявляют типы событий, которые они генерируют, и когда пользователи устанавливают расширение, они выбирают, какие типы событий им интересны. Если они выберут хотя бы одно событие, Firebase предоставит канал Eventarc для расширения в рамках процесса установки. . Затем пользователи могут развернуть свои собственные облачные функции, которые прослушивают этот канал и активируются, когда расширение публикует новые события.
Выполните следующие шаги, чтобы добавить асинхронный хук:
В файле
extension.yaml
добавьте следующий раздел, в котором объявляется один тип события, который генерирует расширение:events: - type: test-publisher.rtdb-uppercase-messages.v1.complete description: >- Occurs when message uppercasing completes. The event subject will contain the RTDB URL of the uppercase message.
Типы событий должны быть универсально уникальными; Чтобы обеспечить уникальность, всегда называйте свои события в следующем формате:
<publisher-id>.<extension-id>.<version>.<description>
> . (У вас еще нет идентификатора издателя, поэтому пока просто используйтеtest-publisher
.)В конце функции
makeuppercase
добавьте код, который публикует событие только что объявленного вами типа:функции/index.js
// Import the Eventarc library: import { initializeApp } from "firebase-admin/app"; import { getEventarc } from "firebase-admin/eventarc"; const app = initializeApp(); // In makeuppercase, after upperRef.set(uppercase), add: // Set eventChannel to a newly-initialized channel, or `undefined` if events // aren't enabled. const eventChannel = process.env.EVENTARC_CHANNEL && getEventarc().channel(process.env.EVENTARC_CHANNEL, { allowedEventTypes: process.env.EXT_SELECTED_EVENTS, }); // If events are enabled, publish a `complete` event to the configured // channel. eventChannel && eventChannel.publish({ type: "test-publisher.rtdb-uppercase-messages.v1.complete", subject: upperRef.toString(), data: { "original": original, "uppercase": uppercase, }, });
В этом примере кода используется тот факт, что переменная среды
EVENTARC_CHANNEL
определяется только тогда, когда пользователь включил хотя бы один тип события. еслиEVENTARC_CHANNEL
не определен, код не пытается публиковать какие-либо события.Вы можете прикрепить дополнительную информацию к событию Eventarc. В приведенном выше примере событие имеет поле
subject
, содержащее ссылку на вновь созданное значение, и полезныеdata
, содержащие исходные сообщения и сообщения в верхнем регистре. Эту информацию могут использовать определяемые пользователем функции, запускающие событие.Обычно переменные среды
EVENTARC_CHANNEL
иEXT_SELECTED_EVENTS
определяются на основе параметров, выбранных пользователем во время установки. Для тестирования с помощью эмулятора вручную определите эти переменные в файлеrtdb-uppercase-messages.env
:EVENTARC_CHANNEL=locations/us-central1/channels/firebase EXT_SELECTED_EVENTS=test-publisher.rtdb-uppercase-messages.v1.complete
На этом этапе вы выполнили шаги, необходимые для добавления асинхронного перехватчика событий в ваше расширение.
Чтобы опробовать эту новую функцию, которую вы только что реализовали, в следующих нескольких шагах примите на себя роль пользователя, который устанавливает расширение:
В каталоге
functions/integration-tests
инициализируйте новый проект Firebase:firebase init functions
При появлении запроса откажитесь от настройки проекта по умолчанию, выберите JavaScript в качестве языка облачных функций и установите необходимые зависимости. Этот проект представляет собой проект пользователя , в котором установлено ваше расширение.
Отредактируйте
integration-tests/functions/index.js
и вставьте следующий код:import { logger } from "firebase-functions/v1"; import { onCustomEventPublished } from "firebase-functions/v2/eventarc"; import { initializeApp } from "firebase-admin/app"; import { getDatabase } from "firebase-admin/database"; const app = initializeApp(); export const extraemphasis = onCustomEventPublished( "test-publisher.rtdb-uppercase-messages.v1.complete", async (event) => { logger.info("Received makeuppercase completed event", event); const refUrl = event.subject; const ref = getDatabase().refFromURL(refUrl); const upper = (await ref.get()).val(); return ref.set(`${upper}!!!`); } );
Это пример функции постобработки, которую может написать пользователь. В этом случае функция прослушивает расширение, чтобы опубликовать
complete
событие, и при срабатывании добавляет три восклицательных знака к новому сообщению, написанному заглавными буквами.Перезапустите эмулятор. Эмулятор загрузит функции расширения, а также функцию постобработки, определенную «пользователем».
Посетите пользовательский интерфейс эмулятора базы данных и отредактируйте корневой узел базы данных, используя путь, определенный выше:
- Поле:
msgs
- Тип:
json
- Значение:
{"11": {"original": "recipe"}}
Когда вы сохраняете изменения в базе данных, функция
makeuppercase
расширения и пользовательская функцияextraemphasis
должны сработать последовательно, в результате чегоupper
поле получит значениеRECIPE!!!
.- Поле:
- Ваши расширения могут включать в себя перехватчики, позволяющие пользователям вставлять свою собственную логику в базовую операцию вашего расширения.
- Пользовательские перехватчики могут быть синхронными, которые блокируют выполнение расширения до его завершения. Расширения часто используют синхронные перехватчики для выполнения пользовательских задач предварительной обработки.
- Пользовательские перехватчики также могут быть асинхронными, как в примере выше. Асинхронные перехватчики можно использовать для запуска пользовательской логики, которая не важна для правильной работы расширения.
Дополнительная информация
Узнайте больше о добавлении перехватчиков для пользовательской логики , включая асинхронные и синхронные перехватчики.
8. Добавьте обработчики событий жизненного цикла
Написанное вами расширение обрабатывает сообщения по мере их создания. Но что, если у ваших пользователей уже есть база сообщений на момент установки расширения? В расширениях Firebase есть функция, называемая перехватчиками событий жизненного цикла , которую вы можете использовать для запуска действий при установке, обновлении или перенастройке вашего расширения. В этом разделе вы будете использовать перехватчики событий жизненного цикла для заполнения существующей базы данных сообщений проекта сообщениями в верхнем регистре, когда пользователь устанавливает ваше расширение.
Расширения Firebase используют облачные задачи для запуска обработчиков событий жизненного цикла. Вы определяете обработчики событий с помощью облачных функций; всякий раз, когда экземпляр вашего расширения достигает одного из поддерживаемых событий жизненного цикла, если вы определили обработчик, он добавляет обработчик в очередь облачных задач. Затем Cloud Tasks асинхронно выполнит обработчик. Пока работает обработчик событий жизненного цикла, консоль Firebase сообщит пользователю, что у экземпляра расширения выполняется задача обработки. Ваша функция-обработчик должна сообщать пользователю о текущем состоянии и завершении задачи.
Чтобы добавить обработчик событий жизненного цикла, который заполняет существующие сообщения, выполните следующие действия:
Определите новую облачную функцию, которая активируется событиями очереди задач:
функции/index.js
import { tasks } from "firebase-functions/v1"; import { getDatabase } from "firebase-admin/database"; import { getExtensions } from "firebase-admin/extensions"; import { getFunctions } from "firebase-admin/functions"; export const backfilldata = tasks.taskQueue().onDispatch(async () => { const batch = await getDatabase() .ref(process.env.MESSAGE_PATH) .parent.parent.orderByChild("upper") .limitToFirst(20) .get(); const promises = []; for (const key in batch.val()) { const msg = batch.child(key); if (msg.hasChild("original") && !msg.hasChild("upper")) { const upper = msg.child("original").val().toUpperCase(); promises.push(msg.child("upper").ref.set(upper)); } } await Promise.all(promises); if (promises.length > 0) { const queue = getFunctions().taskQueue( "backfilldata", process.env.EXT_INSTANCE_ID ); return queue.enqueue({}); } else { return getExtensions() .runtime() .setProcessingState("PROCESSING_COMPLETE", "Backfill complete."); } });
Обратите внимание, что функция обрабатывает лишь несколько записей, прежде чем снова добавить себя в очередь задач. Это часто используемая стратегия для решения задач обработки, которые не могут быть выполнены в течение тайм-аута облачной функции. Поскольку вы не можете предсказать, сколько сообщений пользователь уже может иметь в своей базе данных на момент установки вашего расширения, эта стратегия хорошо подходит.
В файле
extension.yaml
объявите функцию обратного заполнения как ресурс расширения, имеющий свойствоtaskQueueTrigger
:resources: - name: makeuppercase ... - name: backfilldata type: firebaseextensions.v1beta.function description: >- Backfill existing messages with uppercase versions properties: runtime: "nodejs18" taskQueueTrigger: {}
Затем объявите функцию как обработчик события жизненного цикла
onInstall
:lifecycleEvents: onInstall: function: backfilldata processingMessage: Uppercasing existing messages
Хотя заполнение существующих сообщений полезно, расширение все равно может работать и без него. В подобных ситуациях вам следует сделать запуск обработчиков событий жизненного цикла необязательным.
Для этого добавьте новый параметр в
extension.yaml
:- param: DO_BACKFILL label: Backfill existing messages description: >- Generate uppercase versions of existing messages? type: select required: true options: - label: Yes value: true - label: No value: false
Затем в начале функции обратного заполнения проверьте значение параметра
DO_BACKFILL
и выйдите раньше, если он не установлен:функции/index.js
if (!process.env.DO_BACKFILL) { return getExtensions() .runtime() .setProcessingState("PROCESSING_COMPLETE", "Backfill skipped."); }
Благодаря вышеуказанным изменениям расширение теперь будет преобразовывать существующие сообщения в верхний регистр при установке.
До этого момента вы использовали эмулятор расширения для разработки расширения и тестирования текущих изменений. Однако эмулятор расширения пропускает процесс установки, поэтому для проверки обработчика событий onInstall
вам необходимо установить расширение в реальном проекте. И это даже хорошо, поскольку с добавлением этой функции автоматического заполнения расширение учебного пособия теперь полностью готово к написанию кода!
События жизненного цикла запускаются, когда пользователи выполняют определенные задачи по управлению расширениями:
- Установка экземпляра расширения
- Обновление экземпляра расширения до новой версии
- Переконфигурирование экземпляра расширения
Вы можете определить функции, которые срабатывают при событиях жизненного цикла вашего расширения.
Используйте API среды выполнения расширений Admin SDK, чтобы сообщать пользователю о состоянии обработчика событий жизненного цикла. Пользователи увидят текущий статус обработки расширения в консоли Firebase.
Функции, которые работают со всей базой данных (например, операции обратного заполнения), часто не могут завершиться до истечения времени ожидания облачной функции. Вы можете избежать этой проблемы, разделив задачу на несколько вызовов функций.
Если ваше расширение включает в себя обработчики событий жизненного цикла, которые не являются критически важными для функционирования расширения, вам следует сделать выполнение обработчика настраиваемым пользователем.
Дополнительная информация
Узнайте больше об обработке событий жизненного цикла вашего расширения .
9. Развертывание в реальном проекте Firebase
Хотя эмулятор расширений — отличный инструмент для быстрого изменения расширения во время разработки, в какой-то момент вам захочется опробовать его в реальном проекте.
Для этого сначала настройте новый проект с включенными некоторыми службами:
- В консоли Firebase добавьте новый проект.
- Обновите свой проект до плана Blaze с оплатой по мере использования. Cloud Functions for Firebase требует, чтобы в вашем проекте была учетная запись для выставления счетов, поэтому для установки расширения вам также понадобится учетная запись для выставления счетов.
- В вашем новом проекте включите базу данных реального времени .
- Поскольку вы хотите проверить способность вашего расширения заполнять существующие данные при установке, импортируйте некоторые образцы данных в экземпляр базы данных реального времени:
- Загрузите некоторые начальные данные RTDB .
- На странице базы данных реального времени консоли Firebase нажмите (подробнее) > Импортировать JSON и выберите файл, который вы только что скачали.
Чтобы функция обратного заполнения могла использовать метод
orderByChild
, настройте базу данных для индексации сообщений по значениюupper
:{ "rules": { ".read": false, ".write": false, "messages": { ".indexOn": "upper" } } }
Теперь установите расширение из локального источника в новый проект:
Создайте новый каталог для вашего проекта Firebase:
mkdir ~/extensions-live-test && cd ~/extensions-live-test
Инициализируйте проект Firebase в рабочем каталоге:
firebase init database
При появлении запроса выберите только что созданный проект.
Установите расширение в свой локальный проект Firebase:
firebase ext:install /path/to/rtdb-uppercase-messages
Здесь вы можете увидеть, как работает пользователь при установке расширения с помощью инструмента Firebase CLI. Обязательно выберите «да», когда инструмент настройки спросит, хотите ли вы заполнить существующую базу данных.
После того, как вы выберете параметры конфигурации, интерфейс командной строки Firebase сохранит вашу конфигурацию в каталоге
extensions
и запишет расположение источника расширения в файлеfirebase.json
. В совокупности эти две записи называются манифестом расширений . Пользователи могут использовать манифест, чтобы сохранить конфигурацию своих расширений и развернуть ее в разных проектах.Разверните конфигурацию расширения в работающем проекте:
firebase deploy --only extensions
Если все пойдет хорошо, Firebase CLI должен загрузить ваше расширение в ваш проект и установить его. После завершения установки запустится задача обратной засыпки, и через несколько минут ваша база данных будет обновлена сообщениями в верхнем регистре. Добавьте несколько новых узлов в базу данных сообщений и убедитесь, что расширение также работает для новых сообщений.
- Пользователи могут создать манифест расширения с помощью команды
firebase ext:install
. Вы также можете использовать эту команду для установки расширения из локального источника. - Разверните конфигурацию расширения из манифеста в работающий проект с помощью
firebase deploy
. - Хотя здесь это не показано, пользователи также могут устанавливать расширения в свои проекты из Extensions Hub.
Дополнительная информация
См. пользовательскую документацию по управлению конфигурациями проекта с помощью манифеста расширений .
10. Напишите документацию
Прежде чем поделиться своим расширением с пользователями, убедитесь, что вы предоставляете достаточно документации, чтобы они могли добиться успеха.
Когда вы инициализировали проект расширения, Firebase CLI создал незавершенные версии минимально необходимой документации. Обновите эти файлы, чтобы они точно отражали созданное вами расширение.
расширение.yaml
Вы уже обновляли этот файл при разработке этого расширения, поэтому вам не нужно вносить какие-либо обновления прямо сейчас.
Однако не упускайте из виду важность документации, содержащейся в этом файле. В дополнение к важной идентификационной информации расширения — имени, описанию, автору, официальному расположению репозитория — файл extension.yaml
содержит пользовательскую документацию для каждого ресурса и настраиваемого пользователем параметра. Эта информация отображается пользователям в консоли Firebase, Extensions Hub и Firebase CLI.
PREINSTALL.md
В этом файле предоставьте информацию, необходимую пользователю перед установкой вашего расширения: кратко опишите, что делает расширение, объясните все предварительные требования и предоставьте пользователю информацию о последствиях установки расширения для выставления счетов. Если у вас есть веб-сайт с дополнительной информацией, это также хорошее место для ссылки на него.
Текст этого файла отображается пользователю в Центре расширений и с помощью команды firebase ext:info
.
Вот пример файла PREINSTALL:
Use this extension to automatically convert strings to upper case when added to
a specified Realtime Database path.
This extension expects a database layout like the following example:
"messages": {
MESSAGE_ID: {
"original": MESSAGE_TEXT
},
MESSAGE_ID: {
"original": MESSAGE_TEXT
},
}
When you create new string records, this extension creates a new sibling record
with upper-cased text:
MESSAGE_ID: {
"original": MESSAGE_TEXT,
"upper": UPPERCASE_MESSAGE_TEXT,
}
#### Additional setup
Before installing this extension, make sure that you've
[set up Realtime Database](https://firebase.google.com/docs/database/quickstart)
in your Firebase project.
#### 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:
- Realtime Database
- Cloud Functions (Node.js 10+ runtime)
[See FAQs](https://firebase.google.com/support/faq#extensions-pricing)
- If you enable events,
[Eventarc fees apply](https://cloud.google.com/eventarc/pricing).
POSTINSTALL.md
Этот файл содержит информацию, полезную для пользователей после успешной установки вашего расширения: например, последующие шаги по настройке, пример расширения в действии и т. д.
Содержимое POSTINSTALL.md отображается в консоли Firebase после настройки и установки расширения. Вы можете ссылаться на пользовательские параметры в этом файле, и они будут заменены настроенными значениями.
Вот пример файла после установки для учебного расширения:
### See it in action
You can test out this extension right away!
1. Go to your
[Realtime Database dashboard](https://console.firebase.google.com/project/${param:PROJECT_ID}/database/${param:PROJECT_ID}/data) in the Firebase console.
1. Add a message string to a path that matches the pattern `${param:MESSAGE_PATH}`.
1. In a few seconds, you'll see a sibling node named `upper` that contains the
message in upper case.
### Using the extension
We recommend adding data by pushing -- for example,
`firebase.database().ref().push()` -- because pushing assigns an automatically
generated ID to the node in the database. During retrieval, these nodes are
guaranteed to be ordered by the time they were added. Learn more about reading
and writing data for your platform (iOS, Android, or Web) in the
[Realtime Database documentation](https://firebase.google.com/docs/database/).
### Monitoring
As a best practice, you can
[monitor the activity](https://firebase.google.com/docs/extensions/manage-installed-extensions#monitor)
of your installed extension, including checks on its health, usage, and logs.
CHANGELOG.md
Вам также следует документировать изменения, вносимые вами между выпусками расширения, в файле CHANGELOG.md
.
Поскольку пример расширения никогда ранее не публиковался, в журнале изменений имеется только одна запись:
## Version 0.0.1
Initial release of the _Convert messages to upper case_ extension.
README.md
Большинство расширений также предоставляют файл readme для пользователей, посещающих репозиторий расширения. вы можете написать этот файл вручную или создать файл read me с помощью команды.
Для целей данного руководства пропустите запись файла readme.
Дополнительная документация
Документация, описанная выше, представляет собой минимальный набор документации, которую вы должны предоставить пользователям. Многие расширения требуют более подробной документации, чтобы пользователи могли их успешно использовать. В этом случае вам следует написать дополнительную документацию и разместить ее там, где вы сможете указать пользователям.
Для целей данного руководства не нужно писать более обширную документацию.
- Как минимум, каждое расширение должно предоставлять пользовательскую документацию в следующих файлах:
extension.yaml
,PREINSTALL.md
,POSTINSTALL.md
иCHANGELOG.md
. - При необходимости вам также следует предоставить пользователям более подробную документацию.
Дополнительная информация
См . документацию по написанию документации .
11. Публикация в Центре расширений
Теперь, когда код вашего расширения готов и документирован, вы готовы поделиться им со всем миром в Extensions Hub. Но поскольку это всего лишь руководство, не делайте этого. Начните писать свое собственное расширение, используя то, что вы узнали здесь и в остальной документации издателя Firebase Extensions, а также изучив источник официальных расширений, написанных Firebase.
Когда вы будете готовы опубликовать свою работу в Extensions Hub, сделайте это следующим образом:
- Если вы публикуете свое первое расширение, зарегистрируйтесь в качестве издателя расширения . Когда вы регистрируетесь в качестве издателя расширений, вы создаете идентификатор издателя, который позволяет пользователям быстро идентифицировать вас как автора ваших расширений.
Разместите исходный код вашего расширения в общедоступном месте. Если ваш код доступен из проверенного источника, Firebase может опубликовать ваше расширение непосредственно из этого места. Это поможет гарантировать, что вы публикуете текущую выпущенную версию вашего расширения, а также поможет пользователям, позволяя им изучить код, который они устанавливают в свои проекты.
В настоящее время это означает, что ваше расширение будет доступно в общедоступном репозитории GitHub.
Загрузите свое расширение в Extension Hub с помощью команды
firebase ext:dev:upload
.Перейдите на панель издателя в консоли Firebase, найдите только что загруженное расширение и нажмите «Опубликовать в Extension Hub». Для этого нашим специалистам по проверке требуется проверка, которая может занять несколько дней. В случае одобрения расширение будет опубликовано в Extensions Hub. В случае отклонения вы получите сообщение с объяснением причины; после этого вы сможете устранить обнаруженные проблемы и повторно отправить их на рассмотрение.
- Чтобы делиться расширениями в Extensions Hub, вы должны быть зарегистрированы в качестве издателя.
- Требуется публикация из проверенного источника, и это дает пользователям уверенность в том, что устанавливаемый ими код — это тот же код, который они могут изучить на GitHub.
- Используйте команду
firebase ext:dev:upload
, чтобы загрузить расширение в Extensions Hub. - Отправьте свои расширения на проверку с панели управления издателя.
Дополнительная информация
Узнайте больше о регистрации в качестве издателя и публикации расширения .