mita/uranus-socket-server

使用 Ratchet 构建的 PHP Socket 服务器库

1.0.1 2024-08-26 09:05 UTC

This package is auto-updated.

Last update: 2024-09-26 09:26:46 UTC


README

以下是 UranusSocketServer 文档的修订和结构化版本,包括配置路由、创建控制器以及建立连接后理解数据包结构的附加部分

UranusSocketServer

UranusSocketServer 是一个强大、可扩展且易于使用的 PHP 库,专为构建高性能 WebSocket 应用程序而设计。它具有灵活的中间件管道、全面的事件管理和高效连接处理等功能,让开发者能够轻松创建复杂的 WebSocket 解决方案。

功能

  • 模块化架构:轻松扩展和自定义 WebSocket 服务器。
  • 依赖注入:完全符合 DI 规范,代码干净且易于维护。
  • 可扩展性:高效处理大量并发 WebSocket 连接。
  • 自定义路由:支持中间件的路由消息到控制器。
  • 事件驱动:挂钩到关键的生命周期事件以增强控制。

快速入门指南

1. 安装

使用 Composer 安装库

composer require mita/uranus-socket-server

2. 配置

2.1 设置路由

创建一个 routes.yaml 文件以定义您的 WebSocket 路由

join_room:
    path: /room/{roomId}/join
    controller: Mita\UranusSocketServer\Examples\Chat\Controllers\ChatController

room_publish:
    path: /room/{roomId}/publish
    controller: Mita\UranusSocketServer\Examples\Chat\Controllers\ChatController

2.2 创建控制器

创建一个控制器以处理传入的 WebSocket 消息

<?php

namespace Mita\UranusSocketServer\Examples\Chat\Controllers;

use Mita\UranusSocketServer\Controllers\BaseController;
use Mita\UranusSocketServer\Managers\ConnectionManager;
use Mita\UranusSocketServer\Packets\PacketInterface;
use Ratchet\ConnectionInterface;

class ChatController extends BaseController
{
    public function handle(ConnectionInterface $conn, PacketInterface $packet, array $params)
    {
        if ($params['_route'] === 'join_room') {
            $conn->send("You joined room " . $params['roomId']);
        } elseif ($params['_route'] === 'room_publish') {
            $conn->send("Message to room " . $params['roomId'] . ": " . $packet->getMessage());
        }
    }
}

2.3 理解数据包结构

向服务器发送数据时,数据包应结构化为至少包含两个键的 JSON 对象:routemsg

  • route:指定数据包应发送到的 WebSocket 路由。
  • msg:包含您希望发送的消息或数据。

示例数据包

{
    "route": "/room/123/join",
    "msg": "Hello, I'm joining room 123"
}

3. 运行基本聊天应用程序示例

本节演示了如何快速设置简单的 WebSocket 聊天服务器。

3.1 克隆仓库

git clone https://github.com/mita9497dev/uranus-socket-server.git
cd uranus-socket-server

3.2 安装依赖

composer install

3.3 导航到示例目录

cd examples/chat

3.4 index.php 简介

index.php 文件是 WebSocket 服务器的人口点。它使用基本设置初始化服务器

require __DIR__ . '/vendor/autoload.php';

use Mita\UranusSocketServer\SocketServer;

$settings = [
    'host' => '127.0.0.1',
    'port' => 7654,
    'router_path' => __DIR__ . '/routes.yaml'
];

$socketServer = new SocketServer($settings);
$socketServer->run();

3.5 运行 WebSocket 服务器

使用以下命令启动 WebSocket 服务器

php index.php

3.6 连接到服务器

使用 WebSocket 客户端连接到 ws://127.0.0.1:7654 并发送 JSON 数据包,如

加入房间

{
    "route": "/room/123/join",
    "msg": "Joining room 123"
}

向房间发送消息

{
    "route": "/room/123/publish",
    "msg": "Hello, everyone!"
}

4. 运行带有身份验证的聊天应用程序示例

此示例通过添加基于令牌的认证增强了基本的聊天功能。

4.1 克隆仓库

git clone https://github.com/mita9497dev/uranus-socket-server.git
cd uranus-socket-server

