Cloud Pub/Sub als Endpunkt für Ihre Anwendung verwenden

Beim Erstellen einer Anwendung für Ihre Organisation verwendet Ihre Organisation möglicherweise eine Firewall, die verhindern kann, dass Google Chat Nachrichten an Ihre Anwendung sendet. Dazu kann Google Chat in Cloud Pub/Sub eingebunden werden. Durch diese Einbindung kann Ihre Anwendung eine Verbindung zu Cloud Pub/Sub herstellen und Nachrichten empfangen.

Architektur der Cloud Pub/Sub-Einbindung in Google Chat

Cloud Pub/Sub einrichten

In diesem Abschnitt wird beschrieben, wie Sie ein Cloud Pub/Sub-Thema einrichten und Ihre Anwendung abonnieren.

Pub/Sub-fähiges Google Cloud-Projekt erstellen

Wenn Sie Cloud Pub/Sub mit Ihrer Anwendung verwenden möchten, müssen Sie ein Google Cloud Platform-Projekt erstellen, für das die Pub/Sub API aktiviert ist.

  1. Erstellen Sie ein neues Projekt in der Google Cloud Console.
  2. Wählen Sie im linken Bereich der Konsole Pub/Sub und dann API aktivieren aus.

Pub/Sub-Thema erstellen

Erstellen Sie als Nächstes ein Thema, an das die Chat API Nachrichten senden soll. In der Kurzanleitung zur Pub/Sub-Konsole erfahren Sie, wie Sie ein Thema erstellen.

Google Chat API aktivieren

Achten Sie darauf, die Google Chat API zu aktivieren und auf das im vorherigen Schritt erstellte Thema festzulegen.

  1. Wählen Sie im linken Bereich der Konsole APIs und Dienste aus und aktivieren Sie die Google Chat API.
  2. Achten Sie beim Konfigurieren der API darauf, dass die Verbindungseinstellungen auf Cloud Pub/Sub festgelegt sind, und geben Sie das Thema aus dem vorherigen Schritt an.
  3. Füllen Sie die anderen Felder wie im Leitfaden zur Beispiel-App beschrieben aus.

Veröffentlichungsrechte für das Thema gewähren

Damit Google Chat Nachrichten zu Ihrem Thema veröffentlichen kann, muss es Veröffentlichungsrechte für das Thema haben. Wenn Sie Google Chat diese Berechtigungen erteilen möchten, weisen Sie dem folgenden Dienstkonto die Rolle Pub/Sub-Publisher zu:

chat-api-push@system.gserviceaccount.com

Dadurch wird Google Chat autorisiert, Inhalte zu Ihrem Thema zu veröffentlichen.

Dienstkonto erstellen

Damit Ihr Anwendungscode mit Cloud Pub/Sub und Google Chat autorisiert werden kann, muss er ein Dienstkonto verwenden. Informationen zum Einrichten eines Dienstkontos finden Sie unter Mit einem Dienstkonto bei der Chat API autorisieren und authentifizieren.

Abo erstellen

Folgen Sie dem Cloud Pub/Sub-Abonnentenleitfaden, um ein Abo für das von Ihnen erstellte Thema einzurichten. Konfigurieren Sie den Abotyp als Webhook-Pull. Fügen Sie dem Abo Berechtigungen für das Dienstkonto hinzu, das Sie im letzten Schritt erstellt haben, und weisen Sie ihm die Rolle „Pub/Sub-Abonnent“ zu.

Cloud Pub/Sub-Anwendung veröffentlichen

Wie Sie Ihre Anwendung veröffentlichen, erfahren Sie im Leitfaden Anwendungen veröffentlichen. Wählen Sie bei Cloud Pub/Sub-Anwendungen die Option für Cloud Pub/Sub aus und geben Sie den voll qualifizierten Namen des erstellten Themas ein. Der Themenname muss das folgende Format haben:

projects/PROJECT_ID/topics/TOPIC_ID

Beispiel: projects/pubsub-demo-2/topics/test-topic

Sobald Sie die Anwendung auf diese Weise veröffentlicht haben, können Nutzer sie verwenden und die Anwendung erhält Nachrichten unter dem von Ihnen konfigurierten Pub/Sub-Thema.

