Tworzenie aplikacji Google Chat za zaporą sieciową przy użyciu Pub/Sub

Z tego artykułu dowiesz się, jak utworzyć aplikację do obsługi czatu przy użyciu Pub/Sub. Ten typ architektury aplikacji do obsługi czatu jest przydatny, jeśli Twoja organizacja ma zaporę sieciową, która może uniemożliwiać Google Chat wysyłanie wiadomości do aplikacji do obsługi czatu, lub gdy aplikacja Google Chat korzysta z interfejsu Google Workspace Event API. Ta architektura podlega jednak tym ograniczeniom, ponieważ aplikacje do obsługi czatu mogą wysyłać i odbierać tylko wiadomości asynchroniczne:

  • W wiadomościach nie można używać okien. Zamiast tego użyj wiadomości na karcie.
  • Nie można aktualizować poszczególnych kart z użyciem odpowiedzi synchronicznej. Zamiast tego zaktualizuj całą wiadomość, wywołując metodę patch.

Poniższy diagram przedstawia architekturę aplikacji do obsługi czatu utworzonej w Pub/Sub:

Architektura aplikacji do obsługi czatu wdrożonej w Pub/Sub.

Na poprzednim diagramie użytkownik korzystający z aplikacji do obsługi czatu Pub/Sub otrzymuje następujące informacje:

  1. Użytkownik wyśle wiadomość w Google Chat do aplikacji Google Chat na czacie lub w pokoju czatu albo wyśle zdarzenie w pokoju czatu, w przypadku którego aplikacja Google Chat ma aktywną subskrypcję.

  2. Google Chat wysyła wiadomość do tematu Pub/Sub.

  3. Serwer aplikacji, który jest systemem w chmurze lub lokalnym i zawiera logikę aplikacji Google Chat, subskrybuje temat Pub/Sub, aby odbierać wiadomość przez zaporę sieciową.

  4. Opcjonalnie aplikacja do obsługi czatu może wywoływać interfejs Chat API, aby asynchronicznie publikować wiadomości lub wykonywać inne operacje.

Wymagania wstępne

Java

Konfigurowanie środowiska

Zanim zaczniesz korzystać z interfejsów API Google, musisz włączyć je w projekcie Google Cloud. W jednym projekcie Google Cloud możesz włączyć 1 lub więcej interfejsów API.

Konfiguracja Pub/Sub

  1. Utwórz temat Pub/Sub, do którego interfejs Chat API może wysyłać wiadomości. Zalecamy używanie 1 tematu na każdą aplikację Google Chat.

  2. Przyznaj Google Chat uprawnienia do publikowania w temacie, przypisując rolę publikacji Pub/Sub do tego konta usługi:

    chat-api-push@system.gserviceaccount.com
    
  3. Utwórz konto usługi, aby aplikacja do obsługi czatu autoryzować w Pub/Sub i Google Chat oraz zapisać plik klucza prywatnego w katalogu roboczym.

  4. Utwórz subskrypcję pull dla tematu.

  5. Przypisz do subskrypcji rolę subskrybenta Pub/Sub dla wcześniej utworzonego konta usługi.

Tworzenie scenariusza

Java

  1. W interfejsie wiersza poleceń podaj dane logowania do konta usługi:

    export GOOGLE_APPLICATION_CREDENTIALS=SERVICE_ACCOUNT_FILE_PATH
    
  2. W katalogu roboczym utwórz plik o nazwie pom.xml.

  3. W pliku pom.xml wklej ten kod:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.google.chat.pubsub</groupId>
    <artifactId>java-pubsub-app</artifactId>
    <version>0.1.0</version>
    
    <name>java-pubsub-app</name>
    
    <properties>
      <maven.compiler.target>11</maven.compiler.target>
      <maven.compiler.source>11</maven.compiler.source>
    </properties>
    
    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>com.google.cloud</groupId>
          <artifactId>libraries-bom</artifactId>
          <version>26.26.0</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
      </dependencies>
    </dependencyManagement>
    
    <dependencies>
      <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.9.1</version>
      </dependency>
      <dependency>
        <groupId>com.google.api-client</groupId>
        <artifactId>google-api-client</artifactId>
        <version>1.32.1</version>
      </dependency>
      <dependency>
        <groupId>com.google.cloud</groupId>
        <artifactId>google-cloud-pubsub</artifactId>
      </dependency>
      <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.14.2</version>
      </dependency>
    </dependencies>
    
    <build>
      <pluginManagement>
        <plugins>
          <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
          </plugin>
        </plugins>
      </pluginManagement>
    </build>
    </project>
    
  4. W katalogu roboczym utwórz strukturę katalogów src/main/java.

  5. W katalogu src/main/java utwórz plik o nazwie Main.java.

  6. W interfejsie Main.java wklej ten kod:

    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 = PROJECT_ID;
    
      // Cloud Pub/Sub Subscription ID
      public static final String SUBSCRIPTION_ID = 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 <var>SUBSCRIPTION_ID</var> 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();
      }
    }
    

    Zastąp następujące elementy:

    • PROJECT_ID: identyfikator projektu Google Cloud.
    • SUBSCRIPTION_ID: identyfikator utworzonej wcześniej subskrypcji Pub/Sub.