4.2 安装依赖

composer install

4.3 导航到示例目录

导航到 ChatWithAuth 示例目录

cd examples/ChatWithAuth

4.4 index.php 简介

在此示例中,index.php 文件注册了一个 AuthPlugin 用于基于令牌的认证

require __DIR__ . '/../../vendor/autoload.php';

use Mita\UranusSocketServer\Examples\ChatWithAuth\Plugins\AuthPlugin;
use Mita\UranusSocketServer\SocketServer;

$settings = [
    'host' => '127.0.0.1',
    'port' => 7654,
    'router_path' => __DIR__ . '/routes.yaml'
];

$socketServer = new SocketServer($settings);

$authPlugin = new AuthPlugin('your_secret_key');
$socketServer->addPlugin($authPlugin);

$socketServer->run();

此示例演示了如何创建和集成自定义插件。通过遵循此模式,您可以开发和注册插件以扩展服务器功能。

4.5 更新密钥

'your_secret_key' 替换为您希望的用于认证的密钥。

4.6 运行 WebSocket 服务器

启动 WebSocket 服务器

php index.php

4.7 连接到服务器

使用 WebSocket 客户端连接到 ws://127.0.0.1:7654,包括在 URI 查询字符串中的 access_token

示例连接 URI

ws://127.0.0.1:7654/?access_token=your_secret_key

4.8 加入房间

使用以下JSON负载进行身份验证并加入聊天室

{
    "route": "/room/123/join",
    "msg": "Joining room 123"
}

4.9 向房间发送消息

身份验证并加入后,向房间发送消息

{
    "route": "/room/123/publish",
    "msg": "Hello, authenticated users!"
}

4.10 AuthPlugin.php 解释

AuthPlugin.php 文件是一个自定义插件,它将基于令牌的身份验证添加到您的WebSocket服务器中。以下是其关键部分的详细解释

class AuthPlugin implements PluginInterface, MiddlewareInterface
{
    protected $secretKey;
    protected $keyName;

    // 1. Constructor
    public function __construct($secretKey, $keyName = 'access_token')
    {
        $this->secretKey = $secretKey;
        $this->keyName = $keyName;
    }

解释:构造函数使用一个密钥和一个令牌参数名称初始化插件。这种设置使您能够轻松配置要验证的令牌以及如何验证它。

    // 2. Registering the Plugin
    public function register(EventDispatcherInterface $dispatcher)
    {
        $dispatcher->addListener('middleware.register', [$this, 'onRegisterMiddleware']);
        $dispatcher->addListener('connection.open', [$this, 'onOpen']);
    }

解释register 方法通过监听特定事件(如 middleware.registerconnection.open)将插件钩入WebSocket服务器。这是将身份验证逻辑集成到服务器生命周期的地方。

    // 3. Register Middleware
    public function onRegisterMiddleware(MiddlewarePipeline $pipeline)
    {
        $pipeline->add($this);
    }

解释onRegisterMiddleware 方法将身份验证中间件添加到管道中。这确保每个通过服务器的消息都经过身份验证检查。

    // 4. Connection Open Handler
    public function onOpen(ConnectionInterface $conn)
    {
        $uri = $conn->httpRequest->getUri();
        parse_str($uri->getQuery(), $params);
        $token = $params[$this->keyName] ?? null;
        
        if (!$this->validateToken($token)) {
            $conn->send("Invalid token");
            $conn->close();
            throw new \Exception("Invalid token");
        }
    }

解释:当打开一个新的WebSocket连接时,将调用 onOpen 方法。它从连接URI中提取令牌并进行验证。如果令牌无效,则立即关闭连接。

    // 5. Message Handler Middleware
    public function handle(ConnectionInterface $conn, PacketInterface $packet, callable $next)
    {
        $token = $packet->getMetadata($this->keyName);

        if (!$this->validateToken($token)) {
            $conn->send("Invalid token");
            $conn->close();
            return;
        }

        $next($conn, $packet);
    }

解释handle 方法处理传入的WebSocket消息。它检查消息元数据中的令牌,确保只有经过身份验证的用户才能与服务器交互。

