Skip to content

Instantly share code, notes, and snippets.

@cboden
Last active February 11, 2024 14:38
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cboden/3119135 to your computer and use it in GitHub Desktop.
Save cboden/3119135 to your computer and use it in GitHub Desktop.
Ratchet Routing
<?php
$collection = new RouteCollection;
$collection->add('chatRoom', new Route('/demo', array(
'_controller' => new ChatRoom
, 'allowedOrigins' => 'socketo.me'
)));
$collection->add('echo', new Route('/echo', array(
'_controller' => new AbFuzzyServer
, 'allowedOrigins' => '*'
)));
$collection->add('uhOh', new Route('/what/{happens}/{now}', array(
'_controller' => new Trouble
)));
$router = new WsRouter;
$router->addCollection($collection);
$wsserv = new WebSocket($router);
$server = new IoServer($wsserv);
$server->run();
<?php
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
class Trouble implements MessageComponentInterface {
public function onOpen(ConnectionInterface $conn, , $happens = '', $now = '') { // ???
$from->send('Welcome to ' . $from->WebSocket->Router->path);
}
public function onMessage(ConnectionInterface $from) {
}
public function onClose(ConnectionInterface $conn) {
}
public function onError(ConnectionInterface $conn, \Exception $e) {
}
}
@sudoanand
Copy link

class WsRouter not found, anywhere.

@kl3sk
Copy link

kl3sk commented Feb 1, 2019

This was on 0.3, you should use like this in 0.4as the doc and app said.

public function onOpen(ConnectionInterface $conn) {
      $from->send('Welcome to ' . $conn->httpRequest->getUri()->getPath());
}

@cmancone
Copy link

cmancone commented May 6, 2019

I needed the routing feature, but this doc is very out-of-date and most of the classes don't exist anymore. I did lots of digging through the code, the tests, and the symfony routing components to finally come up with an example that actually works. I did have to do something weird though, and I don't know if that is because things just don't line up anymore, or because I'm missing something (my example works though).

The issue I ran into is that my first attempts with the Router ran but didn't work - the clients would complain that the connection was never established. After more digging I learned that the actual establishment of the connection happens in the WsServer class and isn't handled by the Router. Perhaps the WsRouter would provide this functionality, but in my verson (0.4.1) it does not exist, nor does the WebSocket class that is wrapped around the WsRouter.

This meant that I needed the WsServer class to get in the mix to properly establish connections (either that or add the connection management to my controller, but that would rather defeat the purpose). This means that the WsServer needed to be passed as the controller of the route. Unfortunately the WsServer class needs to be given an instance of the MessageComponentInterface class (aka the class with my actual websocket functionality), but the router wants the controller class and will instantiate it itself. This means that the WsServer cannot be passed in as a controller to the Router, because there is no way to specify which MessageComponentInterface implementer the WsServer should use. To fix this I created a separate class for each of my MessageComponentInterface classes which extends the WsServer and manually instantiates the MessageComponentInterface class and passes it into the WsServer constructor. This worked.

This process was definitely fairly worky, but so far I love the interface/setup this project provides otherwise. Anyway, here's the working example:

<?php
// autoloading needs to go here
// require_once "../vendor/autoload.php";

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Psr\Http\Message\RequestInterface;
use Ratchet\Http\Router;
use Ratchet\Http\HttpServerInterface;
use Ratchet\ConnectionInterface;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\HttpFoundation\Request;

class ChatServer extends WsServer {
    public function __construct() {
        parent::__construct(new Chat());
    }
}
class Chat implements HttpServerInterface {
    protected $clients;

    public function __construct() {
        $this->clients = new \SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn, RequestInterface $request = null) {
        $this->clients->attach($conn);

        print "\nConnection Opened!!!!";
        $conn->send('welcome');
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        foreach ($this->clients as $client) {
            $client->send($msg);
        }
    }

    public function onClose(ConnectionInterface $conn) {
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
    }
}

$collection = new RouteCollection();
$collection->add('enroute', new Route('/enroute', [
    '_controller' => ChatServer::class,
]));
$urlMatcher = new UrlMatcher($collection, new RequestContext());
$router = new Router($urlMatcher);

$server = IoServer::factory(
    new HttpServer($router),
    8080
);
$server->run();

@al-mootasem
Copy link

@cmancone this is actually the only thing worked for me!

@koswarabilly
Copy link

@cmancone Thanks man

@rahulhaque
Copy link

Here is a working example for Laravel. My current version is 0.4.2.

https://gist.github.com/rahulhaque/2a92380e54779d03660e01da3851d24d

@md-riaz
Copy link

md-riaz commented Feb 11, 2024

Does the App class of the ratchet not work anymore in version 0.4.4?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment