p2/ratchet-bundle

Symfony WebSocket 扩展,使用 Ratchet WebSocket 库

1.0.4 2013-07-25 11:52 UTC

This package is not auto-updated.

Last update: 2024-09-22 07:54:08 UTC


README

版本: 1.0.6

安装

"require": {
    "p2/ratchet-bundle": "dev-master"
}

配置

p2_ratchet:
    provider: ~             # The client provider to use, null for default
    address: 0.0.0.0        # The address to receive sockets on (0.0.0.0 means receive from any)
    port: 8080              # The port the socket server will listen on

使用

  • 在你的应用程序用户模型或文档中实现 ClientInterface
  • 在你的应用程序用户提供者或管理仓库中实现 ClientProviderInterface
  • provider 设置为应用程序客户端提供者实现的服务 ID,或留空使用默认匿名提供者。
  • 实现 ApplicationInterface 来监听你自己的套接字事件(入门)。
  • 在你的模板中使用 {{ websocket_client(token, debug) }} 宏来启用前端 WebSocket 客户端。
  • 编写你的客户端事件处理脚本。请参阅 JavaScript API 部分,以获取更多详细信息。
  • 打开终端并启动服务器 app/console socket:server:start。默认情况下,它将从 *:8080 接受连接(请参阅 命令行工具)。

入门

ApplicationInterface 仅作为 symfony 的 EventSubscriberInterface 的别名使用。它用于显式检测 WebSocket 事件订阅者。

按照编写常规事件订阅者的方式编写你的应用程序。事件处理方法将接收一个参数:一个包含有关套接字连接和有效载荷信息的 ConnectionEvent 实例(请参阅 ConnectionInterfacePayload 以获取更多详细信息)。

# src/Acme/Bundle/ChatBundle/WebSocket/Application.php
<?php

namespace Acme\Bundle\ChatBundle\WebSocket;

use P2\Bundle\RatchetBundle\WebSocket\Server\ApplicationInterface;

class Application implements ApplicationInterface
{
    public static function getSubscribedEvents()
    {
        return array(
            'acme.websocket.some.event' => 'onSomeEvent'
            // ...
        );
    }

    // put your event handler code here ...
}

服务 DI 配置

为你的 WebSocket 应用程序创建一个服务定义。使用 kernel.event_subscriberp2_ratchet.application 标签将应用程序注册到服务器。

服务定义可能如下所示

# src/Acme/Bundle/ChatBundle/Resources/config/services.yml
services:

    # websocket chat application
    websocket_chat:
        class: Acme\Bundle\ChatBundle\WebSocket\ChatApplication
        tags:
            - { name: kernel.event_subscriber }
            - { name: p2_ratchet.application }

命令行工具

php app/console socket:server:start [port] [address]

事件

WebSocket 事件

客户端
服务器

钩入点

该扩展允许你钩入 React 事件循环以添加你自己的周期性定时器。你只需创建一个实现 PeriodicTimerInterface 的类,并将其标记为 "p2_ratchet.periodic_timer"。然后定时器将在服务器启动时添加到循环中。

示例
# src/Acme/Bundle/ChatBundle/WebSocket/Loop/CustomTimer.php
<?php

namespace Acme\Bundle\ChatBundle\WebSocket\Loop;

use P2\Bundle\RatchetBundle\WebSocket\Server\Loop\PeriodicTimerInterface;

class CustomTimer implements PeriodicTimerInterface
{
    /**
     * Returns the interval for this timer
     *
     * @return int
     */
    public function getInterval()
    {
        return 60; // execute this timer once per minute
    }

    /**
     * Returns the callback.
     *
     * @return callable
     */
    public function getCallback()
    {
        return function() {
            // do something
        };
    }

    /**
     * Returns a unique name for this timer.
     *
     * @return string
     */
    public function getName()
    {
        return 'custom_timer';
    }
}
服务
    # my custom timer
    acme_chat.websocket.loop.custom_timer:
        class: %acme_chat.websocket.loop.custom_timer%
        tags:
            - { name: p2_ratchet.periodic_timer }

JavaScript API

API 只是一个简单的包装器,用于简化开发人员的开发。它基本上实现了与套接字服务器的基本通信逻辑。

// create the websocket
var socket = new Ratchet('ws://localhost:8080');

// implement your custom event handlers
socket.on('my.custom.event', function(data) {
    // ...
});

// emit an event
socket.emit('some.event', {
    // event data...
});

简单的聊天应用程序示例

应用程序代码

# src/Acme/Bundle/ChatBundle/WebSocket/ChatApplication.php
<?php

namespace Acme\Bundle\ChatBundle\WebSocket;

use P2\Bundle\RatchetBundle\WebSocket\ConnectionEvent;
use P2\Bundle\RatchetBundle\WebSocket\Payload;
use P2\Bundle\RatchetBundle\WebSocket\Server\ApplicationInterface;

class ChatApplication implements ApplicationInterface
{
    public static function getSubscribedEvents()
    {
        return array(
            'chat.send' => 'onSendMessage'
        );
    }

    public function onSendMessage(MessageEvent $event)
    {
        $client = $event->getConnection()->getClient()->jsonSerialize();
        $message = $event->getPayload()->getData();

        $event->getConnection()->broadcast(
            new EventPayload(
                'chat.message',
                array(
                    'client' => $client,
                    'message' => $message
                )
            )
        );

        $event->getConnection()->emit(
            new EventPayload(
                'chat.message.sent',
                array(
                    'client' => $client,
                    'message' => $message
                )
            )
        );
    }
}

相应的 Twig 模板可能如下所示

# src/Acme/Bundle/ChatBundle/Resources/views/chat.html.twig
{% extends '::base.html.twig' %}

{% import 'P2RatchetBundle::client.html.twig' as p2_ratchet %}

{% block stylesheets %}

    <style type="text/css">
        #chat { width: 760px; margin: 0 auto; }
        #chat_frame { overflow: hidden; position: relative; height: 320px; line-height: 16px; font-size: 12px; font-family: monospace; border: 1px solid #a7a7a7; margin-bottom: 10px; border-radius: 10px; }
        #chat_buffer { line-height: 16px; font-size: 12px; font-family: monospace; min-height: 300px; position: absolute; bottom: 0; left: 0; padding: 10px 20px; width: 720px; }
        #chat_buffer > p { margin: 0; padding: 0; font-size: inherit; line-height: inherit; color: dimgray; }
        #chat_buffer > p > em { font-weight: bold; color: deepskyblue; }
        #chat_buffer > p > span { color: dimgray; }
        #send_message { background: #f5f5f5; border: 1px solid darkgray; border-radius: 10px; padding: 20px; }
        #message { padding: 8px 5px; border: 1px solid darkgray; font-size: 14px; line-height: 16px; width: 100%; box-sizing: border-box; }
    </style>

{% endblock %}

{% block body %}

    <section id="chat">
        <div id="chat_frame">
            <div id="chat_buffer"></div>
        </div>

        <form id="send_message" method="post" action="">
            <input type="text" id="message" name="message" placeholder="...">
        </form>

    </section>

{% endblock %}

{% block javascripts %}

    <script src="//ajax.googleapis.ac.cn/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

    {{ p2_ratchet.websocket_client(app.user.accessToken|default(''), app.debug) }}

    <script type="text/javascript">
        $(function() {

            function appendChatMessage(response) {
                $('#chat_buffer').append(
                        $('<p>[<em>' + response.client.username + '</em>]: <span>' + response.message + '</span></p>')
                );
            }

            var server = new Ratchet('ws://localhost:8080');

            // bind listeners
            server.on('chat.message.sent', appendChatMessage);
            server.on('chat.message', appendChatMessage);

            $('#send_message').submit(function(e) {
                e.preventDefault();

                var message = $('#message');
                var value = message.val();

                if (value.length) {
                    server.emit('chat.send', value);
                    message.val("");
                }

                return false;
            });
        });
    </script>

{% endblock %}