Статьи

Получение в реальном времени с Pusher

Вы хотите оживить свои веб-приложения, создав их в режиме реального времени, но не хотите создавать новые инфраструктуры с единственной целью — заставить веб-сокеты работать? В этой статье мы рассмотрим, как использовать и реализовывать Pusher , службу обмена сообщениями в реальном времени на основе HTML5 WebSocket для ваших приложений.


WebSocket Согласно странице WebSocket Wikipedia , WebSocket — это технология, обеспечивающая двунаправленные полнодуплексные каналы связи через один сокет TCP.

Иллюстрация WebSockets от Pusher

С точки зрения непрофессионала, WebSockets позволяет клиенту и серверу взаимодействовать в обоих направлениях. Это позволяет серверу отправлять сообщения клиенту, и наоборот.

На протяжении многих лет истечение срока действия данных всегда было проблемой для веб-приложений, особенно для тех, в которых несколько человек вошли в систему и работают над одними и теми же вещами. Например, в приложении для управления проектами пользователи иногда создают задачи, которые члены их команды создают одновременно. С помощью WebSockets это можно уменьшить, разрешив серверу отправлять уведомления всем подключенным сторонам, позволяя браузерам получать новые данные в режиме реального времени. По сути, перед созданием дублирующего элемента списка дел вы увидите, что его уже создал кто-то другой.

толкатель

Pusher — это размещенный API-интерфейс для быстрого, простого и безопасного добавления масштабируемой функциональности в реальном времени с помощью WebSockets для веб-приложений и мобильных приложений.

По сути, Pusher инкапсулирует реализацию, функциональность, отладку и хостинг WebSockets для вас.
Вместо того, чтобы запускать собственный сервер WebSockets, он позволяет разгрузить весь процесс на серверы Pusher, экономя ваше время и деньги.

Pusher — это размещенный API-интерфейс для быстрого, простого и безопасного добавления масштабируемой функциональности в реальном времени с помощью WebSockets для веб-приложений и мобильных приложений.

Чтобы Pusher работал, вам понадобится и клиентская библиотека, и библиотека издателя . Клиентские библиотеки используются с клиентом, который взаимодействует с вашим приложением. Это может быть браузер (через JavaScript), приложение для iPhone (через Objective-C) или приложение Flash (через ActionScript). Библиотеки Publisher используются на вашем сервере для отправки событий вашим клиентам.

В настоящее время у Pusher есть клиентские библиотеки для JavaScript, Objective-C, ActionScript, .NET и Silverlight, Ruby и Arduino. Он имеет библиотеки издателей для Node.js, Java, Groovy, Grails, Clojure, Python, VB.NET, C #, PHP, Ruby, Perl и ColdFusion.

В этом руководстве мы будем использовать клиентскую библиотеку JavaScript и библиотеку PHP-издателя. Реализация не должна быть слишком разной, если вы используете другой язык программирования.

Я чувствую, что создаю живой виджет чата, чтобы люди могли общаться в режиме реального времени на веб-сайте. Имея это в виду, давайте продолжим.


Для начала зайдите на сайт Pusher и зарегистрируйте свой аккаунт. Они предлагают бесплатную учетную запись для пользователей плана Sandbox, которая включает 20 подключений и 100 000 сообщений в день . Когда вы будете готовы, вы всегда можете перейти на платный план, но так как мы собираемся использовать его только для нашего примера приложения, бесплатный план Sandbox подойдет!

Регистрация толкача

Регистрация толкача

На сайте нажмите кнопку Зарегистрироваться , которую вы найдете в правом верхнем углу, и введите необходимые данные. После этого нажмите кнопку « Зарегистрироваться» еще раз, чтобы завершить регистрацию.


После регистрации вы будете перенаправлены на страницу администрирования Pusher . Здесь вы можете управлять всеми своими приложениями Pusher. Одна учетная запись может содержать несколько приложений.

Pusher Adminstration Page

Страница администрации толкача

