Nutzer-Hooks zu einer Erweiterung hinzufügen

Sie können Nutzern, die Ihre Erweiterung installieren, die Möglichkeit geben, ihre eigene benutzerdefinierte Logik in die Ausführung Ihrer Erweiterung einzufügen. Dafür gibt es zwei Möglichkeiten:

  • Eventarc-Ereignisse: Wenn Sie Nutzern die Möglichkeit geben möchten, asynchron auf Ereignisse zu reagieren, können Sie Ereignisse in Eventarc veröffentlichen. Nutzer können Event-Handler-Funktionen bereitstellen, die beispielsweise Benachrichtigungen senden, nachdem lang andauernde Aufgaben abgeschlossen sind. Sie können auch eigene Nachbearbeitungsfunktionen definieren.

  • Synchrone Hooks: Damit Nutzer Ihrer Erweiterung Blockierungslogik hinzufügen können, können Sie synchrone Hooks an vordefinierten Stellen im Betrieb der Erweiterung hinzufügen. An diesen Stellen führen Sie eine Nutzeranbieterfunktion aus und fahren erst fort, wenn sie abgeschlossen ist. Vorverarbeitungsaufgaben fallen häufig in diese Kategorie.

Eine Erweiterung kann eine oder beide Methoden verwenden.

Eventarc-Ereignisse

So veröffentlichen Sie Ereignisse über eine Erweiterung:

  1. Deklarieren Sie die Ereignistypen, die Sie veröffentlichen möchten, in der Datei 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
    

    Die type-Kennung besteht aus mehreren durch Punkte getrennten Feldern. Die Felder Publisher-ID, Erweiterungsname und Ereignisname sind erforderlich. Das Feld „version“ wird empfohlen. Wählen Sie für jeden veröffentlichten Ereignistyp einen eindeutigen und aussagekräftigen Ereignisnamen aus.

    Die storage-resize-images-Erweiterung deklariert beispielsweise einen einzelnen Ereignistyp:

    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.
    

    Nutzer können bei der Installation der Erweiterung auswählen, welche Ereignisse sie abonnieren möchten.

  2. Importieren Sie in Ihren Erweiterungsfunktionen die Eventarc API aus Admin SDK und initialisieren Sie einen Ereigniskanal mit den Installationseinstellungen des Nutzers. Diese Einstellungen werden über die folgenden Umgebungsvariablen verfügbar gemacht:

    • EVENTARC_CHANNEL: Der vollständig qualifizierte Name des Eventarc-Kanals, in dem der Nutzer Ereignisse veröffentlichen möchte.
    • EXT_SELECTED_EVENTS: Eine durch Kommas getrennte Liste der Ereignistypen, die der Nutzer veröffentlichen möchte. Wenn Sie einen Channel mit diesem Wert initialisieren, werden Ereignisse, die der Nutzer nicht ausgewählt hat, automatisch vom Admin SDK herausgefiltert.
    • EVENTARC_CLOUD_EVENT_SOURCE: die Cloud-Ereignisquellen-ID. Das Admin SDK übergibt diesen Wert automatisch im Feld source veröffentlichter Ereignisse. Normalerweise müssen Sie diese Variable nicht explizit verwenden.

    Wenn Ereignisse bei der Installation nicht aktiviert wurden, sind diese Variablen nicht definiert. Sie können dies nutzen, um einen Ereigniskanal nur zu initialisieren, wenn Ereignisse aktiviert sind:

    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. Veröffentliche Ereignisse für den Kanal an den Stellen in deiner Erweiterung, die du Nutzern präsentieren möchtest. Beispiel:

    // 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. Dokumentieren Sie die Ereignisse, die Sie veröffentlichen, entweder in der Datei „PREINSTALL“ oder „POSTINSTALL“.

    Dokumentieren Sie für jedes Ereignis Folgendes:

    • Verwendungszweck
    • Der Punkt in der Logik Ihrer Erweiterung, an dem sie ausgeführt wird
    • Die enthaltenen Ausgabedaten
    • Die Bedingungen für die Ausführung

    Weisen Sie Nutzer außerdem darauf hin, dass sie in ihren Ereignishandlern keine Aktionen ausführen dürfen, die dieselbe Erweiterung auslösen und so zu einer Endlosschleife führen könnten.

Wenn Sie Ereignisse über eine Erweiterung veröffentlichen, können Nutzer Event-Handler bereitstellen, um mit benutzerdefinierter Logik zu reagieren.

Im folgenden Beispiel wird das Originalbild gelöscht, nachdem es in der Größe angepasst wurde. In diesem Beispiel-Handler wird die subject-Eigenschaft des Ereignisses verwendet, die in diesem Fall der ursprüngliche Dateiname des Bildes ist.

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();
    });

Weitere Informationen finden Sie unter Benutzerdefinierte Ereignistrigger.

Beispiel

Die offizielle Resize Images-Erweiterung bietet einen asynchronen Hook, indem sie nach dem Ändern der Größe eines Bildes in Eventarc veröffentlicht.

Synchrone Hooks

Wenn Sie Nutzern einen Hook zur Verfügung stellen möchten, der erfolgreich abgeschlossen werden muss, damit eine Ihrer Erweiterungsfunktionen ausgeführt werden kann, verwenden Sie synchrone Hooks.

Bei einem synchronen Hook wird eine benutzerdefinierte per HTTPS aufrufbare Cloud-Funktion aufgerufen und auf den Abschluss gewartet (möglicherweise mit einem zurückgegebenen Wert), bevor fortgefahren wird. Ein Fehler in der vom Nutzer bereitgestellten Funktion führt zu einem Fehler in der Erweiterungsfunktion.

So stellen Sie einen synchronen Hook bereit:

  1. Fügen Sie Ihrer Erweiterung einen Parameter hinzu, mit dem Nutzer die Erweiterung mit der URL zu ihrer benutzerdefinierten Cloud-Funktion konfigurieren können. Beispiel:

    - 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. Rufen Sie die Funktion an der Stelle in Ihrer Erweiterung, an der Sie den Hook verfügbar machen möchten, über die URL auf. Beispiel:

    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. Dokumentieren Sie alle Hooks, die Sie in der PREINSTALL- oder POSTINSTALL-Datei zur Verfügung stellen.

    Dokumentieren Sie für jeden Hook Folgendes:

    • Verwendungszweck
    • Der Punkt in der Logik Ihrer Erweiterung, an dem sie ausgeführt wird
    • Die erwarteten Ein- und Ausgaben
    • Die Bedingungen (oder Optionen) für die Ausführung

    Weisen Sie Nutzer außerdem darauf hin, dass sie in der Hook-Funktion keine Aktionen ausführen dürfen, die dieselbe Erweiterung auslösen könnten, da dies zu einer Endlosschleife führen würde.

Beispiel

Die Algolia Search-Erweiterung bietet einen synchronen Hook, mit dem eine vom Nutzer bereitgestellte Transformationsfunktion aufgerufen werden kann, bevor Daten in Algolia geschrieben werden.