sfcod / socketio
Symfony 的 SocketIo 适配器
1.4.0
2022-12-16 13:59 UTC
Requires
- php: ^7.4
- ezyang/htmlpurifier: ^4.0
- predis/predis: ^1.1
- symfony/dotenv: ^5.4
- symfony/framework-bundle: ^5.4
- symfony/monolog-bundle: ^3.1
- symfony/process: ^5.4
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.8
- symfony/phpunit-bridge: ^5.4
README
在您的 Symfony 项目中充分利用 socket.io 的全部功能。
配置
安装 node,然后安装 npm
npm install --prefix ./vendor/sfcod/socketio/Server
services: App\SocketIo\: resource: '../src/SocketIo/*' tags: ['sfcod.socketio.event'] # If you want override default JoinHandler/LeaveHandler. For example, add some condition for join/leave a room. exclude: - '../src/SocketIo/JoinHandler.php' # Optional - '../src/SocketIo/LeaveHandler.php' # Optional # If you want override default JoinHandler SfCod\SocketIoBundle\Service\JoinHandler: class: App\SocketIo\JoinHandler tags: ['sfcod.socketio.event'] # If you want override default LeaveHandler SfCod\SocketIoBundle\Service\LeaveHandler: class: App\SocketIo\LeaveHandler tags: ['sfcod.socketio.event']
扩展基类或使用 SF 装饰器。如有需要,则重写 fire 或 handle 方法。
namespace App\SocketIo; use SfCod\SocketIoBundle\Service\JoinHandler as JoinHandlerBase; class JoinHandler extends JoinHandlerBase { public function fire(): array { // Some additional logic here. // ... return array_merge_recursive(parent::fire(), [ 'key' => 'value' ]); } }
处理中间件
如果您使用 doctrine,则可以连接 "doctrine reconnect",然后它将为每个进程重新连接。
sfcod_socketio: processMiddlewares: - 'SfCod\SocketIoBundle\Middleware\Process\DoctrineReconnect'
###> socketio config ### SOCKET_IO_WS_SERVER=localhost:1358 SOCKET_IO_WS_CLIENT=localhost:1358 SOCKET_IO_SSL='' || '{"key":"path to key", "cert":"path to cert"}' SOCKET_IO_NSP=redis ###< socketio config ###
JWT 令牌认证。放置 SOCKET_IO_AUTH_TOKEN_PATH 或 SOCKET_IO_AUTH_TOKEN_VALUE
#Public jwt token key path (Will be join with base path) SOCKET_IO_AUTH_TOKEN_PATH='/config/jwt/public.pem' #Public key value SOCKET_IO_AUTH_TOKEN_VALUE='public key value' #You can change token name. Default name is 'token' SOCKET_IO_AUTH_TOKEN_NAME='token'
var socket = io('{your_host_address}:1367/notifications', { query: { token: 'yourTokenHere', }, });
使用方法
启动 nodejs 服务器
php bin/console socket-io:node-js-server
启动 php 服务器
php bin/console socket-io:php-server
从服务器到客户端创建发布者
use SfCod\SocketIoBundle\Events\EventInterface; use SfCod\SocketIoBundle\Events\EventPublisherInterface; use SfCod\SocketIoBundle\Events\AbstractEvent; class CountEvent extends AbstractEvent implements EventInterface, EventPublisherInterface { /** * Changel name. For client side this is nsp. */ public static function broadcastOn(): array { return ['notifications']; } /** * Event name */ public static function name(): string { return 'update_notification_count'; } /** * Emit client event * @return array */ public function fire(): array { return [ 'count' => 10, ]; } }
var socket = io('{your_host_address}:1367/notifications'); socket.on('update_notification_count', function(data){ console.log(data) });
从客户端到服务器创建接收者
use SfCod\SocketIoBundle\Events\EventInterface; use SfCod\SocketIoBundle\Events\EventSubscriberInterface; use SfCod\SocketIoBundle\Events\AbstractEvent; use SfCod\SocketIoBundle\Service\Broadcast; class MarkAsReadEvent extends AbstractEvent implements EventInterface, EventSubscriberInterface { private $broadcast; public function __construct(Broadcast $broadcast) { $this->broadcast = $broadcast; } /** * Changel name. For client side this is nsp. */ public static function broadcastOn(): array { return ['notifications']; } /** * Event name */ public static function name(): string { return 'mark_as_read_notification'; } /** * Handle client event */ public function handle() { // Mark notification as read // And call client update $this->broadcast->emit('update_notification_count', ['some key' => 'some value']); } }
var socket = io('{your_host_address}:1367/notifications'); socket.emit('mark_as_read_notification', {id: 10});
您可以在一个事件中拥有发布者和接收者。如果您需要检查从客户端到服务器的数据,您应该使用
- EventPolicyInterface
带有从客户端到服务器检查的接收者
use SfCod\SocketIoBundle\Events\EventSubscriberInterface; use SfCod\SocketIoBundle\Events\EventInterface; use SfCod\SocketIoBundle\Events\EventPolicyInterface; use SfCod\SocketIoBundle\Events\AbstractEvent; use SfCod\SocketIoBundle\Service\Broadcast; class MarkAsReadEvent extends AbstractEvent implements EventInterface, EventSubscriberInterface, EventPolicyInterface { private $broadcast; public function __construct(Broadcast $broadcast) { $this->broadcast = $broadcast; } /** * Changel name. For client side this is nsp. */ public static function broadcastOn(): array { return ['notifications']; } /** * Event name */ public static function name(): string { return 'mark_as_read_notification'; } public function can($data): bool { // Check data from client return true; } /** * Emit client event * @return array */ public function handle() { // Mark notification as read // And call client update $this->broadcast->emit('update_notification_count', ['some key' => 'some value']); } }
Socket.io 房间
- EventRoomInterface(后端)
use SfCod\SocketIoBundle\Events\EventPublisherInterface; use SfCod\SocketIoBundle\Events\EventInterface; use SfCod\SocketIoBundle\Events\EventRoomInterface; use SfCod\SocketIoBundle\Events\AbstractEvent; class CountEvent extends AbstractEvent implements EventInterface, EventPublisherInterface, EventRoomInterface { /** * Changel name. For client side this is nsp. */ public static function broadcastOn(): array { return ['notifications']; } /** * Event name */ public static function name(): string { return 'update_notification_count'; } /** * Socket.io room * @return string */ public function room(): string { return 'user_id_' . $this->userId; } /** * Emit client event * @return array */ public function fire(): array { return [ 'count' => 10, ]; } }
客户端
var socket = io('{your_host_address}:1367/notifications'); socket.emit('join', {room: 'user_id_10'}); // Now you will receive data from 'room-1' socket.on('update_notification_count', function(data){ console.log(data) }); // You can leave room socket.emit('leave', {room: 'user_id_10'});
在后台运行此命令
$this->broadcast->emit('update_notification_count', ['some key' => 'some value', 'userId' => 10]);
默认事件
- 连接
- 断开连接
- 加入
- 离开
use SfCod\SocketIoBundle\Events\EventSubscriberInterface; use SfCod\SocketIoBundle\Events\EventInterface; use Psr\Log\LoggerInterface; use SfCod\SocketIoBundle\Events\AbstractEvent; class СonnectionEvent extends AbstractEvent implements EventInterface, EventSubscriberInterface { private $logger; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } /** * Changel name. For client side this is nsp. */ public static function broadcastOn(): array { return ['notifications']; } /** * Event name */ public static function name(): string { return 'connection'; // or 'disconnect' } /** * Handle client event */ public function handle() { // Socket.io ID // $this->socketId $this->logger->info('disconnect', $this->payload); } }