Publikowanie aplikacji w Google Chat

  1. W konsoli Google Cloud kliknij Menu > Interfejsy API i usługi > Włączone interfejsy API i usługi > Google Chat API > Konfiguracja.

    Otwórz konfigurację

  2. Skonfiguruj aplikację Google Chat pod kątem Pub/Sub:

    1. W polu Nazwa aplikacji wpisz Quickstart App.
    2. W polu Avatar URL (URL awatara) wpisz https://developers.google.com/chat/images/quickstart-app-avatar.png.
    3. W polu Opis wpisz Quickstart app.
    4. W sekcji Funkcjonalność wybierz Odbieranie wiadomości 1:1 i Dołączanie do pokoi i rozmów grupowych.
    5. W sekcji Ustawienia połączenia wybierz Cloud Pub/Sub i wklej nazwę utworzonego wcześniej tematu Pub/Sub.
    6. W sekcji Widoczność wybierz Udostępnij tę aplikację Google Chat określonym osobom i grupom w domenie i wpisz swój adres e-mail.
    7. W sekcji Logi wybierz Rejestruj błędy w usłudze Logging.
  3. Kliknij Zapisz.

Aplikacja jest gotowa do odbierania wiadomości i odpowiadania na nie w Google Chat.

Uruchom skrypt

W interfejsie wiersza poleceń przejdź do katalogu roboczego i uruchom skrypt:

Java

mvn compile exec:java -Dexec.mainClass=Main

Gdy uruchomisz kod, aplikacja zacznie nasłuchiwać wiadomości opublikowanych w temacie Pub/Sub.

Testowanie aplikacji do obsługi czatu

Aby przetestować aplikację Google Chat, wyślij do niej wiadomość na czacie:

  1. Otwórz Google Chat.
  2. Aby wysłać wiadomość na czacie do aplikacji, kliknij Rozpocznij czat i w wyświetlonym oknie kliknij Znajdź aplikacje.
  3. W oknie Znajdź aplikacje wyszukaj „Quickstart App”.
  4. Aby otworzyć czat z aplikacją, znajdź aplikację szybkiego startu i kliknij Dodaj > Czat.
  5. W oknie czatu wpisz Hello i naciśnij enter. Aplikacja Google Chat odtworzy Ci wiadomość.

Aby dodać zaufanych testerów i dowiedzieć się więcej o testowaniu funkcji interaktywnych, przeczytaj artykuł Testowanie funkcji interaktywnych w aplikacjach Google Chat.

Rozwiązywanie problemów

Gdy aplikacja lub karta Google Chat zwróci błąd, interfejs czatu wyświetli komunikat „Coś poszło nie tak” lub „Nie udało się przetworzyć Twojej prośby”. Czasami w interfejsie Google Chat nie pojawia się żaden komunikat o błędzie, ale aplikacja lub karta Google Chat zwraca nieoczekiwany wynik, na przykład komunikat na karcie może się nie pojawić.

Mimo że komunikat o błędzie może nie wyświetlać się w interfejsie Google Chat, dostępne są opisowe komunikaty o błędach i dane dziennika, które pomogą Ci naprawić błędy występujące po włączeniu logowania błędów w aplikacjach do obsługi czatu. Informacje o wyświetlaniu, debugowaniu i naprawianiu błędów znajdziesz w artykule Rozwiązywanie problemów z Google Chat i ich naprawianie.