Сверху у вас есть панель навигации, где вы найдете следующие разделы:

  • Панель инструментов — здесь вы увидите статистику своего приложения Pusher. Вы можете увидеть скорость сообщений (количество сообщений, отправленных за минуту), количество подключений (количество открытых подключений за определенное время) и количество сообщений (общее количество сообщений, отправляемых вашим приложением за день).
  • Изменить — здесь вы можете переименовать текущее приложение и выбрать, использовать ли шифрование SSL.
  • Доступ к API — содержит учетные данные API вашего приложения, которые потребуются нам позже.
  • Отладка — это отобразит все события, инициированные и сообщения, отправленные вашим приложением Pusher, а также когда клиенты подключаются или отключаются. Это чрезвычайно полезно при разработке вашего веб-приложения, поскольку вы можете увидеть здесь, что именно отправляет и получает Pusher и кто находится в сети, чтобы получить их.
  • Event Creator — это полезный инструмент для отправки тестовых событий вашим подключенным клиентам — без необходимости инициировать события самостоятельно из вашего веб-приложения.

Теперь вы готовы начать разработку с Pusher!


Давайте начнем разработку нашего живого виджета чата с создания HTML. Я имею в виду виджет, который появится в нижней части экрана со списком «Кто онлайн», например IRC.

1
<!DOCTYPE HTML> <html> <body> <div id=»chat_widget_container»> <div id=»chat_widget_login»> <label for=»chat_widget_username»>Name:</label> <input type=»text» id=»chat_widget_username» /> <input type=»button» value=»Login!»

Некоторые CSS для стиля нашего HTML:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#chat_widget_container{padding:20px 20px 5px 20px;
border-bottom:0px;
position:fixed;
 
#chat_widget_login{width:333px;
 
#chat_widget_main_container{display:none}
 
#chat_widget_messages_container{float:left;
padding:5px;
 
#chat_widget_messages{overflow-x:hidden;
 
#chat_widget_online{width:100px;
border-left:0px;
 
#chat_widget_online_list{list-style:none;
 
#chat_widget_online_list >li{margin-left:0px}
 
#chat_widget_input_container{margin-top:10px;
 
#chat_widget_input{width:260px;
 
#chat_widget_loader{display:none}
 
#chat_widget_login_loader{display:none}
 
.clear{clear:both}

Сочетание HTML и CSS, приведенное выше, должно отображать нечто вроде:

Демо Войти

Демо Войти

Нам нужно создать функцию, которая срабатывает, когда мы нажимаем кнопку « Вход» и проверяем введенное значение, поэтому давайте сделаем это:

01
02
03
04
05
06
07
08
09
10
11
12
13
$(‘#chat_widget_login_button’).click(function() {
    $(this).hide();
    $(‘#chat_widget_login_loader’).show();
    username = $(‘#chat_widget_username’).val();
    username = username.replace(/[^a-z0-9]/gi, »);
    if( username == » ) { //if blank, then alert the user
        alert(‘Please provide a valid username (alphanumeric only)’);
    } else { //else, login our user via start_session.php
        ajaxCall(‘start_session.php’, { username : username }, function() {
            //We’re logged in!
        });
    }
});

Затем нам нужно сообщить серверу, когда мы вошли в систему. Для этого мы создадим файл start_session.php, который по сути войдет в систему пользователя.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
//Start a PHP session
session_start();
 
//Get the username sent from the user
$username = $_REQUEST[‘username’];
 
//filter it
$username = trim(filter_var($username, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES));
 
//set the username for the session
$_SESSION[‘username’] = $username;
 
//set a unique id for the user.
//variable to generate a unique id, and add the user’s name to it and the user’s session id, then
//MD5 the whole thing
$_SESSION[‘userid’] = md5(time() + ‘_’ + $username + ‘_’ + session_id());
 
//echo the json_encoded success message for our ajax call
echo json_encode(array(‘success’ => true));
exit();
?>

Вы заметите, что я создал функцию ajaxCall , которая в основном просто оборачивается вокруг функции jQuery $ .ajax. Просто добавьте это перед строкой $ (document) .ready ().

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
function ajaxCall(ajax_url, ajax_data, successCallback) {
    $.ajax({
        type : «POST»,
        url : ajax_url,
        dataType : «json»,
        data: ajax_data,
        time : 10,
        success : function(msg) {
            if( msg.success ) {
                successCallback(msg);
            } else {
                alert(msg.errormsg);
            }
        },
        error: function(msg) {
        }
    });
}

Теперь давайте загрузим JavaScript-библиотеку Pusher и jQuery. Поместите следующие ссылки на скрипты в <head> вашего HTML:

1
2
<script src=»http://js.pusherapp.com/1.9/pusher.min.js»></script>
<script src=»https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js»></script>

Помните страницу доступа к API сверху? Вернитесь к нему и запишите свои учетные данные API. Нам понадобятся эти значения при настройке библиотек клиента и издателя.

Pusher API Credentials

Pusher API Credentials

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

Прежде чем мы начнем внедрять Pusher в наше приложение, нам нужно понять некоторые термины Pusher:

  • Канал — это способ дифференциации потоков данных внутри приложения. Приложение может иметь несколько каналов, и один канал может иметь несколько клиентов. Мы можем сравнить это с чатом в IRC — все сообщения, отправленные в определенную комнату чата, могут видеть все люди, которые находятся внутри.
  • События — это похоже на сервер, отправляющий данные клиенту, чтобы вы могли просматривать сообщения в чате. События запускаются библиотекой издателя, и клиенты могут подписаться на эти события. В нашей аналогии подписка на событие похожа на прослушивание, когда люди общаются в комнате, и принятие к сведению того, что они говорят.

Есть три типа каналов:

  • Публичные каналы — каналы, на которые может подписаться каждый, если они знают название канала.
  • Частные каналы — каналы, на которые могут подписаться только авторизованные пользователи.
  • Каналы присутствия — аналогичны частным каналам, но также позволяют нам сообщать другим подключенным клиентам информацию о подключении клиента. Мы будем использовать этот канал в нашем виджете чата.

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

Давайте начнем с подключения нашего клиента к сервису Pusher. Для этого нам нужно создать новый экземпляр объекта Pusher (из библиотеки) и вызвать функцию подписки . Добавьте следующий код после //We're logged in! Now what? //We're logged in! Now what? комментарий.

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

1
2
3
pusher = new Pusher(’12c4f4771a7f75100398′);
Pusher.channel_auth_endpoint = ‘pusher_auth.php’;
nettuts_channel = pusher.subscribe(‘presence-nettuts’);

При подписке на канал присутствия или частный канал нам необходимо убедиться, что подключающемуся пользователю разрешен доступ к каналу. Поэтому, прежде чем позволить клиенту полностью подключиться к нему, клиент Pusher автоматически выполняет вызов URL-адреса, определенного в переменной channel_auth_endpoint, и отправляет ему информацию о подключении пользователя. Затем через channel_auth_endpoint мы можем выяснить, авторизован ли подключающийся пользователь.

По умолчанию этот вызов выполняется для / pusher / auth , но мы можем переопределить его, установив переменную channel_auth_endpoint .

Последовательность аутентификации толкателя

Уникальный socket_id генерируется и отправляется в браузер Pusher. Когда делается попытка подписаться на socket_id канал или канал присутствия, socket_id и socket_id отправляются в ваше приложение (1) с помощью запроса AJAX POST, который разрешает пользователю доступ к каналу в вашей существующей системе аутентификации. В случае успеха ваше приложение возвращает строку авторизации в браузер, подписанную вашим секретом Pusher. Это отправляется Pusher через WebSocket, который завершает авторизацию (2), если строка авторизации совпадает.

Возвращаясь к нашему приложению, нам нужно создать нашу channel_auth_endpoint . Создайте файл с именем pusher_auth.php и поместите его внутрь:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
//Start the session again so we can access the username and userid
session_start();
 
//include the pusher publisher library
include_once ‘Pusher.php’;
 
//These values are automatically POSTed by the Pusher client library
$socket_id = $_POST[‘socket_id’];
$channel_name = $_POST[‘channel_name’];
 
//You should put code here that makes sure this person has access to this channel
/*
if( $user->hasAccessTo($channel_name) == false ) {
    header(», true, 403);
    echo( «Not authorized» );
    exit();
}
*/
 
$pusher = new Pusher(
    ’12c4f4771a7f75100398′, //APP KEY
    ‘51399f661b4e0ff15af6’, //APP SECRET
    ‘8896’ //APP ID
);
 
//Any data you want to send about the person who is subscribing
$presence_data = array(
    ‘username’ => $_SESSION[‘username’]
);
 
echo $pusher->presence_auth(
    $channel_name, //the name of the channel the user is subscribing to
    $socket_id, //the socket id received from the Pusher client library
    $_SESSION[‘userid’], //a UNIQUE USER ID which identifies the user
    $presence_data //the data about the person
);
exit();
?>

Теперь, когда мы можем аутентифицировать подключающихся пользователей, нам нужно привязать некоторые функции JavaScript к событиям Pusher, чтобы показать, что мы уже вошли в систему. Обновите код под //We're logged in! Now what? //We're logged in! Now what? комментарий, вот так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//We’re logged in!
pusher = new Pusher(’12c4f4771a7f75100398′);
Pusher.channel_auth_endpoint = ‘pusher_auth.php’;
nettuts_channel = pusher.subscribe(‘presence-nettuts’);
 
pusher.connection.bind(‘connected’, function() { //bind a function after we’ve connected to Pusher
    $(‘#chat_widget_login_loader’).hide();
    $(‘#chat_widget_login_button’).show();
     
    $(‘#chat_widget_login’).hide();
    $(‘#chat_widget_main_container’).show();
     
    //here, we bind to the pusher:subscription_succeeded event, which is called whenever you
    //successfully subscribe to a channel
    nettuts_channel.bind(‘pusher:subscription_succeeded’, function(members) {
        //this makes a list of all the online clients and sets the online list html
        //it also updates the online count
        var whosonline_html = »;
        members.each(function(member) {
            whosonline_html += ‘<li class=»chat_widget_member» id=»chat_widget_member_’ +
            member.id + ‘»>’ + member.info.username + ‘</li>’;
        });
        $(‘#chat_widget_online_list’).html(whosonline_html);
        updateOnlineCount();
    });
     
    //here we bind to the pusher:member_added event, which tells us whenever someone else
    //successfully subscribes to the channel
    nettuts_channel.bind(‘pusher:member_added’, function(member) {
        //this appends the new connected client’s name to the online list
        //and updates the online count as well
        $(‘#chat_widget_online_list’).append(‘<li class=»chat_widget_member» ‘ +
        ‘id=»chat_widget_member_’ + member.id + ‘»>’ + member.info.username + ‘</li>’);
        updateOnlineCount();
    });
     
    //here, we bind to pusher:member_removed event, which tells us whenever someone
    //unsubscribes or disconnects from the channel
    nettuts_channel.bind(‘pusher:member_removed’, function(member) {
        //this removes the client from the online list and updates the online count
        $(‘#chat_widget_member_’ + member.id).remove();
        updateOnlineCount();
    });
});

Не забудьте добавить updateOnlineCount (); Функция над строкой $(document).ready() :

1
2
3
function updateOnlineCount() {
    $(‘#chat_widget_counter’).html($(‘.chat_widget_member’).length);
}

Функция pusher.connection.bind позволяет нам связывать функцию обратного вызова при каждом изменении состояния соединения Pusher. Существует много возможных состояний, таких как инициализирован, подключен, недоступен, неисправен и отключен . Мы не будем использовать их в этом руководстве, но вы можете прочитать больше о них в документации Pusher .

Функция channel_name.bind позволяет нам привязать функцию к определенному событию, которое может произойти внутри канала. По умолчанию каналы присутствия имеют свои собственные события, с которыми мы можем связать функции, например, событие pusher: subscription_succeeded, которое мы использовали выше. Подробнее о них вы можете прочитать в документации по событиям Client Presence .

Давайте протестируем приложение сейчас и посмотрим, что произойдет. Для этого откройте две вкладки своего приложения и дважды войдите в систему. Вы должны увидеть что-то вроде этого:

Первый тест

Первый тест

Когда вы закрываете одну вкладку, второй клиент также закрывается, вызывая событие pusher: member_removed и удаляя клиента из онлайн-списка:

Второй тест

Второй тест

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

Давайте начнем с привязки функции к событию отправки в нашей форме чата:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
$(‘#chat_widget_form’).submit(function() {
  var chat_widget_input = $(‘#chat_widget_input’),
        chat_widget_button = $(‘#chat_widget_button’),
        chat_widget_loader = $(‘#chat_widget_loader’),
 
        message = chat_widget_input.val();
     
    chat_widget_button.hide();
    chat_widget_loader.show();
 
    ajaxCall(‘send_message.php’, { message : message }, function(msg) {
        //make an ajax call to send_message.php
        chat_widget_input.val(»);
        chat_widget_loader.hide();
        chat_widget_button.show();
 
        newMessageCallback(msg.data);
    });
 
    return false;
});

Функция newMessageCallback :

1
2
3
4
5
6
7
8
function newMessageCallback(data) {
    if( has_chat == false ) { //if the user doesn’t have chat messages in the div yet
        $(‘#chat_widget_messages’).html(»);
        has_chat = true;
    }
     
    $(‘#chat_widget_messages’).append(data.message + ‘<br />’);
}

После этого нам нужно создать send_message.php, чтобы получить наш AJAX-вызов сверху и вызвать событие new_message :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
//Start the session again so we can access the username
session_start();
 
//include the pusher publisher library
include_once ‘Pusher.php’;
 
$pusher = new Pusher(
    ’12c4f4771a7f75100398′, //APP KEY
    ‘51399f661b4e0ff15af6’, //APP SECRET
    ‘8896’ //APP ID
);
 
//get the message posted by our ajax call
$message = $_POST[‘message’];
 
//trim and filter it
$message = trim(filter_var($message, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES));
 
//wrap it with the user’s name when we display
$message = «<strong>&lt;{$_SESSION[‘username’]}&gt;</strong> {$message}»;
 
//trigger the ‘new_message’ event in our channel, ‘presence-nettuts’
$pusher->trigger(
    ‘presence-nettuts’, //the channel
    ‘new_message’, //the event
    array(‘message’ => $message) //the data to send
);
 
//echo the success array for the ajax call
echo json_encode(array(
    ‘message’ => $message,
    ‘success’ => true
));
exit();
?>

Вы, наверное, задаетесь вопросом, почему мы абстрагировали newMessageCallback в его собственную функцию. Что ж, нам придется вызывать его снова, когда мы получим событие new_message от Pusher. Следующий код связывает функцию с событием, называемым new_message , которое будет запускаться каждый раз, когда пользователь отправляет сообщение. Добавьте этот код после nettuts_channel.bind('pusher:member_removed') кода nettuts_channel.bind('pusher:member_removed') :

1
2
3
nettuts_channel.bind(‘new_message’, function(data) {
    newMessageCallback(data);
});

Переменная data в функции привязки выше будет данными, которые сервер отправляет в $pusher->trigger() , которые должны содержать данные сообщения.

Давайте попробуем наше приложение еще раз с two browsers , а не с вкладками. (Или попробуйте с другом, если вы его где-то загрузили.)

Рабочая Демо

Привет друг!

Поздравляем! Вы успешно создали работающее приложение, используя Pusher.


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

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

Этот урок только царапает поверхность Pusher и WebSockets в целом. С такими технологиями все, что вы можете сделать, ограничено только тем, что вы можете себе представить.

Вы пытались создать что-то с помощью Pusher или планируете сделать это в ближайшее время? Дай мне знать в комментариях!

Примечание. Pusher потребовал, чтобы мы сбросили учетные данные API, используемые демо-счетом в этом руководстве, в качестве меры предосторожности при злоупотреблении им. Я извиняюсь перед вами, ребята, и, надеюсь, вы можете получить свой собственный 🙂 Спасибо!