Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Создание виджета «Счет Live» использую PHP Web Sockets

Anna | 31.05.2014 | нет комментариев
Внедрение веб-сокетов разрешает веб-приложения обрабатывать данные в режиме реального времени, не прибегая к «хакам», таким как long-polling.
Одним из примеров использования, является отображение итогов спортивного матча. Даже теперь, много сайтов, которые показывают эти данные применяют Flash-приложения, т.к. Action Script разрешает общаться с сервером через сокет-соединения. Тем не менее, вев-сокеты разрешают сделать тоже самое применяя только HTML и JavaScript. Это, мы постараемся сделать в данном начальстве, применяя php-сервер.
image

Установка и настройка

Мы будем применять библиотеку Ratchet, разрешающую PHP применять web-сокеты.
Сделайте дальнейший composer.json, тот, что устанавливает как эту связанность, так и автозагрузку для кода, тот, что мы напишем дальше:

{
    "require": {
        "cboden/Ratchet": "0.2.*"
    },
    "autoload": {
        "psr-0": {
            "LiveScores": "src"
        }
    }    
}

Теперь сделайте следующую конструкцию каталогов:

[root]
    bin
    src
        LiveScores
    public
        assets
            css
                vendor
            js
                vendor
    vendor

Допустимо, вы захотите взять все из репозитория, тот, что содержит ряд надобных css, js и изображений, а так же каждый код из этого начальства. Если же вы хотите писать все с нуля, параллельно с начальством, то скопируйте только public/assets/*/vendor.
Безусловно, не позабудьте запустить php composer.phar update. Если у вас не установлен composer, установите его исполнив curl -sS getcomposer.org/installer | php.
Мы начнем с создания класса, тот, что будет принимать подключения и отправлять сообщения. Позднее, мы будем его применять для обновления данных о идущий играх. Это фундамент класса, что бы показать как работает брокер сообщений:

// src/LiveScores/Scores.php

<?php namespace LiveScores;

use RatchetMessageComponentInterface;
use RatchetConnectionInterface;

class Scores implements MessageComponentInterface {

    private $clients;    

    public function __construct() 
    {    
        $this->clients = new SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn) 
    {
        $this->clients->attach($conn);
    }

    public function onMessage(ConnectionInterface $from, $msg) 
    {            
        foreach ($this->clients as $client) {
            if ($from !== $client) {
                // The sender is not the receiver, send to each client connected
                $client->send($msg);
            }
        }
    }

    public function onClose(ConnectionInterface $conn) 
    {
        $this->clients->detach($conn);
    }

    public function onError(ConnectionInterface $conn, Exception $e) 
    {     
        $conn->close();
    }

}

Значимо подметить:

  • Класс должен реализовывать MessageComponentInterface для того, что бы выступать в качестве брокера сообщений
  • Мы бережем список всех подключенных заказчиков в виде коллекции
  • Когда заказчик добавляется, вызывается событие onOpen, и заказчик добавляется в коллекцию
  • Способ onClose делает противоположное
  • Интерфейс также требует от нас создания обработчика ошибок

Дальнейшим шагом будет создания демона, тот, что будет создавать экземпляр нашего класса, будет слушать входящие соединения. Сделайте файл:

// bin/server.php

<?php
use RatchetServerIoServer;
use RatchetWebSocketWsServer;
use LiveScoresScores;

require dirname(__DIR__) . '/vendor/autoload.php';

$server = IoServer::factory(
    new WsServer(
        new Scores()
    )
    , 8080
);

$server->run();

Все это нуждается в пояснениях. WsServer — является реализацией больше всеобщего класса IoServer, тот, что осуществляет передачу данных через web-сокет. Мы будем слушать 8080 порт. Вы можете предпочесть всякий порт, основное проверьте, Дабы он не блокировался брендмауэром.

Поддержание состояния

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

// src/LiveScores/Fixtures.php
<?php namespace LiveScores;

class Fixtures {

    public static function random()
    {
        $teams = array("Arsenal", "Aston Villa", "Cardiff", "Chelsea", "Crystal Palace", "Everton", "Fulham", "Hull", "Liverpool", "Man City", "Man Utd", "Newcastle", "Norwich", "Southampton", "Stoke", "Sunderland", "Swansea", "Tottenham", "West Brom", "West Ham");

        shuffle($teams);

        for ($i = 0; $i <= count($teams); $i  ) {
            $id = uniqid();
            $games[$id] = array(
                'id' => $id,
                'home' => array(
                    'team' => array_pop($teams),
                    'score' => 0,
                ),
                'away' => array(
                    'team' => array_pop($teams),
                    'score' => 0,
                ),
            );
        }

        return $games;
    }

}  

Обратите внимание, что мы присваиваем всякой игре неповторимый id, тот, что мы будем применять дальше, Дабы указать в какой игре случилось событие. Вернёмся к нашем Score классу:

// src/LiveScores/Scores.php

public function __construct() {

    // Create a collection of clients
    $this->clients = new SplObjectStorage;

    $this->games = Fixtures::random();
}

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

// src/LiveScores/Scores.php

public function onOpen(ConnectionInterface $conn) {
    // Store the new connection to send messages to later
    $this->clients->attach($conn);

    // New connection, send it the current set of matches
    $conn->send(json_encode(array('type' => 'init', 'games' => $this->games)));

    echo "New connection! ({$conn->resourceId})n";
}

Подмечу, что сообщение мы шлем как JSON-объект, где тип события — это качество. Не непременно применять JSON, вы может применять всякий иной формат, но так, Дабы мы могли слать структурированные данные.

HTML

Раз мы шлем данные через web-сокет, а отображать их будем применяя JavaScript, html-код страницы дюже примитивен:

<div id="scoreboard">

    <table>

    </table>

</div>

Строка в таблице с итогами будет выглядеть так:

<tr data-game-id="SOME-IDENTIFIER">
    <td>
        <h3>HOME TEAM NAME</h3>
    </td>
    <td>
        <div id="counter-0-home"></div>
    </td>
    <td>
        <p>:</p>
    </td>
    <td>
        <div id="counter-0-away"></div>
    </td>
    <td>
        <h3>AWAY TEAM NAME</h3>
    </td>
</tr>

id элементов Counter-* — * мы будем применять дальше в JS-плагине.

JavaScript

Приступим к JavaScript. Первое что необходимо сделать — это открыть сокет:

var conn = new WebSocket('ws://localhost:8080');

Допустимо вам придётся заменить адрес хоста либо порт, в зависимости от указанных настроек сервера/демона.
Дальше нужен обработчик события, тот, что будет отрабатывать при приобретении сообщения:

conn.onmessage = function(e) {  

Сообщение находится в свойстве data объекта событие e. Так как мы шлём сообщения в JSON, вначале мы обязаны разобрать его:

var message = $.parseJSON(e.data);

Сейчас мы можем проверить тип сообщения и вызвать соответствующую функцию:

switch (message.type) {
    case 'init':
        setupScoreboard(message);
        break;
    case 'goal':
        goal(message);
        break;
}

Функция setupScoreboard достаточно примитивна:

function setupScoreboard(message) {

    // Create a global reference to the list of games
    games = message.games;

    var template = '<tr data-game-id="{{ game.id }}"><td><h3>{{game.home.team}}</h3></td><td><div id="counter-{{game.id}}-home"></div></td><td><p>:</p></td><td><div id="counter-{{game.id}}-away"></div></td><td><h3>{{game.away.team}}</h3></td></tr>';

    $.each(games, function(id){        
        var game = games[id];                
        $('#scoreboard table').append(Mustache.render(template, {game:game} ));        
        game.counter_home = new flipCounter("counter-" id "-home", {value: game.home.score, auto: false});
        game.counter_away = new flipCounter("counter-" id "-away", {value: game.away.score, auto: false});
    });

}

В этой функции мы легко «пробегаем» по массиву игр, использую Mustache для рендера новой строки в таблицу счета и реализации пары анимированых счетчиков для всякой игры. Массив games будет беречь нынешнее состояние игр и ссылки на счетчики, Дабы мы могли их обновлять по мере необходимости.
Дальше идет функция goal. Мы получаем сообщение через web-сокет, которое сигнализирует нам об изменении состояния, имеет следующую конструкцию:

{
    type: 'goal',
    game: 'UNIQUE-ID',
    team: 'home'
}

Качество game — неповторимый ID, team — либо «home», либо «away». Применяя эти данные мы можем обновить счет в массиве games, обнаружить необходимый нам объект счетчика и увеличить его.

function goal(message) {    
    games[message.game][message.team]['score']  ;
    var counter = games[message.game]['counter_' message.team];
    counter.incrementTo(games[message.game][message.team]['score']);
}

Сейчас, всё что нам осталось это запустить сервер из командной строки:

php bin/server.php

Завершение

В данной статье я показал как легко дозволено сделать виджет «Live счета» использую JS, HTML и web-сокеты. Безусловно, обыкновенно охота увидеть гораздо огромнее информации, чем легко счет, но раз мы используем JSON, мы сумеем без задач добавить и другие данные.
Демо.

Источник: programmingmaster.ru
Оставить комментарий
БАЗА ЗНАНИЙ
СЛУЧАЙНАЯ СТАТЬЯ
СЛУЧАЙНЫЙ БЛОГ
СЛУЧАЙНЫЙ МОД
СЛУЧАЙНЫЙ СКИН
НОВЫЕ МОДЫ
НОВЫЕ СКИНЫ
НАКОПЛЕННЫЙ ОПЫТ
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB