Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Swoole Websocket Bundle Laravel Package

cydrickn/swoole-websocket-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle:

    composer require cydrickn/swoole-websocket-bundle
    

    Enable the bundle in config/bundles.php:

    return [
        // ...
        Cydrickn\SwooleWebsocketBundle\SwooleWebsocketBundle::class => ['all' => true],
    ];
    
  2. Configure the Bundle (optional): Override default settings in config/packages/swoole_websocket.yaml:

    swoole_websocket:
        host: '0.0.0.0'  # Expose to LAN
        port: 8080       # Match client JS port
        workers: 4       # Adjust based on CPU cores
    
  3. First Use Case: Basic Echo Server Create an event subscriber to handle messages:

    php bin/console make:subscriber WebsocketMessageSubscriber
    

    Implement MessageEvent handling:

    // src/EventSubscriber/WebsocketMessageSubscriber.php
    namespace App\EventSubscriber;
    
    use Cydrickn\SwooleWebsocketBundle\Event\MessageEvent;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    
    class WebsocketMessageSubscriber implements EventSubscriberInterface
    {
        public static function getSubscribedEvents(): array
        {
            return [
                MessageEvent::class => 'onMessage',
            ];
        }
    
        public function onMessage(MessageEvent $event): void
        {
            $fd = $event->getFd(); // Client connection ID
            $message = $event->getData();
            $event->getServer()->push($fd, "Echo: $message"); // Send back
        }
    }
    
  4. Run the Server:

    php bin/console websocket:server
    

    Test with the provided JavaScript snippet (update port to 8080).


Implementation Patterns

Core Workflows

  1. Event-Driven Architecture

    • Subscribe to OpenEvent, MessageEvent, and CloseEvent for lifecycle management.
    • Example: Track active connections in OpenEvent and clean up in CloseEvent.
      public function onOpen(OpenEvent $event): void
      {
          $this->connectionManager->addConnection($event->getFd());
      }
      
  2. Broadcasting to Clients

    • Use $event->getServer()->push($fd, $data) for one-to-one messaging.
    • Broadcast to all clients via $event->getServer()->push($fd, $data) in a loop (store FDs in a service).
    • Optimize with Swoole’s task workers for heavy processing:
      $event->getServer()->task([$this, 'processMessage'], $message);
      
  3. Authentication & Authorization

    • Validate clients in OpenEvent:
      public function onOpen(OpenEvent $event): void
      {
          $token = $event->getGet()['token'] ?? null;
          if (!$this->authService->validate($token)) {
              $event->getServer()->close($event->getFd());
              return;
          }
          // Proceed if valid
      }
      
  4. Integration with Symfony Services

    • Inject services into subscribers (e.g., MessageBus, EntityManager):
      public function __construct(private MessageBus $bus) {}
      
    • Use DependencyInjection to configure the bundle (e.g., override workers count).
  5. Graceful Shutdown

    • Handle CloseEvent to log disconnections or trigger cleanup:
      public function onClose(CloseEvent $event): void
      {
          $this->connectionManager->removeConnection($event->getFd());
      }
      

Advanced Patterns

  1. Room-Based Messaging

    • Maintain a Room service to group connections (e.g., by user ID or channel).
    • Example:
      // In MessageEvent
      $roomId = $this->roomService->getRoomFor($fd);
      $this->roomService->broadcast($roomId, $data);
      
  2. Rate Limiting

    • Use Swoole’s onHandshake to throttle connections:
      $event->getServer()->on('handshake', function ($request, $response) {
          if ($this->rateLimiter->isOverLimit($request->fd)) {
              $response->end();
              return;
          }
      });
      
  3. Hybrid HTTP/WebSocket

    • Proxy HTTP requests to Swoole for unified routing (e.g., using swoole_serve middleware).

Gotchas and Tips

Pitfalls

  1. Connection Leaks

    • Issue: Unclosed connections can exhaust file descriptors.
    • Fix: Always call $server->close($fd) in CloseEvent or when done.
    • Debug: Monitor lsof -i :8080 for open connections.
  2. Event Dispatcher Order

    • Issue: Subscribers may not fire in expected order (Swoole’s async nature).
    • Fix: Use EventDispatcher::DISPATCHER_PRIORITY_HIGH for critical logic.
  3. Serialization Quirks

    • Issue: Swoole’s push() expects strings. JSON-encode data:
      $server->push($fd, json_encode(['type' => 'update']));
      
    • Client-Side: Decode with JSON.parse(event.data).
  4. Worker Isolation

    • Issue: Shared memory ($server) is not thread-safe across workers.
    • Fix: Use Swoole\Table or Redis for shared state.
  5. Port Conflicts

    • Issue: Default port 8000 may clash with other services.
    • Fix: Configure via CLI or config/packages/:
      php bin/console websocket:server --port=9090
      

Debugging Tips

  1. Swoole Logs

    • Enable logging in config/packages/swoole_websocket.yaml:
      swoole_websocket:
          log_file: '%kernel.logs_dir%/swoole.log'
          log_level: 7  # DEBUG
      
  2. Xdebug with Swoole

    • Use swoole_set_process_name() to identify workers in Xdebug:
      $server->on('start', function () {
          swoole_set_process_name("websocket-worker");
      });
      
  3. Connection Inspection

    • Dump active connections in a subscriber:
      public function onOpen(OpenEvent $event): void
      {
          $connections = $event->getServer()->connections;
          file_put_contents('connections.log', print_r($connections, true));
      }
      

Extension Points

  1. Custom Handshake

    • Override the handshake event to validate headers:
      $server->on('handshake', function ($request, $response) {
          if (!$this->validateHandshake($request->header)) {
              $response->end();
          }
      });
      
  2. Protocol Upgrades

    • Extend with Swoole\WebSocket\Frame for custom framing:
      $frame = new \Swoole\WebSocket\Frame($data, \Swoole\WebSocket::OP_BINARY);
      $server->push($fd, $frame);
      
  3. Metrics Integration

    • Integrate with Symfony Monitor or Prometheus via CloseEvent:
      public function onClose(CloseEvent $event): void
      {
          $this->metrics->inc('websocket.connections.closed');
      }
      
  4. Load Testing

    • Use autobahn-testsuite to validate compliance:
      npm install -g autobahn-testsuite
      websocket -m f64 -c 100 ws://localhost:8080
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle