how to get the connection object of a specific user?

Anas EL KORCHI picture Anas EL KORCHI · Jul 11, 2013 · Viewed 8k times · Source

I am working in a real time Symfony app using Ratchet library, in this app I need to send some data to a specific user so the logic solution was to use the SessionProvider that will attach a Symfony2 Session object to each incoming Connection object. As the documentation states I have setup a non-native session handler to store my sessions i.e. in a database via PDO. and that work fine for the moment but I need to get the Connection object of a specific user to send him some data so in other way I need to find the connection object that reference to this user and I can't find a way to do it ? her's my server code :

    $app=new AggregateApplication();
    $loop   = \React\EventLoop\Factory::create();
    $context = new \React\ZMQ\Context($loop);
    $pull = $context->getSocket(\ZMQ::SOCKET_PULL);
    $pull->bind('tcp://127.0.0.1:5555');
    $pull->on('message', array($app, 'onNotification'));
    $webSock = new \React\Socket\Server($loop);
    $webSock->listen(8080, '127.0.0.1');
    $handler = $this->getContainer()->get('session.handler');
    $server=new \Ratchet\Wamp\WampServer($app);
    $server = new SessionProvider($server, $handler);
    $webServer = new \Ratchet\Server\IoServer(new \Ratchet\WebSocket\WsServer($server),$webSock);
    $loop->run();

Answer

Scott Yang picture Scott Yang · Jul 19, 2013

I had the exact same question myself (minus Symfony) and here is what I did.

Based on the hello world tutorial, I have substituted SplObjectStorage with an array. Before presenting my modifications, I'd like to comment that if you followed through that tutorial and understood it, the only thing that prevented you from arriving at this solution yourself is probably not knowing what SplObjectStorage is.

class Chat implements MessageComponentInterface {
    protected $clients;

    public function __construct() {
        $this->clients = array();
    }

    public function onOpen(ConnectionInterface $conn) {
        // Store the new connection to send messages to later
        $this->clients[$conn->resourceId] = $conn;
        echo "New connection! ({$conn->resourceId})\n";
    }

    public function onMessage(ConnectionInterface $from, $msg) {
        $numRecv = count($this->clients) - 1;
        echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
            , $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');

        foreach ($this->clients as $key => $client) {
            if ($from !== $client) {
                // The sender is not the receiver, send to each client connected
                $client->send($msg);
            }
        }
        // Send a message to a known resourceId (in this example the sender)
        $client = $this->clients[$from->resourceId];
        $client->send("Message successfully sent to $numRecv users.");
    }

    public function onClose(ConnectionInterface $conn) {
        // The connection is closed, remove it, as we can no longer send it messages
        unset($this->clients[$conn->resourceId]);

        echo "Connection {$conn->resourceId} has disconnected\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "An error has occurred: {$e->getMessage()}\n";

        $conn->close();
    }
}

Of course to make it really useful you may also want to add in a DB connection, and store/retrieve those resourceIds.