Крестики-нолики с помощью Channel API на Google App Engine и Java

в 5:10, , рубрики: google app engine, метки:

Представляю вашему вниманию рассказ об использовании Сhannel API в игре крестики-нолики по мотивам вот этой статьи: Channel API Overview (Java).
Крестики нолики с помощью Channel API на Google App Engine и Java

На хабре уже была статья об Channel API, но там python и чат, а здесь будет игра в крестики нолики и java. Исходники игры здесь, автор исходников не я. Если у Вас не заработало то сделайте как написано в Issue 3.

Как известно Channel API позволяет установить соединение между клиентом (web-страница, javascript) и Google App Engine. Здесь знающие люди говорят что работает это через XMPP в данный момент, но в дальнейшем возможно можно будет использовать и WebSockets. Для игры в крестики нолики это означает что игрок сможет получить результат хода своего оппонента не используя поллинг. Подключить javascript библиотеку и создать канал можно следующим образом (на стороне клиента):

        <script src='/_ah/channel/jsapi'></script>  // Здесь js-api

        // token - уникальный идентификатор канала
        var channel = new goog.appengine.Channel(token);
        
        // Для канала указываются js-обработчики событий
        var handler = {
          'onopen': onOpened,         // обработчик открытия
          'onmessage': onMessage, // обработчик получения сообщения
          'onerror': function() {},
          'onclose': function() {}
        };
        var socket = channel.open(handler);
        socket.onopen = onOpened;
        socket.onmessage = onMessage;

В этом коде token — уникальный идентификатор канала (далее токен). В данной игре он записывается сервером прямо в веб-страницу и клиент сразу его имеет. Токен формируется сервером с помощью вызова метода

String token = ChannelServiceFactory.getChannelService().createChannel("ваша строка");

. Срок действия токена составляет 2 часа. В данном примере в createChannel передается идентификатор который формируется из id пользователя (

String userId = UserServiceFactory.getUserService().getCurrentUser().getUserId();

) и ключа игры, по которому объект игры сохраняется в постоянном хранилище. При входе для каждого пользователя сразу создается игра, в которую он может пригласить другого игрока передав ему ссылку, содержащую ключ игры. Параметр createChannel должен быть короче 64 байт при представлении в utf-8 (Issue 3), собственно там есть фикс потому что в исходниках из svn с этим проблемы.

В данном примере используется 3 сервлета. TicTacToeServlet делает всю основную работу создавая для пользователя игру, канал, и записывая все необходимое в тело веб-страницы. OpenedServlet отвечает на запрос клиента после того как клиент загрузившись создает канал на своей стороне и выдает клиенту текущее состояние игры. Игра в данном случае либо еще не началась либо если клиент перезагрузит страницу в процессе игры имеет состояние отличное от начального. MoveServlet получает запросы клиентов о выполнении ими своего хода, и обновляет игру. Что включает и рассылку обновлений игрокам с помощью Channel API. Таким образом Channel API используется для обновления состояния игры для обеих участников.

Так же из интересного здесь использование JDO для хранения игр. Возможно для хранения игр лучше было бы использовать Memcache. И еще как сделано игровое поле — canvas не используется.

Так же Channel API может использоваться для проверки подключения/отключения клиентов. Для этого в appengine-web.xml нужно добавить:

<inbound-services>
    <service>channel_presence</service>
</inbound-services>

Тогда клиенты будут стучаться к вам POST-сообщениями на /_ah/channel/connected/ и /_ah/channel/disconnected/ при коннекте и дисконнекте соответственно. Проверить подключение на стороне сервера можно так:


    ChannelServiceFactory.getChannelService();
    ChannelPresence presence = channelService.parsePresence(req);
    String id = presence.clientId();
    boolean connected = presence.isConnected();

Что можно использовать расширив пример и добавив туда возможность выбора соперников из списка подключенных игроков.

Токен — ключ канала желательно хранить в секрете. Через 2 часа его срок действия истекает и на клиенте срабатывают обработчики onerror(), onclose() (см. код создания канала).

Из минусов данной технологии стоит отметить отсутствие встроенного броадкастинга. Т.е. общий чат делать нужно самому. Также одна веб-страница не может создавать более одного канала.

Исходники примера здесь. Для работы с версией SDK 1.7 мне пришлось добавить

<threadsafe>true</threadsafe>

в appengine-web.xml.
Также здесь описано как создать чат на Google App Engine/java c помощью Channel API: Tutorial: Code Lab Exercise 4: Channel API.

Автор: ChernovDmitry

* - обязательные к заполнению поля