    // 6. Token Validation Method
    protected function validateToken($token)
    {
        if (!$token) {
            return false;
        }

        return $token == $this->secretKey;
    }
}

解释validateToken 方法是一个实用函数,用于将提供的令牌与密钥进行比较。如果需要,此简单方法可以扩展为更复杂的验证逻辑。

ChatWithAuth 示例的代码概述

  • ChatController.php:处理房间加入和消息发布逻辑。
  • AuthPlugin.php:基于令牌的身份验证中间件。
  • ChatService.php:管理房间订阅和广播消息。
  • index.php:入口点,初始化WebSocket服务器并注册 AuthPlugin
  • routes.yaml:定义加入和房间内消息的路由。

API 文档

1. SocketServer

SocketServer 类是您的WebSocket服务器的入口点。

  • run()

    启动WebSocket服务器。

    public function run()
  • registerEventListener(string $eventName, callable $listener)

    注册事件监听器。

    public function registerEventListener(string $eventName, callable $listener)

2. RoutingMiddleware

RoutingMiddleware 类处理传入WebSocket消息的路由。

  • handle(ConnectionInterface $conn, PacketInterface $packet, callable $next)

    将消息路由到适当的控制器。

    public function handle(ConnectionInterface $conn, PacketInterface $packet, callable $next)

3. MiddlewarePipeline

通过一系列中间件处理消息。

  • add(MiddlewareInterface $middleware)

    将中间件添加到管道中。

    public function add(MiddlewareInterface $middleware)
  • process(ConnectionInterface $conn, PacketInterface $packet, callable $finalHandler)

    通过中间件管道处理数据包。

    public function process(ConnectionInterface $conn, PacketInterface $packet, callable $finalHandler)

4. ConnectionManager

管理WebSocket连接及其订阅。

  • add(ConnectionInterface $conn)

    添加新连接。

    public function add(ConnectionInterface $conn)
  • remove(ConnectionInterface $conn)

    删除连接。

    public function remove(ConnectionInterface $conn)

5. EventDispatcher

管理事件监听器和事件分发。

  • addListener(string $eventName, callable $listener)

    注册事件监听器。

    public function addListener(string $eventName, callable $listener)
  • dispatch(string $eventName, $eventData = null)

    将事件分发给注册的监听器。

    public function dispatch(string $eventName, $eventData = null)

6. Packet

表示WebSocket消息数据包。

  • getRoute()

    返回数据包的路由。

    public function getRoute(): string
  • getMessage()

    返回消息内容。

    public function getMessage()
  • getMetadata(string $key = null)

    返回元数据或特定键值。

    public function getMetadata(string $key = null)

7. PacketFactory

从JSON字符串创建 Packet 实例。

  • createFromJson(string $json): PacketInterface

    从JSON字符串创建一个 Packet

    public function createFromJson(string $json): PacketInterface

8. PluginManager

管理系统插件的生命周期。

  • addPlugin(PluginInterface $plugin)

    将插件添加到管理器。

    public function addPlugin(PluginInterface $plugin)
  • registerPlugins(EventDispatcherInterface $dispatcher)

    将所有插件注册到事件调度器,并触发plugin.registered事件。

    public function registerPlugins(EventDispatcherInterface $dispatcher)
  • bootPlugins()

    启动所有已注册的插件。

    public function bootPlugins()

创建插件

要在UranusSocketServer中创建插件,您需要实现PluginInterface。插件可以用于向服务器添加自定义功能,例如身份验证、日志记录或其他中间件。以下是创建和注册插件的简要概述

  1. 实现PluginInterface
use Mita\UranusSocketServer\Events\EventDispatcherInterface;
use Mita\UranusSocketServer\Plugins\PluginInterface;

class MyCustomPlugin implements PluginInterface
{
    public function register(EventDispatcherInterface $dispatcher)
    {
        // Register events or middleware here
    }

    public function boot()
    {
        // Code to run when the plugin is booted
    }

    public function unregister(EventDispatcherInterface $dispatcher)
    {
        // Unregister events or middleware here
    }
}
  1. 将插件添加到服务器
