Привет!
Продолжая статьи о Центрифуге, мне хотелось бы обсудить один из способов подключения реал-тайм событий на сайт.
Суть отдельностоящих серверов рассылки сообщений в реальном времени такова, что клиенты из браузера должны подключиться к серверу, подписаться на нужные каналы и ждать сообщений из этих каналов.
Давайте посмотрим, что нам предлагает Центрифуга:
var centrifuge = new Centrifuge({
url: 'http://localhost:8000/connection',
token: 'TOKEN',
project: 'PROJECT_ID',
user: 'USER_ID'
});
centrifuge.on('connect', function() {
centrifuge.subscribe('public:comments', function(message) {
// message from channel received
});
});
Вполне легко и просто, правда? Но возможно ли сделать еще проще?
В общем случае, пожалуй, нет. Конец статьи!
Стоп, стоп, конечно же нет, давайте посмотрим на частный случай. Если ваше веб-приложение требует достаточно сложной логики подписок, публикаций, менеджмента каналов, то скорее всего вариант, который я опишу ниже, не для вашего сайта. Однако, большинство веб-приложений не стремятся выжать максимум реалтаймовых возможностей — и все что им нужно — это слушать определенные каналы, которые динамически не меняются, получать события и реагировать на них, в большинстве случаев просто отрисовывая изменения на веб-странице. Это комментарии, счетчики, уведомления, графики и многое другое.
Многие из вас слышали о Knockout, AngularJS. Одно из средств, применяемых этими библиотеками — вынесение описания логики приложения в html страницы. Задавая атрибуты и их значения, вы можете легко менять поведение на желаемое. Что если воспользоваться html и в нашем случае?
Посмотрим на подключение к Центрифуге. Нужно передать адрес, токен, идентификатор пользователя и идентификатор проекта. Клиентская часть узнает нужные значения от бэкенда. Имена нужных каналов для подписки также передает в шаблон бэкенд. Как сообщить эти данные джаваскрипту?
Рассмотрим самые очевидные варианты. Можно передать эти данные в виде JSON на вход инициализирующей функции. А можно отрендерить данные на веб-странице как атрибуты html-элементов, а затем из кода обращаться к нужным элементам, брать значения их свойств и использовать. И этот второй вариант мне представляется наиболее гибким. Настолько гибким, что подобным образом программист, желающий использовать Центрифугу, может поступать на всех страничках с реал-тайм элементами.
Поэтому, чтобы вам не пришлось писать свою обертку, я написал jQuery плагин centrifuge.dom.js:
<script src="raw.github.com/FZambia/centrifuge/master/javascript/centrifuge.dom.js"></script>
Будучи подключенным, он цепляет данные из отрендеренных на страничке html-элементов, сам создает на их основе подключение к Центрифуге, подписывается на каналы. А когда приходит сообщение — триггерит событие на html-элементе с полученными данными.
Всё что остается вам в данном случае — описать, как будет реагировать веб-страница на полученное сообщение, то есть:
$(' #html-element').on('centrifuge.message', function(message) {
console.log(message.data);
});
Это, вкупе с парой строк инициализации плагина в основном шаблоне веб-приложения, будет весь js-код, необходимый для добавления реал-тайм событий на сайт.
Рассмотрим, как это выглядит на практике и возьмем в качестве примера комментарии. Пользователь пишет комментарий, после сабмита формы отправляется Ajax-запрос к вашему приложению, вы делаете валидацию и сохранение как обычно, после чего отправляете сообщение в нужный канал Центрифуги для того, чтобы новый комментарий моментально появился у всех пользователей.
1) В основном шаблоне инициализируем плагин:
$(function(){
$.centrifuge_dom({});
});
2) Также в основном шаблоне прописываем постоянные html-элементы с токеном, адресом и идентификаторами:
<div id="centrifuge-address" data-centrifuge-value="{{ centrifuge_address }}"></div>
<div id="centrifuge-token" data-centrifuge-value="{{ centrifuge_token }}"></div>
<div id="centrifuge-user" data-centrifuge-value="{{ centrifuge_user }}"></div>
<div id="centrifuge-project" data-centrifuge-value="{{ centrifuge_project }}"></div>
Здесь используется синтаксис django-шаблонов, данные об адресе, токене, ID юзера и проекта предоставляет бэкенд вашего приложения.
3) На странице с комментариями добавляем html-элемент с именем канала:
<div class="centrifuge" id="comments-handler" data-centrifuge-channel="comments" data-centrifuge-namespace=”public”></div>
4) И на этой же страничке c комментариями добавляем javascript:
$(function() {
$(‘#comments-handler’).on(‘centrifuge.message’, function(message) {
$(‘body’).append(message.data);
});
});
Всё!
Более того, теперь, чтобы добавить новый реал-тайм элемент на любую страницу, вам потребуется выполнить только последние 2 пункта.
Вариант не учитывает возможных ошибок, в некоторых случаях вам и не потребуется их отлавливать. Но в любом случае плагин предоставляет возможность повесить дополнительные обработчики событий на html-элемент, такие как centrifuge.error
, centrifuge.disconnect
, чтобы должным образом среагировать.
Та ли это идеальная простота, о которой говорил Альберт Эйнштейн (его знаменитый афоризм в основе заголовка данной статьи) — покажет время.
Напоследок, хотелось бы отметить некоторые изменения, случившиеся с момента предыдущей публикации.
Центрифуга доросла до версии 0.3.1.
Теперь для PUB/SUB механизма можно использовать Redis вместо ZeroMQ. А в случае если вам достаточно одного инстанса Центрифуги, то можно обойтись вообще без них.
Можно установить Центрифугу без ненужных вам зависимостей, используя флаги setup.py: --without-zmq
, --without-redis
, --without-postgresql
, --without-mongodb
Переделан веб-интерфейс, он теперь хорошо выглядит на мобильных устройствах и, на мой взгляд, стал гораздо симпатичней.
Из раздела “менеджмент проекта” можно публиковать JSON в каналы (для этого используется Ace editor), a также запрашивать presence, history данные канала и отписывать пользователя по ID.
Появилось API для структуры проектов и пространств имен — абсолютно все действия теперь можно выполнять не используя веб-интерфейс.
На этом пока всё, до новых встреч, друзья!
Автор: FZambia