Skip to content

WebSocket Transport

Diffyne supports WebSocket transport for real-time, bidirectional communication. This provides lower latency and persistent connections compared to AJAX.

Overview

WebSocket transport uses Sockeon as the WebSocket server, providing high-performance real-time communication.

When to Use WebSocket

Use WebSocket when:

  • Building real-time applications (chat, notifications, live updates)
  • You need lower latency (< 50ms)
  • High-frequency updates (multiple per second)
  • Persistent connections are beneficial

Use AJAX when:

  • Standard web applications
  • Occasional updates (every few seconds or less)
  • Simpler deployment is preferred
  • Lower server resource usage is needed

Setup

1. Install Sockeon

bash
composer require sockeon/sockeon

2. Configure WebSocket

Add to your .env:

bash
DIFFYNE_TRANSPORT=websocket
DIFFYNE_WS_HOST=127.0.0.1
DIFFYNE_WS_PORT=6001
DIFFYNE_WS_PATH=/diffyne
DIFFYNE_WS_KEY=your-secret-key-here
DIFFYNE_WS_CORS_ORIGINS=*

3. Start WebSocket Server

bash
php artisan diffyne:websocket

For development, run in background:

bash
php artisan diffyne:websocket > /dev/null 2>&1 &

4. Production Setup

Use a process manager like Supervisor:

/etc/supervisor/conf.d/diffyne-websocket.conf:

ini
[program:diffyne-websocket]
command=php /path/to/artisan diffyne:websocket
directory=/path/to/project
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/path/to/logs/diffyne-websocket.log

Then:

bash
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start diffyne-websocket

Configuration

Basic Configuration

php
// config/diffyne.php
'websocket' => [
    'host' => env('DIFFYNE_WS_HOST', '127.0.0.1'),
    'port' => env('DIFFYNE_WS_PORT', 6001),
    'path' => env('DIFFYNE_WS_PATH', '/diffyne'),
    'key' => env('DIFFYNE_WS_KEY'),
    'cors' => [
        'allowed_origins' => explode(',', env('DIFFYNE_WS_CORS_ORIGINS', '*')),
        'allowed_methods' => ['GET', 'POST', 'OPTIONS'],
            'allowed_headers' => ['Content-Type', 'Authorization'],
    ],
],

CORS Configuration

For production, restrict CORS origins:

bash
DIFFYNE_WS_CORS_ORIGINS=https://example.com,https://www.example.com

Security Key

Generate a secure key:

bash
php artisan tinker
>>> Str::random(32)

Add to .env:

bash
DIFFYNE_WS_KEY=generated-key-here

How It Works

Connection Flow

  1. Client connects to WebSocket server
  2. Server authenticates using key
  3. Persistent connection established
  4. All requests go through WebSocket
  5. Server responds through same connection

Automatic Fallback

If WebSocket connection fails, Diffyne automatically falls back to AJAX:

javascript
// Client automatically handles:
// 1. Try WebSocket connection
// 2. If fails, use AJAX
// 3. Retry WebSocket in background

Switching Between Transports

Runtime Switching

You can switch transports per-request or per-component:

php
// In your component
public function mount(): void
{
    // Force AJAX for this component
    config(['diffyne.transport' => 'ajax']);
}

Environment-Based

php
// config/diffyne.php
'transport' => env('DIFFYNE_TRANSPORT', app()->environment('production') ? 'websocket' : 'ajax'),

Performance Comparison

Latency

OperationAJAXWebSocket
Initial connection~50ms~10ms
Subsequent requests~50-200ms~10-50ms
Connection overheadPer requestOne-time

Throughput

MetricAJAXWebSocket
Requests/second~10-50~100-1000
Connection overheadHighLow
Server resourcesLowerHigher

Use Cases

AJAX is better for:

  • Standard CRUD operations
  • Form submissions
  • Occasional updates
  • Lower server load

WebSocket is better for:

  • Real-time chat
  • Live notifications
  • Dashboard updates
  • Collaborative editing
  • Live data feeds

