Создание чат-приложений

Оптимизируйте свои подборки Сохраняйте и классифицируйте контент в соответствии со своими настройками.

На этой странице описывается, как создавать приложения, которые получают, обрабатывают и реагируют на события из Google Chat:

  • Получать сообщения и другие события, генерируемые Google Chat
  • Отправляйте ответы на события и другие сообщения в Google Chat

Типы конечных точек

События из Google Chat доставляются в ваше приложение через конечную точку , которая бывает разных типов:

  • Конечные точки HTTPS представляют ваше приложение как веб-службу. Вам потребуется настроить веб-сервер для использования в качестве интерфейса для реализации вашего приложения. Ваше приложение может реагировать на эти события синхронно или асинхронно .
  • Конечные точки Google Cloud Pub/Sub используют тему в Google Cloud Pub/Sub для ретрансляции события в реализацию вашего приложения. Это полезно, когда ваша реализация находится за брандмауэром. Приложения, использующие конечные точки публикации/подписки, могут отвечать только асинхронно.
  • Конечные точки DialogFlow позволяют вашему приложению использовать возможности DialogFlow по обработке естественного языка (NLP). Подробности смотрите в документации DialogFlow .

Для простой и понятной архитектуры приложения попробуйте реализовать приложение, использующее конечную точку HTTPS (по сути, веб-службу), которая отвечает синхронно, всегда заключая свою полезную нагрузку в ответ HTTPS POST. Этот подход не требует авторизации, поэтому учетная запись службы не требуется. См. раздел реализации простого приложения ниже для примера этого стиля приложения.

Вам может потребоваться более сложный подход, если ваше приложение защищено брандмауэром или отправляет нежелательные сообщения, такие как сигналы тревоги или другие уведомления, в Google Chat.

Очень простая реализация приложения

Следующий код реализует простое приложение на Python с использованием веб-фреймворка Flask .

#!/usr/bin/env python3
"""Example app that returns a synchronous response."""

from flask import Flask, request, json


app = Flask(__name__)


@app.route('/', methods=['POST'])
def on_event():
  """Handles an event from Google Chat."""
  event = request.get_json()
  if event['type'] == 'ADDED_TO_SPACE' and not event['space']['singleUserBotDm']:
    text = 'Thanks for adding me to "%s"!' % (event['space']['displayName'] if event['space']['displayName'] else 'this chat')
  elif event['type'] == 'MESSAGE':
    text = 'You said: `%s`' % event['message']['text']
  else:
    return
  return json.jsonify({'text': text})


if __name__ == '__main__':
  app.run(port=8080, debug=True)

Поскольку это веб-служба, приложение представляет собой конечную точку HTTPS, и ему не нужно использовать Cloud Pub/Sub для ретрансляции событий. А поскольку он всегда возвращает полезную нагрузку ответа в ответе JSON, ему не нужно проходить аутентификацию с использованием учетной записи службы.

Обработка событий из Google Chat

В этом разделе описывается, как получать и обрабатывать события, которые ваше приложение получает от Google Chat.

Зарегистрируйте приложение

Прежде чем ваше приложение сможет получать события из Google Chat, вы должны указать его конечную точку на вкладке конфигурации Chat API при публикации приложения .

После того как вы зарегистрируете конечную точку и опубликуете свое приложение, Google Chat распознает события, адресованные вашему приложению, и отправит их на указанную конечную точку.

Подтвердить подлинность приложения

После того как вы зарегистрировали свое HTTPS-приложение , вам нужен способ для вашей реализации, чтобы убедиться, что запрос действительно исходит от Google.

Google Chat включает токен носителя в заголовок Authorization каждого HTTPS-запроса к приложению. Например:

POST
Host: yourappurl.com
Authorization: Bearer AbCdEf123456
Content-Type: application/json
User-Agent: Google-Dynamite

Строка AbCdEf123456 в приведенном выше примере является токеном авторизации носителя. Это криптографический токен, созданный Google. Вы можете проверить свой токен на предъявителя с помощью клиентской библиотеки Google API с открытым исходным кодом:

Все токены-носители, отправленные с запросами из чата Google, будут иметь chat@system.gserviceaccount.com в качестве отправителя, а в поле audience будет указан номер проекта целевого приложения из Google API Console . Например, если запрос для приложения с номером проекта 1234567890 , то аудитория — 1234567890 .

Вы должны убедиться, что запрос исходит от Google и предназначен для целевого приложения. Если токен не проходит проверку, приложение должно ответить на запрос с кодом ответа HTTPS 401 (Unauthorized) .

Ява

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager;
import com.google.api.client.http.apache.ApacheHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;

/** Tool for verifying JWT Tokens for Apps in Google Chat. */
public class JWTVerify {
  // Bearer Tokens received by apps will always specify this issuer.
  static String CHAT_ISSUER = "chat@system.gserviceaccount.com";

  // Url to obtain the public certificate for the issuer.
  static String PUBLIC_CERT_URL_PREFIX =
      "https://www.googleapis.com/service_accounts/v1/metadata/x509/";

  // Intended audience of the token, which will be the project number of the app.
  static String AUDIENCE = "1234567890";

  // Get this value from the request's Authorization HTTPS header.
  // For example, for "Authorization: Bearer AbCdEf123456" use "AbCdEf123456"
  static String BEARER_TOKEN = "AbCdEf123456";

  public static void main(String[] args) throws GeneralSecurityException, IOException {
    JsonFactory factory = new JacksonFactory();

    GooglePublicKeysManager.Builder keyManagerBuilder =
        new GooglePublicKeysManager.Builder(new ApacheHttpTransport(), factory);

    String certUrl = PUBLIC_CERT_URL_PREFIX + CHAT_ISSUER;
    keyManagerBuilder.setPublicCertsEncodedUrl(certUrl);

    GoogleIdTokenVerifier.Builder verifierBuilder =
        new GoogleIdTokenVerifier.Builder(keyManagerBuilder.build());
    verifierBuilder.setIssuer(CHAT_ISSUER);
    GoogleIdTokenVerifier verifier = verifierBuilder.build();

    GoogleIdToken idToken = GoogleIdToken.parse(factory, BEARER_TOKEN);
    if (idToken == null) {
      System.out.println("Token cannot be parsed");
      System.exit(-1);
    }

    // Verify valid token, signed by CHAT_ISSUER.
    if (!verifier.verify(idToken)
        || !idToken.verifyAudience(Collections.singletonList(AUDIENCE))
        || !idToken.verifyIssuer(CHAT_ISSUER)) {
      System.out.println("Invalid token");
      System.exit(-1);
    }

    // Token originates from Google and is targeted to a specific client.
    System.out.println("The token is valid");
  }
}

питон

import sys

from oauth2client import client

# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'

# Url to obtain the public certificate for the issuer.
PUBLIC_CERT_URL_PREFIX = 'https://www.googleapis.com/service_accounts/v1/metadata/x509/'

# Intended audience of the token, which will be the project number of the app.
AUDIENCE = '1234567890'

# Get this value from the request's Authorization HTTPS header.
# For example, for 'Authorization: Bearer AbCdEf123456' use 'AbCdEf123456'.
BEARER_TOKEN = 'AbCdEf123456'

try:
  # Verify valid token, signed by CHAT_ISSUER, intended for a third party.
  token = client.verify_id_token(
      BEARER_TOKEN, AUDIENCE, cert_uri=PUBLIC_CERT_URL_PREFIX + CHAT_ISSUER)

  if token['iss'] != CHAT_ISSUER:
    sys.exit('Invalid issuee')
except:
  sys.exit('Invalid token')

# Token originates from Google and is targeted to a specific client.
print 'The token is valid'

Полезная нагрузка события

Когда ваше приложение получает событие от Google Chat, это событие включает текст запроса : это полезные данные JSON, представляющие событие. Тело запроса всегда включает следующую информацию:

  • type : Строка, указывающая тип события.
  • eventTime : строка, содержащая метку времени события.

Дополнительная информация, содержащаяся в теле запроса, зависит от типа события. В следующем примере показана возможная полезная нагрузка:

{
  "type": "MESSAGE",
  "eventTime": "2017-03-02T19:02:59.910959Z",
  "space": {
    "name": "spaces/AAAAAAAAAAA",
    "displayName": "Best Dogs Discussion Space",
    "type": "ROOM"
  },
  "message": {
    "name": "spaces/AAAAAAAAAAA/messages/CCCCCCCCCCC",
    "sender": {
      "name": "users/12345678901234567890",
      "displayName": "Chris Corgi",
      "avatarUrl": "https://lh3.googleusercontent.com/.../photo.jpg",
      "email": "chriscorgi@example.com"
    },
    "createTime": "2017-03-02T19:02:59.910959Z",
    "text": "I mean is there any good reason their legs should be longer?",
    "thread": {
      "name": "spaces/AAAAAAAAAAA/threads/BBBBBBBBBBB"
    }
  }
}

Дополнительные сведения о различных типах событий и форматах их запросов см. в справочнике по форматам событий.

Обработать событие

Когда ваше приложение получает событие от Google Chat, то, что оно делает с этим событием, полностью зависит от реализации. Приложение может искать некоторую информацию из источника данных, записывать информацию о событии или что-то еще. Это поведение обработки, по сути, и определяет приложение.

В большинстве случаев приложение не только обрабатывает информацию, содержащуюся в событии, но и формирует ответ потоку, создавшему событие. На следующей диаграмме показано типичное взаимодействие с приложением в пространстве чата.

На приведенной выше диаграмме показаны три вида событий: ADDED_TO_SPACE , MESSAGE и REMOVED_FROM_SPACE . Приложение не может ответить после удаления из пространства, но может ответить на два других типа.

Отвечать синхронно

Приложение может синхронно реагировать на событие, возвращая полезные данные сообщения в формате JSON в ответе HTTPS. Крайний срок для синхронного ответа составляет 30 секунд.

Синхронный ответ от приложения всегда публикуется в потоке, создавшем событие для приложения.

Отвечать асинхронно

Если приложению необходимо ответить на сообщение пользователя после истечения 30-секундного срока (например, ему может потребоваться отчитаться после завершения длительной задачи), оно может ответить асинхронно, создав сообщение с помощью Chat REST API .

Повторить попытку

Если HTTPS-запрос к вашему приложению завершается неудачно (например, тайм-аут, временный сбой сети или код состояния HTTPS, отличный от 2xx), Google Chat дополнительно повторяет доставку дважды с задержкой не менее десяти секунд между каждой повторной попыткой. В результате приложение может получить одно и то же сообщение до трех раз в определенных ситуациях. Повторная попытка не предпринимается, если запрос завершается успешно, но возвращает недопустимую полезную нагрузку сообщения.