Agregar enlaces de usuario a una extensión

Puede proporcionar a los usuarios que instalen su extensión la posibilidad de insertar su propia lógica personalizada en la ejecución de su extensión. Hay dos maneras de lograr esto:

  • Eventos de Eventarc : para brindarles a los usuarios una forma de reaccionar asincrónicamente a los eventos, puede publicar en Eventarc. Los usuarios pueden implementar funciones de controlador de eventos que, por ejemplo, envían notificaciones después de completar tareas de larga duración, o pueden definir sus propias funciones de posprocesamiento.

  • Ganchos sincrónicos : para brindarles a los usuarios una manera de agregar lógica de bloqueo a su extensión, puede agregar ganchos sincrónicos en puntos predefinidos en la operación de la extensión. En estos puntos, ejecuta una función de proveedor de usuario y continúa solo después de que se completa. Las tareas de preprocesamiento suelen entrar en esta categoría.

Una extensión puede utilizar uno o ambos métodos.

Eventos de Eventarc

Para publicar eventos desde una extensión:

  1. Declare los tipos de eventos que publicará en el archivo 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
    

    El identificador type se compone de varios campos delimitados por puntos. Los campos ID del editor , nombre de la extensión y nombre del evento son obligatorios. Se recomienda el campo de versión. Elija un nombre de evento único y descriptivo para cada tipo de evento que publique.

    Por ejemplo, la extensión storage-resize-images declara un único tipo de 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.
    

    Los usuarios podrán elegir a qué eventos suscribirse cuando instalen la extensión.

  2. En sus funciones de extensión, importe la API de Eventarc desde el SDK de administración e inicialice un canal de eventos utilizando la configuración de instalación del usuario. Estas configuraciones se exponen utilizando las siguientes variables de entorno:

    • EVENTARC_CHANNEL : el nombre completo del canal Eventarc en el que el usuario eligió publicar eventos.
    • EXT_SELECTED_EVENTS : una lista separada por comas de tipos de eventos que el usuario eligió publicar. Cuando inicializa un canal con este valor, el SDK de administrador filtra automáticamente los eventos que el usuario no seleccionó.
    • EVENTARC_CLOUD_EVENT_SOURCE : el identificador de origen del evento en la nube. El SDK de administración pasa automáticamente este valor en el campo source de los eventos publicados. Normalmente no es necesario utilizar explícitamente esta variable.

    Si los eventos no se habilitaron durante la instalación, estas variables no estarán definidas. Puede utilizar este hecho para inicializar un canal de eventos solo cuando los eventos están habilitados:

    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. Publique eventos en el canal en los puntos de su extensión que desee exponer a los usuarios. Por ejemplo:

    // 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. Documente los eventos que publique, ya sea en el archivo PREINSTALL o POSTINSTALL.

    Para cada evento, documente lo siguiente:

    • Su propósito previsto
    • El punto en la lógica de su extensión que ejecuta
    • Los datos de salida que incluye.
    • Las condiciones para su ejecución.

    Además, advierta a los usuarios que no realicen ninguna acción en sus controladores de eventos que pueda activar la misma extensión, lo que resultaría en un bucle infinito.

Cuando publica eventos desde una extensión, los usuarios pueden implementar controladores de eventos para responder con lógica personalizada.

Por ejemplo, el siguiente ejemplo elimina la imagen original después de cambiar su tamaño. Tenga en cuenta que este controlador de ejemplo utiliza la propiedad del subject del evento, que en este caso es el nombre de archivo original de la imagen.

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

Consulte Activadores de eventos personalizados para obtener más información.

Ejemplo

La extensión oficial Resize Images proporciona un enlace asincrónico al publicar en Eventarc después de cambiar el tamaño de una imagen.

Ganchos sincrónicos

Cuando desee proporcionar a los usuarios un enlace que debe completarse correctamente para que funcione una de las funciones de su extensión, utilice enlaces sincrónicos .

Un enlace sincrónico llama a una función de nube invocable HTTPS definida por el usuario y espera su finalización (posiblemente con un valor devuelto) antes de continuar. Un error en la función proporcionada por el usuario da como resultado un error en la función de extensión.

Para exponer un gancho sincrónico:

  1. Agregue un parámetro a su extensión que permita a los usuarios configurar la extensión con la URL de su función de nube personalizada. Por ejemplo:

    - 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. En el punto de su extensión donde desea exponer el gancho, llame a la función usando su URL. Por ejemplo:

    const functions = require('firebase-functions');
    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. Documente los enlaces que ponga a disposición en el archivo PREINSTALL o POSTINSTALL.

    Para cada gancho, documente lo siguiente:

    • Su propósito previsto
    • El punto en la lógica de su extensión que ejecuta
    • Sus entradas y salidas esperadas
    • Las condiciones (u opciones) para su ejecución.

    Además, advierta a los usuarios que no realicen ninguna acción en la función de enlace que pueda activar la misma extensión, lo que resultaría en un bucle infinito.

Ejemplo

La extensión Algolia Search proporciona un enlace sincrónico para llamar a una función de transformación proporcionada por el usuario antes de escribir en Algolia.