Skip to content
This repository was archived by the owner on Mar 24, 2025. It is now read-only.

7. Websocket

Albert Chen edited this page May 2, 2018 · 25 revisions

Websocket

This is a very important feature of this package. Generally in Laravel when you want to build a webscoket server, you have to rely on third party websocket server. The most common way is to use Pusher or Socket.io provided by NodeJS and with combination of Broadcasting. There's no way to build a websocket server in Laravel.

Now with Swoole, it is possible and not difficult to integrate with Laravel. Nowadays when we talk about Websocket, the majority choose Socket.io to be their solution. The good news is this package is compatible with Socket.io protocol(partially). That means in the brower or other clients you can use Socket.io client directly.

These Socket.io features are not implemented:

  • namespace
  • path
  • long polling
  • sid (sid interacts with server will be ignored)
  • only supports text type data

Websocket Event Binding

After you run vendor:publish, you can find websocket.php in your routes folder. This is where you can register your websocket events. It looks pretty much like how you register a HTTP route in Laravel. You can register events with on function, and it supports callback function or handler path.

<?php

use SwooleTW\Http\Websocket\Facades\Websocket;

/*
|--------------------------------------------------------------------------
| Websocket Routes
|--------------------------------------------------------------------------
|
| Here is where you can register websocket events for your application.
|
*/

Websocket::on('open', function ($websocket, $request) {
    // in open callback, data will be illuminate request 
    $websocket->emit('message', 'welcome');
});

Websocket::on('disconnect', function ($websocket) {
    //
});

Websocket::on('example', function ($websocket, $data) {
    $websocket->emit('message', $data);
});

Websocket::on('test', 'ExampleController@method');

In callback functions, you can get $websocket and $data as parameters.

Parameter sequence doen't matter, but parameter names does.

Middleware for onOpen event request

onOpen is a special event which will be triggered after the websocket connection is established. You can do some authorization here according to the request. Here you can use middleware for pre-processing the requst. The default middleware are set in config/swoole_websocket.php.

'middleware' => [
    SwooleTW\Http\Websocket\Middleware\DecryptCookies::class,
    SwooleTW\Http\Websocket\Middleware\StartSession::class,
    SwooleTW\Http\Websocket\Middleware\Authenticate::class,
],

There are some built-in middleware for fetching auth user with session guard. You can customize your middleware for your authorization.

Websocket::on('open', function ($websocket, $request) {
    $request->user();
    auth()->user();
});

Getting authorized user is as easy as what you usually do in Laravel.

Websocket::on('open', function ($websocket, $request) {
    //
})->middleware(FooBarMiddleware::class);

You can also append your middleware after the on function.

Websocket APIs

function Parameters Description
on string $event, callable $callback Listen to a event name, and bind to handler
broadcast None Set current message to broadcast
to int string $value Assigned to specific fd, or specific room name
toAll array $values Assigned to multiple fds or rooms
join string $room Join current sender to a room
joinAll array $rooms Join current sender to multiple rooms
leave string $room Make current sender leave a specific room
leaveAll array $rooms Make current sender leave multiple rooms
emit string $event, mixed $data Emit an event with data
close None Close current connection
getSender None Get current sender's fd
getIsBroadcast None Get if is briadcast now
getTo None Get assigned fds and rooms
reset boolean $force Reset isBroadcast, to and sender (if force is true)

Usage Examples

The usage of websocket refers to Socket.io, so they look highly similar and friendly for those developers who have experience in Socket.io.

<?php

use SwooleTW\Http\Websocket\Facades\Websocket;

// sending to sender-client only
Websocket::emit('message', 'this is a test');

// sending to all clients except sender
Websocket::broadcast()->emit('message', 'this is a test');

// sending to all clients in 'game' room except sender
Websocket::broadcast()->to('game')->emit('message', 'nice game');

// sending to all clients in 'game' including sender client
Websocket::to('game')->emit('message', 'enjoy the game');

// sending to individual socketid 1
Websocket::broadcast()->to(1)->emit('message', 'for your eyes only');

// join to subscribe the socket to a given channel
Websocket::join('some room');

// leave to unsubscribe the socket to a given channel
Websocket::leave('some room');
<?php

use SwooleTW\Http\Websocket\Facades\Room;

// get all fds in a 'game' room
Room::getClients('game');

// get all rooms of fd 1
Room::getRooms(1);

// add fd 1 to a 'game' room
Room::add(1, 'room');

// add fd 1 to 'game' and 'test' rooms
Room::addAll(1, ['game', 'test']);

// delete fd 1 from a 'game' room
Room::delete(1, 'room');

// delete fd 1 from 'game' and 'test' rooms
Room::deleteAll(1, ['game', 'test']);

Customization

Default handler uses Socket.io, but you can still use your customized websocket protocol.

There are two classes you need to deal with:

  • Websocket Handler: Need to implement HandlerContract
<?php

namespace SwooleTW\Http\Websocket;

use Illuminate\Http\Request;
use Swoole\Websocket\Frame;

interface HandlerContract
{
    /**
     * "onOpen" listener.
     *
     * @param int $fd
     * @param \Illuminate\Http\Request $request
     */
    public function onOpen($fd, Request $request);

    /**
     * "onMessage" listener.
     *  only triggered when event handler not found
     *
     * @param \Swoole\Websocket\Frame $frame
     */
    public function onMessage(Frame $frame);

    /**
     * "onClose" listener.
     *
     * @param int $fd
     * @param int $reactorId
     */
    public function onClose($fd, $reactorId);
}
  • Packet Parser: Need to extend Parser
<?php

namespace SwooleTW\Http\Websocket\Foo;

use Swoole\Websocket\Frame;
use SwooleTW\Http\Websocket\Parser;

class FooParser extends Parser
{
    /**
     * Strategy classes need to implement handle method.
     */
    protected $strategies = [
        // optional
    ];

    /**
     * Encode output message for websocket push.
     *
     * @return mixed
     */
    public function encode($event, $data)
    {
        // your formatiing logic
        return $result;
    }

    /**
     * Decode message from websocket client.
     * Define and return payload here.
     *
     * @param \Swoole\Websocket\Frame $frame
     * @return array
     */
    public function decode(Frame $frame)
    {
        // your formatiing logic
        return [
            'event' => $yourParsedEventName,
            'data' => $yourParsedData
        ];
    }
}

And configure them with your class path in config/swoole_websocket.php

'handler' => SwooleTW\Http\Websocket\SocketIO\WebsocketHandler::class,
'parser' => SwooleTW\Http\Websocket\SocketIO\SocketIOParser::class,
Clone this wiki locally