Adicionar ganchos de usuário a uma extensão

Você pode fornecer aos usuários que instalam sua extensão a capacidade de inserir sua própria lógica personalizada na execução de sua extensão. Existem duas maneiras de fazer isso:

  • Eventos do Eventarc : para oferecer aos usuários uma maneira de reagir de forma assíncrona aos eventos, você pode publicar no Eventarc. Os usuários podem implantar funções de manipulador de eventos que, por exemplo, enviam notificações após a conclusão de tarefas de longa duração ou podem definir suas próprias funções de pós-processamento.

  • Ganchos síncronos : para fornecer aos usuários uma maneira de adicionar lógica de bloqueio à sua extensão, você pode adicionar ganchos síncronos em pontos predefinidos na operação da extensão. Nesses pontos, você executa uma função de provedor de usuário e prossegue somente após sua conclusão. As tarefas de pré-processamento geralmente se enquadram nesta categoria.

Uma extensão pode usar um ou ambos os métodos.

Eventos Eventarc

Para publicar eventos de uma extensão:

  1. Declare os tipos de eventos que você publicará no arquivo 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
    

    O identificador type é composto por vários campos delimitados por pontos. Os campos ID do editor , nome da extensão e nome do evento são obrigatórios. O campo versão é recomendado. Escolha um nome de evento exclusivo e descritivo para cada tipo de evento que você publicar.

    Por exemplo, a extensão storage-resize-images declara um ú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.
    

    Os usuários poderão escolher quais eventos assinar quando instalarem a extensão.

  2. Nas funções de extensão, importe a API Eventarc do Admin SDK e inicialize um canal de eventos usando as configurações de instalação do usuário. Essas configurações são expostas usando as seguintes variáveis ​​de ambiente:

    • EVENTARC_CHANNEL : o nome completo do canal Eventarc no qual o usuário optou por publicar eventos.
    • EXT_SELECTED_EVENTS : uma lista separada por vírgulas de tipos de eventos que o usuário escolheu publicar. Quando você inicializa um canal com esse valor, o Admin SDK filtra automaticamente os eventos que o usuário não selecionou.
    • EVENTARC_CLOUD_EVENT_SOURCE : o identificador de origem do Cloud Event. O Admin SDK transmite automaticamente esse valor no campo de source dos eventos publicados. Normalmente você não precisa usar essa variável explicitamente.

    Se os eventos não foram habilitados na instalação, essas variáveis ​​serão indefinidas. Você pode usar este fato para inicializar um canal de eventos somente quando os eventos estiverem 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 no canal nos pontos da sua extensão que você deseja expor aos usuários. Por exemplo:

    // 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 os eventos que você publica, no arquivo PREINSTALL ou POSTINSTALL.

    Para cada evento, documente o seguinte:

    • Seu propósito pretendido
    • O ponto na lógica da sua extensão que ele executa
    • Os dados de saída que inclui
    • As condições para a sua execução

    Além disso, avise os usuários para não executarem nenhuma ação em seus manipuladores de eventos que possa acionar a mesma extensão, resultando em um loop infinito.

Ao publicar eventos de uma extensão, os usuários podem implantar manipuladores de eventos para responder com lógica personalizada.

Por exemplo, o exemplo a seguir exclui a imagem original após ela ter sido redimensionada. Observe que este manipulador de exemplo utiliza a propriedade subject do evento, que neste caso é o nome do arquivo original da imagem.

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 Gatilhos de eventos personalizados para obter mais informações.

Exemplo

A extensão oficial Resize Images fornece um gancho assíncrono ao publicar no Eventarc após redimensionar uma imagem.

Ganchos síncronos

Quando você quiser fornecer aos usuários um gancho que deve ser concluído com êxito para que uma de suas funções de extensão funcione, use ganchos síncronos .

Um gancho síncrono chama uma Cloud Function que pode ser chamada por HTTPS definida pelo usuário e aguarda a conclusão (possivelmente com um valor retornado) antes de continuar. Um erro na função fornecida pelo usuário resulta em um erro na função de extensão.

Para expor um gancho síncrono:

  1. Adicione um parâmetro à sua extensão que permita aos usuários configurá-la com o URL da função personalizada do Cloud. Por exemplo:

    - 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. No ponto da sua extensão onde você deseja expor o gancho, chame a função usando seu URL. Por exemplo:

    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 todos os ganchos disponibilizados no arquivo PREINSTALL ou POSTINSTALL.

    Para cada gancho, documente o seguinte:

    • Seu propósito pretendido
    • O ponto na lógica da sua extensão que ele executa
    • Suas entradas e saídas esperadas
    • As condições (ou opções) para a sua execução

    Além disso, avise os usuários para não realizarem nenhuma ação na função de gancho que possa acionar a mesma extensão, resultando em um loop infinito.

Exemplo

A extensão Algolia Search fornece um gancho síncrono para chamar uma função de transformação fornecida pelo usuário antes de gravar no Algolia.