erfanvahabpour/laravel-swoole-ws

Laravel WebSocket server built on Swoole/OpenSwoole with routing, command protocols, scoped connections, channels, and Redis/Table-backed connection stores.

Installs: 17

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/erfanvahabpour/laravel-swoole-ws

v0.1.0 2025-12-18 14:16 UTC

This package is auto-updated.

Last update: 2025-12-18 14:21:09 UTC


README

A high-performance WebSocket server library for Laravel powered by Swoole / OpenSwoole, designed for:

  • Real-time applications
  • IoT / device communication
  • Command-based device protocols
  • Channel & room broadcasting
  • Scalable multi-connection state management (memory / table / Redis)

This package provides a Laravel-native DX while running outside the HTTP lifecycle.

โš ๏ธ Status: Under active development APIs are stabilizing, but breaking changes may occur.

Features

  • ๐Ÿš€ Swoole / OpenSwoole WebSocket server
  • ๐Ÿ”Œ Laravel service provider & facade
  • ๐Ÿงญ WebSocket routing (WS::route)
  • ๐Ÿง  Command-based device protocol (WS::command, WS::response)
  • ๐ŸŒ Handshake URL path scoping (/pub/chat, /attendance, etc.)
  • ๐Ÿ” Middleware support (ws.auth, custom middleware)
  • ๐Ÿ‘ฅ Channels & presence authorization
  • ๐Ÿ“ก Broadcast to rooms / users
  • ๐Ÿ—ƒ Connection stores:
    • In-memory
    • Swoole\Table
    • Redis (multi-server ready)
  • ๐Ÿงช Testbench + PHPUnit support
  • โš™๏ธ Artisan commands (ws:start, ws:stop, ws:reload)

Requirements

  • PHP 8.2+
  • Laravel 10+
  • Swoole or OpenSwoole extension enabled

Check extension:

php -m | grep swoole
php -m | grep openswoole

Installation

composer require erfanvahabpour/laravel-swoole-ws

Laravel auto-discovery is enabled.

Publish Config & Routes

php artisan vendor:publish --tag=ws-config
php artisan vendor:publish --tag=ws-routes
php artisan vendor:publish --tag=ws-channels

Files created:

  • config/ws.php
  • routes/ws.php
  • routes/ws_channels.php

Starting the WebSocket Server

php artisan ws:start

Default output:

WS server starting on 0.0.0.0:9502

Stop / reload:

php artisan ws:stop
php artisan ws:reload

WebSocket Protocols Supported

This library supports two protocols at the same time:

1๏ธโƒฃ Legacy Route Protocol (WS::route)

Client message format

{
  "path": "/chat",
  "action": "send",
  "data": { "text": "hello" },
  "meta": {}
}

Route definition

use EFive\Ws\Facades\WS;

WS::route('/chat', 'send', function ($ctx, $data) {
    return ['ok' => true];
});

Response format

{
  "event": "ws.response",
  "data": { "ok": true },
  "meta": []
}

2๏ธโƒฃ Command / Device Protocol (WS::command)

Designed for IoT / terminal / attendance devices.

Client โ†’ Server

{
  "cmd": "reg",
  "sn": "ABC123",
  "version": "1.0"
}

Server โ†’ Client (reply)

{
  "ret": "reg",
  "result": true,
  "cloudtime": "2025-01-01 12:00:00"
}

Handshake Path Scoping (IMPORTANT)

Devices can connect using different WebSocket URLs:

ws://127.0.0.1:9502/pub/chat
ws://127.0.0.1:9502/attendance

The handshake path becomes a routing scope.

Why?

Different devices may use the same cmd names (reg, sendlog, etc.) but require different logic.

Scoped Command Routing

Define scoped commands

use EFive\Ws\Facades\WS;

WS::scope('/pub/chat')->command('reg', function ($ctx, $payload) {
    return ['pong' => true];
});

WS::scope('/attendance')->command('reg', function ($ctx, $payload) {
    return [
        'device' => 'attendance',
        'sn' => $payload['sn'] ?? null,
    ];
});

Client connects

wscat -c ws://127.0.0.1:9502/pub/chat

Send:

{"cmd":"reg"}

Response:

{"ret":"reg","result":true,"pong":true}

Automatic ret Replies

When handling WS::command:

  • If handler returns an array, it is automatically sent as:

    { "ret": "<cmd>", "result": true, ...payload }
  • If handler calls $ctx->replyRet(), return null to avoid double responses.

Example

WS::command('reg', fn () => ['pong' => true]);

โžก automatically sends:

{"ret":"reg","result":true,"pong":true}

Manual Replies & Server Push

Manual reply

$ctx->replyRet('reg', true, ['cloudtime' => now()]);

Push command to client

$ctx->pushCmd('getuserlist', ['count' => 10]);

Middleware

Apply to routes

WS::route('/chat', 'send', $handler)
  ->middleware(['ws.auth']);

Built-in

  • ws.auth โ€“ token-based authentication

Authentication

Handshake token

ws://host:port/path?token=YOUR_TOKEN

Message token

{
  "cmd": "reg",
  "meta": { "auth": "TOKEN" }
}

Custom resolver (recommended)

config()->set('ws.auth.resolver', function (string $token) {
    return (object) ['id' => 1, 'name' => 'Device'];
});

Channels & Presence

Define channels

routes/ws_channels.php

WS::channel('private-chat.{id}', function ($user, $id) {
    return true;
});

Subscribe

{
  "path": "/ws",
  "action": "subscribe",
  "data": { "channel": "private-chat.1" }
}

Connection Stores

Configured in config/ws.php.

Available drivers

  • memory โ€“ simple, single worker
  • table โ€“ fast shared memory
  • redis โ€“ recommended for multi-server scaling

Redis example

'store' => [
  'driver' => 'redis',
  'redis' => [
    'connection' => 'default',
    'prefix' => 'ws:',
    'ttl_seconds' => 86400,
  ],
],

Testing

vendor/bin/phpunit

Uses Orchestra Testbench.

CI

GitHub Actions included:

  • PHP 8.2 / 8.3
  • PHPUnit

Roadmap (v0.1.0)

  • WebSocket routing
  • Command protocol
  • Handshake path scoping
  • Redis connection store
  • ws.auth middleware
  • Subscribe / unsubscribe routes
  • Presence broadcasting
  • Rate limiting middleware
  • Server metrics endpoint
  • Binary protocol support

License

MIT ยฉ Erfan Vahabpour