Как играть! Работа кометы?

Я увидел, что в описании модуля Akka говорится, что Play имеет отличную поддержку Comet, но я никогда не использовал Comet, и я не могу найти упоминания об этом в документации Play. Как это работает в Play?


Я потратил несколько часов в течение двух дней на то, чтобы понять это, поэтому я хотел поделиться этой информацией для других начинающих игр.

Ответы

Ответ 1

Воспроизведение включает пример приложения чата, который демонстрирует, как использовать комету. Пример не объясняет, что происходит, поэтому вот что я понял.

Model

Чтобы другие могли найти новые обновления, которые вы отправляете, их нужно будет где-то хранить. По-видимому, это может быть в кеше или даже в самом контроллере, но база данных будет самой безопасной ставкой, поэтому вам понадобится модель. Им также понадобится способ определить, какие обновления для них новы, а это значит, что вам, вероятно, понадобится поле даты (см. Также: Временная метка последнего обновления с JPA)., В примере чата используется простая модель:

@Entity
public class Message extends Model {     
    public String user;
    public Date date;
    public String text;

    public Message(String user, String text) {
        this.user = user;
        this.text = text;
        this.date = new Date();
    }       
}

контроллер

Контроллер нуждается в двух методах, чтобы облегчить комету. Там, где публикуются новые данные, что не делает ничего особенного:

public static void postMessage(String message) {
    new Message(session.get("nick"), message).save();
}

и один для получения обновлений:

public static void newMessages() {
    List<Message> messages = Message.find("date > ?", request.date).fetch();
    if (messages.isEmpty()) {
        suspend("1s");
    }
    renderJSON(messages);
}

Ключевым битом здесь является suspend("1s"), который является тем, что содержит HTTP-запрос, открытым, проверяя новые данные один раз в секунду.

Вид

В представлении есть три обязанности - отправка новых данных, выборка обновлений и последующее предоставление этих обновлений.

Отправка, как и соответствующее действие контроллера, не делает ничего особенного:

$('#send').click(function(e) {
    var message = $('#message').val();
    $('#message').val('');
    $.post('@{postMessage()}', {message: message}); 
});

Получение обновлений - это волшебный бит:

// Retrieve new messages
var getMessages = function() {
    $.ajax({
        url: '@{newMessages()}',
        success: function(messages) {
            $(messages).each(function() {
                display(this);
            });
        },
        complete: function() {
            getMessages();
        },
        dataType: 'json'
    });
}
getMessages();

getMessages() вызывается один раз, чтобы начать все, а затем он вызывает себя рекурсивно после каждого успешного запроса. Он ПОЛУЧИТ действие newMessages(), которое ищет новые сообщения, и если они отсутствуют, запрос остается открытым до тех пор, пока он не сможет что-то сообщить. Когда новые сообщения обнаружены, данные JSON передаются функции display:

var display = function(message) {
    $('#thread').append(tmpl('message_tmpl', {message: message}));
}

Функция display применяет JavaScript-шаблон для JavaScript к данным JSON для визуализации новых сообщений. Использование микро шаблонов не требуется, но это работает очень хорошо. Они включены прямо в шаблон страницы, которая будет их использовать:

<script type="text/html" id="message_tmpl">
    <div class="message <%= message.user == '${session.nick}' ? 'you' : '' %> <%= message.user == 'notice' ? 'notice' : '' %>">
        <h2><%= message.user %></h2>
        <p><%= message.text.replace('\n', '<br/>') %></p>
    </div>
</script>

type="text/html" заставляет браузеры, поисковые системы и устройства чтения с экрана игнорировать весь блок script. Результат намного легче читать и поддерживать, чем использовать jQuery для сборки узлов или объединения строк. В целом это довольно просто, как только вы знаете, какие биты имеют значение.

Ответ 2

Существует множество способов достижения сервер-push или Comet в веб-приложениях, а одним из наиболее распространенных является Long Polling, благодаря тому, что он хорошо поддерживается в большинстве современных браузеров.

Play выполняет длительный опрос в основном через функцию suspend(time);. Эта функция выполняет две очень важные вещи.

  • он сохраняет HTTP-запрос открытым и повторяет действие в указанное время. Это позволяет вам удерживать HTTP-запрос и продолжать повторять действие до тех пор, пока не произойдет что-то, что вы хотите сообщить обозревателю о

  • и очень важно, что поток освобождается при приостановке запроса. Это означает, что HTTP-запрос не содержит открытый поток для каждого приостановленного запроса.

Когда воспроизведение выполняется в режиме DEV, оно работает только в одном потоке, но вы можете (и я попытался) запустить десятки пользователей в примере приложения чата без зависания сервера или пользователей, получающих заблокированные запросы.

Однако метод приостановки - это единственное, что действительно помогает, чтобы помочь с кометами. Если вы запустите образец приложения чата и оставьте его открытым, вы заметите, что через 120 секунд запрос будет тайм-аут. Образец приложения не повторяет запрос. Клиентская сторона технологии долгосрочного опроса, которую вы должны создать самостоятельно.

Гийом упомянул в форумах, что пример чата - всего лишь демонстрация того, как долго можно использовать опрос. Поэтому я не думаю, что Play может подтвердить, что у вас отличная поддержка Comet, это всего лишь шаг в правильном направлении.