Question

The situation:

There is a long-running task that needs to be launched asynchronously. The details of this task aren't really all that important (the basics are that multiple VMs are going to be provisioned and a complex network setup), and this is being handled by a python script that will be running on a different server. We decided to go with WebSockets for the communication back and forth between the web server and the client, and I have the bi-directional communication there working. The web server will be sending requests to the other server, and will receive HTTP POST notifications back from the python script when each machine is up and running, and a final HTTP POST back when the entire network is up.

All of this works. The framework we're using on the web server is Laravel 4, and the web socket server was built using Ratchet, and implemented in an artisan command. My issue is I'm not sure how to relay the HTTP POSTs to a Laravel controller from the python script to the WebSocket server so that it in turn can relay that information back to the client.

Below is the implementation of Ratchet's MessageComponentInterface::onMessage method, which is using an Observer pattern to notify any subscribed listeners of a message event.

// Class: SocketMessenger
public function onMessage(ConnectionInterface $from, $msg) {
    $respondTo = null;
    foreach($this->_clients as $client) {
        if($client->resourceId == $from->resourceId) {
            $respondTo = $client;
            break;
        }
    }

    $msg = json_decode($msg, true);

    if(!$respondTo || !$msg || !isset($msg['type'])) {
        echo 'Malformed Socket Message Received, Rejecting.';
        return;
    }

    $type = $msg['type'];

    // Notify any subscribed listeners with this message type of the 
    // incoming message. Any response received will be relayed back to 
    // the client.
    if(isset($this->_listeners[$type])) {
        foreach( $this->_listeners[$type] as $listener ) {
            $response = $listener->notify( $respondTo, $msg );
            if($response) {
                $respondTo->send( $response );
            }
        }
    }
}

The WebSocket server is constructed within a service provider like this:

// Class: SocketServiceProvider
$app->bind( 'Ratchet\MessageComponentInterface', function( $app, $params ) {
    $port = $params && isset($params[0]) ?
        $params[0] : self::DEFAULT_PORT
    ;

    $messenger = new SocketMessenger;

    // Setup the Ratchet Server.
    $server = IoServer::factory(
        new HttpServer(
            new WsServer(
                 $messenger
            )
        ),
        $port
    );

    // Subscribe socket listeners to the socket messenger
    $messenger->subscribe( new TopologyMessageListener, TopologyMessageListener::TYPE );

    return $server;
} );

Is there any way take requests to a Laravel controller and notify the running WebSocket server whenever a given controller's method is hit?

Was it helpful?

Solution

The answer here appears to be that I need to create a WebSocket client in PHP that will send messages to the WebSocket server, the same as a client written in JavaScript would. For any interested viewers struggling with the same issue, I was able to find a few WebSocket Clients written in PHP:

  1. https://github.com/gabrielbull/php-websocket-client
  2. https://github.com/Devristo/phpws
  3. https://github.com/symbiose/php-websocket-client (<-- This is the one I wound up going with)

I'll be leaving this question open for awhile in case anyone comes up with a different idea / better client library to use.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top