Aggiungere hook utente a un'estensione

Puoi fornire agli utenti che installano la tua estensione la possibilità di inserire la propria logica personalizzata nell'esecuzione dell'estensione. Esistono due modi per farlo:

  • Eventi Eventarc: per offrire agli utenti un modo per reagire in modo asincrono agli eventi, puoi pubblicare su Eventarc. Gli utenti possono implementare funzioni di gestore degli eventi che, ad esempio, inviano notifiche al termine di attività di lunga durata oppure possono definire le proprie funzioni di post-elaborazione.

  • Hook sincroni: per offrire agli utenti un modo per aggiungere logica di blocco all'estensione, puoi aggiungere hook sincroni in punti predefiniti del funzionamento dell'estensione. A questo punto, esegui una funzione per l'utente e il fornitore e procedi solo al termine. Le attività di pre-elaborazione rientrano spesso in questa categoria.

Un'estensione può utilizzare uno o entrambi i metodi.

Eventi Eventarc

Per pubblicare eventi da un'estensione:

  1. Dichiara i tipi di eventi che pubblicherai nel file 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
    

    L'identificatore type è costituito da diversi campi delimitati da punti. I campi ID publisher, nome dell'estensione e nome evento sono obbligatori. Il campo della versione è consigliato. Scegli un nome di evento univoco e descrittivo per ogni tipo di evento che pubblichi.

    Ad esempio, l'estensione storage-resize-images dichiara un singolo tipo di evento:

    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.
    

    Gli utenti potranno scegliere a quali eventi iscriversi quando installano l'estensione.

  2. Nelle funzioni di estensione, importa l'API Eventarc dal Admin SDK e inizializza un canale di eventi utilizzando le impostazioni di installazione dell'utente. Queste impostazioni vengono esposte utilizzando le seguenti variabili di ambiente:

    • EVENTARC_CHANNEL: il nome completo del canale Eventarc in cui l'utente ha scelto di pubblicare gli eventi.
    • EXT_SELECTED_EVENTS: un elenco separato da virgole dei tipi di eventi che l'utente ha scelto di pubblicare. Quando viene inizializzato un canale con questo valore, l'SDK Admin esclude automaticamente gli eventi non selezionati dall'utente.
    • EVENTARC_CLOUD_EVENT_SOURCE: l'identificatore dell'origine evento Cloud. L'SDK Admin passa automaticamente questo valore nel campo source degli eventi pubblicati. In genere, non è necessario utilizzare esplicitamente questa variabile.

    Se gli eventi non sono stati attivati durante l'installazione, queste variabili saranno undefined. Puoi utilizzare questa informazione per inizializzare un canale di eventi solo quando gli eventi sono abilitati:

    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. Pubblica gli eventi sul canale nei punti della tua estensione che vuoi mostrare agli utenti. Ad esempio:

    // 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. Documenta gli eventi pubblicati nel file PREINSTALL o POSTINSTALL.

    Per ogni evento, documenta quanto segue:

    • Scopo previsto
    • Il punto della logica dell'estensione in cui viene eseguito
    • I dati di output inclusi
    • Le condizioni per la sua esecuzione

    Inoltre, avvisa gli utenti di non eseguire azioni nei gestori degli eventi che potrebbero attivare la stessa estensione, generando un loop infinito.

Quando pubblichi eventi da un'estensione, gli utenti possono implementare gestori di eventi per rispondere con una logica personalizzata.

Ad esempio, l'esempio seguente elimina l'immagine originale dopo aver cambiato le dimensioni. Tieni presente che questo gestore di esempio utilizza la proprietà subject dell'evento, che in questo caso è il nome file originale dell'immagine.

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

Per saperne di più, consulta Attivatori evento personalizzati.

Esempio

L'estensione Modifica le dimensioni delle immagini ufficiale fornisce un hook asincrono pubblicando su Eventarc dopo aver modificato le dimensioni di un'immagine.

Hook sincroni

Quando vuoi fornire agli utenti un hook che deve essere completato correttamente per il funzionamento di una delle funzioni di estensione, utilizza gli hook sincroni.

Un hook sincrono chiama una funzione Cloud invocabile tramite HTTPS definita dall'utente e attende il completamento (eventualmente con un valore restituito) prima di continuare. Un errore nella funzione fornita dall'utente provoca un errore nella funzione di estensione.

Per esporre un hook sincrono:

  1. Aggiungi un parametro all'estensione che consenta agli utenti di configurarla con l'URL della loro funzione Cloud personalizzata. Ad esempio:

    - 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. Nel punto dell'estensione in cui vuoi esporre l'hook, chiama la funzione utilizzando il relativo URL. Ad esempio:

    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. Documenta tutti gli hook che rendi disponibili nel file PREINSTALL o POSTINSTALL.

    Per ogni hook, documenta quanto segue:

    • Scopo previsto
    • Il punto della logica dell'estensione in cui viene eseguito
    • I relativi input e output previsti
    • Le condizioni (o le opzioni) per la sua esecuzione

    Inoltre, avvisa gli utenti di non eseguire azioni nella funzione di hook che potrebbero attivare la stessa estensione, generando un loop infinito.

Esempio

L'estensione Algolia Search fornisce un hook sincrono per chiamare una funzione di trasformazione fornita dall'utente prima di scrivere in Algolia.