Monitoring

Logs

WebSocket server logs to:

storage/logs/diffyne-websocket/

Health Check

Check if WebSocket server is running:

bash
curl http://127.0.0.1:6001/health

Connection Status

Monitor connections in your application:

php
// In your component or service
$wsStatus = cache()->get('diffyne:websocket:status', 'disconnected');

Troubleshooting

Connection Refused

Problem: WebSocket connection failed

Solutions:

  1. Check if server is running: ps aux | grep diffyne:websocket
  2. Verify port is open: netstat -tuln | grep 6001
  3. Check firewall rules
  4. Verify host/port in config

CORS Errors

Problem: CORS policy blocked

Solutions:

  1. Add your domain to DIFFYNE_WS_CORS_ORIGINS
  2. Check CORS headers in response
  3. Verify key is correct

Authentication Failed

Problem: WebSocket authentication failed

Solutions:

  1. Verify DIFFYNE_WS_KEY matches on client and server
  2. Check key is set in .env
  3. Clear config cache: php artisan config:clear

High Memory Usage

Problem: WebSocket server using too much memory

Solutions:

  1. Reduce connection timeout
  2. Implement connection limits
  3. Monitor and restart periodically
  4. Use load balancer for multiple instances

Best Practices

1. Use WebSocket Selectively

php
// Use WebSocket for real-time components
class ChatRoom extends Component
{
    // WebSocket transport
}

// Use AJAX for standard components
class UserForm extends Component
{
    // AJAX transport
}

2. Handle Disconnections Gracefully

php
public function hydrate(): void
{
    // Check WebSocket status
    if (! $this->isWebSocketConnected()) {
        // Fallback logic
    }
}

3. Monitor Connection Health

php
// In your service provider
if (config('diffyne.transport') === 'websocket') {
    $this->app->singleton('diffyne.websocket.health', function () {
        return new WebSocketHealthChecker();
    });
}

4. Use Load Balancing

For high-traffic applications:

nginx
upstream diffyne_websocket {
    server 127.0.0.1:6001;
    server 127.0.0.1:6002;
    server 127.0.0.1:6003;
}

server {
    location /diffyne {
        proxy_pass http://diffyne_websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

5. Secure Your WebSocket

php
// Use authentication
'websocket' => [
    'key' => env('DIFFYNE_WS_KEY'), // Strong, random key
    'cors' => [
        'allowed_origins' => [
            'https://yourdomain.com',
            'https://www.yourdomain.com',
        ],
    ],
],

Example: Real-Time Chat

php
class ChatRoom extends Component
{
    public array $messages = [];
    public string $newMessage = '';
    
    public function mount(): void
    {
        $this->loadMessages();
    }
    
    #[Invokable]
    public function sendMessage(): void
    {
        $this->validate([
            'newMessage' => 'required|string|max:500',
        ]);
        
        Message::create([
            'user_id' => auth()->id(),
            'content' => $this->newMessage,
            'room_id' => $this->roomId,
        ]);
        
        $this->newMessage = '';
        $this->loadMessages();
        
        // Broadcast to all connected clients
        $this->dispatch('message-sent', [
            'room_id' => $this->roomId,
        ]);
    }
    
    #[On('message-sent')]
    public function handleNewMessage(array $data): void
    {
        if ($data['room_id'] === $this->roomId) {
            $this->loadMessages();
        }
    }
}

Migration from AJAX

Step 1: Test Locally

bash
DIFFYNE_TRANSPORT=websocket

Step 2: Monitor Performance

Watch for:

  • Connection stability
  • Memory usage
  • Response times
  • Error rates

Step 3: Deploy Gradually

  1. Deploy to staging
  2. Test thoroughly
  3. Deploy to production
  4. Monitor closely

Step 4: Rollback Plan

Keep AJAX as fallback:

php
'transport' => env('DIFFYNE_TRANSPORT', 'ajax'),

If issues occur, simply change .env:

bash
DIFFYNE_TRANSPORT=ajax

Next Steps

Released under the MIT License.