Das Beispiel im nächsten Abschnitt zeigt, wie Sie eine einfache Anwendung erstellen und ausführen, die diese Objekte implementiert.

Beispiel für eine App-Implementierung

Der folgende Beispielcode zeigt eine einfache Anwendung, die Cloud Pub/Sub zum Empfangen eingehender Nachrichten verwendet. Um diese App auszuprobieren, müssen Sie:

  • Bearbeiten Sie die Werte für die Projekt-ID und die Abo-ID in der Main-Klasse
  • Geben Sie die Anmeldedaten für das Dienstkonto an, wie unter Erste Schritte bei der Authentifizierung beschrieben.

    export GOOGLE_APPLICATIONCREDENTIALS=<path_to_service_account_file>

Zum Ausführen dieses Codes benötigen Sie die folgenden Abhängigkeiten in Ihrem Klassenpfad:

package com.google.chat;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.ByteArrayContent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpContent;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpTransport;
import com.google.cloud.pubsub.v1.AckReplyConsumer;
import com.google.cloud.pubsub.v1.MessageReceiver;
import com.google.cloud.pubsub.v1.Subscriber;
import com.google.pubsub.v1.PubsubMessage;
import com.google.pubsub.v1.ProjectSubscriptionName;
import java.io.FileInputStream;
import java.util.Collections;

public class Main {

  public static final String CREDENTIALS_PATH_ENV_PROPERTY = "GOOGLE_APPLICATION_CREDENTIALS";

  // Google Cloud Project ID
  public static final String PROJECT_ID = "my-project-id";

  // Cloud Pub/Sub Subscription ID
  public static final String SUBSCRIPTION_ID = "my-subscription-id";

  public static void main(String[] args) throws Exception {
    ProjectSubscriptionName subscriptionName =
        ProjectSubscriptionName.of(PROJECT_ID, SUBSCRIPTION_ID);

    // Instantiate app, which implements an asynchronous message receiver.
    EchoApp echoApp = new EchoApp();

    // Create a subscriber for "my-subscription-id" bound to the message receiver
    final Subscriber subscriber =
        Subscriber.newBuilder(subscriptionName, echoApp).build();
    System.out.println("Starting subscriber...");
    subscriber.startAsync();

    // Wait for termination
    subscriber.awaitTerminated();
  }
}

/**
 * A demo app which implements {@link MessageReceiver} to receive messages. It simply echoes the
 * incoming messages.
 */
class EchoApp implements MessageReceiver {

  // Path to the private key JSON file of the service account to be used for posting response
  // messages to Google Chat.
  // In this demo, we are using the same service account for authorizing with Cloud Pub/Sub to
  // receive messages and authorizing with Google Chat to post messages. If you are using
  // different service accounts, please set the path to the private key JSON file of the service
  // account used to post messages to Google Chat here.
  private static final String SERVICE_ACCOUNT_KEY_PATH =
      System.getenv(Main.CREDENTIALS_PATH_ENV_PROPERTY);

  // Developer code for Google Chat api scope.
  private static final String GOOGLE_CHAT_API_SCOPE = "https://www.googleapis.com/auth/chat.bot";

  // Response URL Template with placeholders for space id.
  private static final String RESPONSE_URL_TEMPLATE =
      "https://chat.googleapis.com/v1/__SPACE_ID__/messages";

  // Response echo message template.
  private static final String RESPONSE_TEMPLATE = "You said: `__MESSAGE__`";

  private static final String ADDED_RESPONSE = "Thank you for adding me!";

  GoogleCredential credential;
  HttpTransport httpTransport;
  HttpRequestFactory requestFactory;

  EchoApp() throws Exception {
    credential =
        GoogleCredential.fromStream(new FileInputStream(SERVICE_ACCOUNT_KEY_PATH))
            .createScoped(Collections.singleton(GOOGLE_CHAT_API_SCOPE));
    httpTransport = GoogleNetHttpTransport.newTrustedTransport();
    requestFactory = httpTransport.createRequestFactory(credential);
  }

