Nutzer-Hooks zu einer Erweiterung hinzufügen

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

  • Eventarc-Ereignisse: Sie können in Eventarc veröffentlichen, damit Nutzer asynchron auf Ereignisse reagieren können. Nutzer können Event-Handler-Funktionen bereitstellen, die beispielsweise Benachrichtigungen senden, nachdem Aufgaben mit langer Ausführungszeit abgeschlossen sind, oder eigene Nachbearbeitungsfunktionen definieren.

  • Synchrone Hooks: Damit Nutzer eine Blockierlogik zu Ihrer Erweiterung hinzufügen können, können Sie an vordefinierten Punkten im Vorgang der Erweiterung synchrone Hooks hinzufügen. An diesen Stellen führen Sie eine Nutzeranbieterfunktion aus und fahren erst fort, wenn sie abgeschlossen ist. Aufgaben der Vorverarbeitung fallen oft in diese Kategorie.

Für eine Erweiterung kann entweder eine oder beide Methoden verwendet werden.

Eventarc-Ereignisse

So veröffentlichen Sie Ereignisse aus einer Erweiterung:

  1. Deklarieren Sie die Ereignistypen, die Sie in der extension.yaml-Datei veröffentlichen möchten:

    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 Kennzeichnung type besteht aus mehreren durch Punkte getrennten Feldern. Die Felder Publisher-ID, Erweiterungsname und Ereignisname sind erforderlich. Das Versionsfeld wird empfohlen. Wählen Sie für jeden Ereignistyp, den Sie veröffentlichen, einen eindeutigen und aussagekräftigen Ereignisnamen aus.

    Die Erweiterung storage-resize-images 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 beim Installieren der Erweiterung auswählen, welche Ereignisse sie abonnieren möchten.

  2. Importieren Sie in Ihren Erweiterungsfunktionen die Eventarc API aus der Admin SDK und initialisieren Sie einen Ereigniskanal mit den Installationseinstellungen des Nutzers. Diese Einstellungen werden mithilfe der folgenden Umgebungsvariablen bereitgestellt:

    • EVENTARC_CHANNEL: Der vollständige 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 vom Admin SDK automatisch Ereignisse herausgefiltert, die der Nutzer nicht ausgewählt hat.
    • EVENTARC_CLOUD_EVENT_SOURCE: die Quellen-ID des Cloud-Ereignisses. Der Wert wird vom Admin SDK automatisch im Feld source veröffentlichter Ereignisse übergeben. 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 einen Ereigniskanal nur dann 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öffentlichen Sie Ereignisse auf dem Kanal an den Stellen in Ihrer Erweiterung, die Sie Nutzern zugänglich machen möchten. 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 veröffentlichten Ereignisse in der Datei PREINSTALL oder POSTINSTALL.

    Dokumentieren Sie für jedes Ereignis Folgendes:

    • Verwendungszweck
    • Den Punkt in der Logik der Erweiterung, der ausgeführt wird
    • Die enthaltenen Ausgabedaten
    • Die Bedingungen für die Ausführung

    Außerdem sollten Nutzer in ihren Ereignishandlern keine Aktionen ausführen, die dieselbe Erweiterung auslösen könnten, was zu einer endlosen Schleife führen würde.

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

Im folgenden Beispiel wird das Originalbild beispielsweise gelöscht, nachdem es neu skaliert wurde. In diesem Beispiel-Handler wird die Eigenschaft subject des Ereignisses verwendet, in diesem Fall der ursprüngliche Dateiname des Bilds.

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.appspot.com")
          .file(event.subject)
          .delete();
    });

Weitere Informationen finden Sie unter Benutzerdefinierte Ereignistrigger.

Beispiel

Die offizielle Erweiterung „Bilder anpassen“ bietet einen asynchronen Hook, indem nach der Größenänderung eines Bilds in Eventarc veröffentlicht wird.

Synchrone Hooks

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

Ein synchroner Hook ruft eine benutzerdefinierte HTTPS-aufrufbare Cloud-Funktion auf und wartet auf den Abschluss (ggf. mit einem zurückgegebenen Wert), bevor er fortfährt. Ein Fehler in der vom Nutzer bereitgestellten Funktion führt zu einem Fehler in der Erweiterungsfunktion.

So legen Sie einen synchronen Hook offen:

  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 auf, an der Sie den Hook freigeben möchten. Verwenden Sie dazu die URL der Funktion. 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 Datei PREINSTALL oder POSTINSTALL verfügbar machen.

    Dokumentieren Sie für jeden Hook Folgendes:

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

    Außerdem sollten Sie Nutzer warnen, in der Hook-Funktion keine Aktionen auszuführen, die dieselbe Erweiterung auslösen könnten, was zu einer unendlichen Schleife führen würde.

Beispiel

Die Algolia Search-Erweiterung bietet einen synchronen Hook, mit dem Sie eine benutzerdefinierte Transformationsfunktion aufrufen können, bevor Daten in Algolia geschrieben werden.