$myPlugin = new MyCustomPlugin();
$socketServer->addPlugin($myPlugin);

通过遵循此模式,您可以扩展WebSocket服务器的功能,以满足您的特定需求。

事件文档

概述

UranusSocketServer库提供了一种强大的基于事件的架构,允许您挂钩WebSocket服务器各种生命周期事件。本节介绍了可用的事件、触发它们的上下文、它们提供的参数以及如何使用它们的示例。

1. connection.opened

  • 描述:当建立新的WebSocket连接时触发。
  • 上下文:WebSocketService::onOpen中触发。
  • 参数
    • ConnectionInterface $conn:表示新的连接。
  • 示例
    $socketServer->registerEventListener('connection.opened', function($conn) {
        echo "New connection opened with ID: " . $conn->resourceId . "\n";
    });

2. message.received

  • 描述:当接收到WebSocket消息时触发。
  • 上下文:WebSocketService::onMessage中触发。
  • 参数
    • ConnectionInterface $connection:接收消息的连接实例。
    • string $message:实际的消息内容。
  • 示例
    $socketServer->registerEventListener('message.received', function($data) {
        $conn = $data['connection'];
        $msg = $data['message'];
        echo "Message received from connection {$conn->resourceId}: {$msg}\n";
    });

3. plugin.registered

  • 描述:当在系统中注册插件时触发。
  • 上下文:PluginManager::registerPlugins中触发。
  • 参数
    • PluginInterface $plugin:已注册的插件实例。
  • 示例
    $socketServer->registerEventListener('plugin.registered', function($plugin) {
        echo "Plugin registered: " . get_class($plugin) . "\n";
    });

4. connection.added

  • 描述:当WebSocket连接添加到ConnectionManager时触发。
  • 上下文:ConnectionManager::add中触发。
  • 参数
    • ConnectionInterface $conn:被添加的连接对象。
  • 示例
    $socketServer->registerEventListener('connection.added', function($conn) {
        echo "Connection added with ID: " . $conn->resourceId . "\n";
    });

5. connection.removed

  • 描述:当WebSocket连接从ConnectionManager中删除时触发。
  • 上下文:ConnectionManager::remove中触发。
  • 参数
    • ConnectionInterface $conn:被删除的连接对象。
  • 示例
    $socketServer->registerEventListener('connection.removed', function($conn) {
        echo "Connection removed with ID: " . $conn->resourceId . "\n";
    });

6. connection.subscribed

  • 描述:当连接订阅特定路由时触发。
  • 上下文:ConnectionManager::subscribe中触发。
  • 参数
    • ConnectionInterface $conn:订阅的连接。
    • string $route:连接订阅的路由。
  • 示例
    $socketServer->registerEventListener('connection.subscribed', function($data) {
        $conn = $data['conn'];
        $route = $data['route'];
        echo "Connection {$conn->resourceId} subscribed to route: {$route}\n";
    });

7. connection.unsubscribed

  • 描述:当连接取消订阅特定路由时触发。
  • 上下文:ConnectionManager::unsubscribe中触发。
  • 参数
    • ConnectionInterface $conn:取消订阅的连接。
    • string $route:连接取消订阅的路由。
  • 示例
    $socketServer->registerEventListener('connection.unsubscribed', function($data) {
        $conn = $data['conn'];
        $route = $data['route'];
        echo "Connection {$conn->resourceId} unsubscribed from route: {$route}\n";
    });

8. message.sent

  • 描述:当将消息发送到特定路由的所有订阅者时触发。
  • 上下文:ConnectionManager::sendToRoute中触发。
  • 参数
    • string $route:消息发送到的路由。
    • string $message:发送的消息内容。
  • 示例
    $socketServer->registerEventListener('message.sent', function($data) {
        $route = $data['route'];
        $message = $data['message'];
        echo "Message sent to route {$route}: {$message}\n";
    });

感谢您使用UranusSocketServer!希望它可以帮助您轻松构建下一个WebSocket应用程序。如果您有任何问题或需要支持,请随时打开一个问题或联系社区。

编码愉快!