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

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

  • События 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 состоит из нескольких полей, разделенных точками. Поля «Идентификатор издателя» , «Название расширения» и «Название события» являются обязательными. Рекомендуется указать поле «Версия». Выберите уникальное и описательное имя для каждого публикуемого типа событий.

    Например, расширение 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 : идентификатор источника события в облаке. Admin 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-адресом своей пользовательской функции Cloud. Например:

    - 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.