  // Called when a message is received by the subscriber.
  @Override
  public void receiveMessage(PubsubMessage pubsubMessage, AckReplyConsumer consumer) {
    System.out.println("Id : " + pubsubMessage.getMessageId());
    // handle incoming message, then ack/nack the received message
    try {
      ObjectMapper mapper = new ObjectMapper();
      JsonNode dataJson = mapper.readTree(pubsubMessage.getData().toStringUtf8());
      System.out.println("Data : " + dataJson.toString());
      handle(dataJson);
      consumer.ack();
    } catch (Exception e) {
      System.out.println(e);
      consumer.nack();
    }
  }

  public void handle(JsonNode eventJson) throws Exception {
    JsonNodeFactory jsonNodeFactory = new JsonNodeFactory(false);
    ObjectNode responseNode = jsonNodeFactory.objectNode();

    // Construct the response depending on the event received.

    String eventType = eventJson.get("type").asText();
    switch (eventType) {
      case "ADDED_TO_SPACE":
        responseNode.put("text", ADDED_RESPONSE);
        // An app can also be added to a space by @mentioning it in a message. In that case, we fall
        // through to the MESSAGE case and let the app respond. If the app was added using the
        // invite flow, we just post a thank you message in the space.
        if(!eventJson.has("message")) {
          break;
        }
      case "MESSAGE":
        responseNode.put("text",
            RESPONSE_TEMPLATE.replaceFirst(
                "__MESSAGE__", eventJson.get("message").get("text").asText()));
        // In case of message, post the response in the same thread.
        ObjectNode threadNode = jsonNodeFactory.objectNode();
        threadNode.put("name", eventJson.get("message").get("thread").get("name").asText());
        responseNode.put("thread", threadNode);
        break;
      case "REMOVED_FROM_SPACE":
      default:
        // Do nothing
        return;
    }

    // Post the response to Google Chat.

    String URI =
        RESPONSE_URL_TEMPLATE.replaceFirst(
            "__SPACE_ID__", eventJson.get("space").get("name").asText());
    GenericUrl url = new GenericUrl(URI);

    HttpContent content =
        new ByteArrayContent("application/json", responseNode.toString().getBytes("UTF-8"));
    HttpRequest request = requestFactory.buildPostRequest(url, content);
    com.google.api.client.http.HttpResponse response = request.execute();
  }
}

Einschränkungen und Hinweise

Beachten Sie die folgenden Pub/Sub-Limits und Hinweise:

  • Zum Öffnen, Senden oder Abbrechen eines Dialogfelds ist eine synchrone Antwort von einer Chat-Anwendung mit einer DialogEventType erforderlich. Daher werden Dialogfelder von Chat-Anwendungen, die mit einer asynchronen Architektur wie Cloud Pub/Sub erstellt wurden, nicht unterstützt. Sie können das Problem umgehen, indem Sie anstelle eines Dialogfelds eine Kartennachricht verwenden.
  • Chatanwendungen, die mit Cloud Pub/Sub erstellt wurden, können einzelne Karten nicht mit einer synchronen Antwort aktualisieren. Aktualisieren Sie zum Aktualisieren einer Karte die gesamte Nachricht durch Aufrufen der API-Methode Patch Message.

Fehlerbehebung

Wenn eine Google Chat-App oder Google Chat-Karte einen Fehler zurückgibt, wird in der Chat-Oberfläche die Meldung „Ein Fehler ist aufgetreten“ oder „Ihre Anfrage konnte nicht verarbeitet werden“ angezeigt. Manchmal wird in der Chat-Benutzeroberfläche keine Fehlermeldung angezeigt, aber die Chat-App oder -Karte führt zu einem unerwarteten Ergebnis, z. B. kann es sein, dass keine Kartennachricht angezeigt wird.

Obwohl eine Fehlermeldung möglicherweise nicht in der Chat-Benutzeroberfläche angezeigt wird, sind beschreibende Fehlermeldungen und Protokolldaten verfügbar, mit denen Sie Fehler beheben können, wenn die Fehlerprotokollierung für Chat-Apps aktiviert ist. Informationen zum Aufrufen, Debuggen und Beheben von Fehlern finden Sie im Hilfeartikel Google Chat-Fehler beheben.