Добавьте пользовательские перехватчики в расширение

Вы можете предоставить пользователям, установившим ваше расширение, возможность встраивать собственную логику в его выполнение. Это можно сделать двумя способами:

  • События Eventarc : чтобы предоставить пользователям возможность асинхронно реагировать на события, вы можете публиковать их в Eventarc. Пользователи могут развертывать функции обработчиков событий, которые, например, отправляют уведомления после завершения длительных задач, или определять собственные функции постобработки.

  • Синхронные хуки : чтобы предоставить пользователям возможность добавлять блокирующую логику в ваше расширение, вы можете добавлять синхронные хуки в предопределенных точках работы расширения. В этих точках вы запускаете функцию-поставщик данных и продолжаете работу только после ее завершения. Задачи предварительной обработки часто относятся к этой категории.

Расширение может использовать один из этих методов или оба сразу.

События Eventarc

Для публикации событий из расширения:

  1. В файле extension.yaml укажите типы событий, которые вы будете публиковать:

    events:
      - type: publisher-id.extension-name.version.event-name
        description: event-description
      - type: publisher-id.extension-name.version.another-event-name
        description: another-event-description
    

    Идентификатор type состоит из нескольких полей, разделенных точками. Поля «ID издателя» , «имя расширения» и «имя события» являются обязательными. Поле «версия» рекомендуется. Для каждого публикуемого вами типа события выбирайте уникальное и описательное имя события.

    Например, расширение storage-resize-images объявляет единственный тип события:

    events:
      - type: firebase.extensions.storage-resize-images.v1.complete
        description: |
          Occurs when image resizing completes. The event will contain further
          details about specific formats and sizes.
    

    После установки расширения пользователи смогут выбирать, на какие события подписаться.

  2. В функциях расширения импортируйте API Eventarc из Admin SDK и инициализируйте канал событий, используя параметры установки пользователя. Эти параметры доступны через следующие переменные среды:

    • EVENTARC_CHANNEL : полное имя канала Eventarc, в который пользователь решил публиковать события.
    • EXT_SELECTED_EVENTS : список типов событий, разделенных запятыми, которые пользователь выбрал для публикации. При инициализации канала с этим значением Admin SDK автоматически отфильтровывает события, которые пользователь не выбрал.
    • EVENTARC_CLOUD_EVENT_SOURCE : идентификатор источника облачных событий. Административный SDK автоматически передает это значение в поле source опубликованных событий. Обычно нет необходимости явно использовать эту переменную.

    Если при установке не была включена поддержка событий, эти переменные будут неопределенными. Вы можете использовать это для инициализации канала событий только тогда, когда события включены:

    import * as admin from "firebase-admin";
    import {getEventarc} from 'firebase-admin/eventarc';
    
    admin.initializeApp();
    
    // 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,
      });
    
  3. Публикуйте события в канале в тех местах вашего расширения, которые вы хотите сделать доступными для пользователей. Например:

    // If events are enabled, publish a `complete` event to the configured
    // channel.
    eventChannel && eventChannel.publish({
        type: 'firebase.extensions.storage-resize-images.v1.complete',
        subject: filename,  // the name of the original file
        data: {
          // ...
        }
    });
    
  4. Документируйте публикуемые вами события в файле PREINSTALL или POSTINSTALL.

    Для каждого события задокументируйте следующее:

    • Его предназначение
    • Точка в логике вашего расширения, где оно выполняется.
    • Выходные данные, которые он включает
    • Условия его исполнения

    Кроме того, следует предупредить пользователей о том, что в обработчиках событий не следует выполнять действия, которые могут активировать то же самое расширение, что приведет к бесконечному циклу.

При публикации событий из расширения пользователи могут развертывать обработчики событий для генерации собственной логики.

Например, следующий пример удаляет исходное изображение после изменения его размера. Обратите внимание, что в этом примере обработчик использует свойство subject события, которое в данном случае представляет собой исходное имя файла изображения.

exports.onimageresized = onCustomEventPublished(
    "firebase.extensions.storage-resize-images.v1.complete",
    (event) => {
      logger.info("Received image resize completed event", event);
      // For example, delete the original.
      return admin.storage()
          .bucket("my-project.firebasestorage.app")
          .file(event.subject)
          .delete();
    });

Дополнительную информацию см. в разделе «Пользовательские триггеры событий» .

Пример

Официальное расширение Resize Images обеспечивает асинхронный перехват, публикуя данные в Eventarc после изменения размера изображения.

Синхронные крючки

Если вам нужно предоставить пользователям хук, который должен успешно завершиться для корректной работы одной из ваших функций расширения, используйте синхронные хуки .

Синхронный обработчик вызывает определяемую пользователем облачную функцию, запускаемую по протоколу HTTPS , и ожидает завершения (возможно, с возвращенным значением), прежде чем продолжить. Ошибка в предоставленной пользователем функции приводит к ошибке в функции расширения.

Чтобы открыть синхронный обработчик:

  1. Добавьте в расширение параметр, позволяющий пользователям настраивать расширение, указывая URL-адрес их собственной облачной функции. Например:

    - param: PREPROCESSING_FUNCTION
      label: Pre-processing function URL
      description: >
        An HTTPS callable function that will be called to transform the input data
        before it is processed by this function.
      type: string
      example: https://us-west1-my-project-id.cloudfunctions.net/preprocessData
      required: false
    
  2. В том месте вашего расширения, где вы хотите сделать хук доступным, вызовите функцию, используя её URL-адрес. Например:

    const functions = require('firebase-functions/v1');
    const fetch = require('node-fetch');
    
    const preprocessFunctionURL = process.env.PREPROCESSING_FUNCTION;
    
    exports.yourFunctionName = functions.firestore.document("collection/{doc_id}")
        .onWrite((change, context) => {
          // PREPROCESSING_FUNCTION hook begins here.
          // If a preprocessing function is defined, call it before continuing.
          if (preprocessFunctionURL) {
            try {
              await fetch(preprocessFunctionURL); // Could also be a POST request if you want to send data.
            } catch (e) {
              // Preprocessing failure causes the function to fail.
              functions.logger.error("Preprocessor error:", e);
              return;
            }
          }
          // End of PREPROCESSING_FUNCTION hook.
    
          // Main function logic follows.
          // ...
        });
    
  3. Задокументируйте все доступные вам перехватчики событий в файлах PREINSTALL или POSTINSTALL.

    Для каждого крючка задокументируйте следующее:

    • Его предназначение
    • Точка в логике вашего расширения, где оно выполняется.
    • Ожидаемые входные и выходные данные
    • Условия (или варианты) его выполнения

    Кроме того, следует предупредить пользователей о том, что в функции-перехватчике нельзя выполнять действия, которые могут активировать то же самое расширение, что приведет к бесконечному циклу.

Пример

Расширение Algolia Search предоставляет синхронный обработчик для вызова предоставленной пользователем функции преобразования перед записью в Algolia.