Ratchet without ZeroMQ: A debug-a-thon;

759 views
Skip to first unread message

Grim Lodaf

unread,
Feb 19, 2014, 1:22:08 AM2/19/14
to ratch...@googlegroups.com
Hi guys, greetings from Africa!
First, thank you Igor and Cboden for these wonderful libraries, they're an inspiration.
Secondly, apologies for re-posting a question, but I feel it is necessary that I post this afresh, and in full detail.
I successfully followed the Ratchet "Hello World" tutorial, everything worked fine.
Then I moved on to the "Push-Integration" tut. Here's where it got a bit tricky.I am developing on Win7, PHP 5. There are no existing ZeroMQ bindings for said
specifications, as far as I know.
But then again that shouldn't be hard, just use bare sockets!!
Which is what I did.After some brutal 24 hours trying to find the code, I re-did the tut, again, this time
with minimal changes to the code.(Even the comments ;). )
So here we go:
         (Pusher.php)
   
 namespace MyApp;
   
use Ratchet\ConnectionInterface;
   
use Ratchet\Wamp\WampServerInterface;

   
class Pusher implements WampServerInterface {
   
/**
     * A lookup of all the topics clients have subscribed to
     */

   
protected $subscribedTopics = array();

   
public function onSubscribe(ConnectionInterface $conn, $topic) {
       
// When a visitor subscribes to a topic link the Topic object in a  lookup array
       
if (!array_key_exists($topic->getId(), $this->subscribedTopics)) {
            $this
->subscribedTopics[$topic->getId()] = $topic;
            echo
"Subscription::". $topic. "\n";
       
}
   
}
   
   
/**
     * @param string JSON'ified string we'll receive from ZeroMQ
     */

   
public function onBlogEntry($entry) {
        $entryData
= json_decode($entry, true);

       
// If the lookup topic object isn't set there is no one to publish to
       
if (!array_key_exists($entryData['channel'], $this->subscribedTopics)) {
            echo
"Fail\n";
           
return;
       
}

        $topic
= $this->subscribedTopics[$entryData['channel']];

       
// re-send the data to all the clients subscribed to that category
        $topic
->broadcast($entryData);
        echo
"BOOM!\n";
   
}
   
   
public function onUnSubscribe(ConnectionInterface $conn, $topic) {
   
}
   
public function onOpen(ConnectionInterface $conn) {
   
}
   
public function onClose(ConnectionInterface $conn) {
   
}
   
public function onCall(ConnectionInterface $conn, $id, $topic, array $params) {
       
// In this application if clients send data it's because the user hacked around in console
        $conn
->callError($id, $topic, 'You are not allowed to make calls')->close();
   
}
   
public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible) {
       
// In this application if clients send data it's because the user hacked around in console
        $conn
->close();
   
}
   
public function onError(ConnectionInterface $conn, \Exception $e) {
   
}
}




Anything suspicious so far?No?Moving on...
(push-server.php)
   
require dirname(__DIR__) . '/vendor/autoload.php';

    $loop  
= React\EventLoop\Factory::create();
    $pusher
= new MyApp\Pusher;

   
// Listen for the web server to make a ZeroMQ push after an ajax request
    $socket
= new React\Socket\Server($loop);
    $socket
->on('connection', function ($conn) {
        $pusher
= new MyApp\Pusher;
        $conn
->on('data', array($pusher, 'onBlogEntry'));
        echo
"Whooops!\n";
       
});
        $socket
->listen(1337, '127.0.0.1'); //Binding to our IP so remotes can't connect.

   
// Set up our WebSocket server for clients wanting real-time updates
    $webSock
= new React\Socket\Server($loop);
    $webSock
->listen(9000, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
    $webServer
= new Ratchet\Server\IoServer(
       
new Ratchet\Http\HttpServer(
           
new Ratchet\WebSocket\WsServer(
               
new Ratchet\Wamp\WampServer(
                    $pusher
               
)
           
)
       
),
        $webSock
   
);

    $loop
->run();


   
Anything?No?the javascript...

     
 var conn = new ab.Session(
       
'ws://localhost:9000' // The host (our Ratchet WebSocket server) to connect to
     
, function() {            // Once the connection has been established
            conn
.subscribe('kittensCategory', function(topic, data) {
               
// This is where you would add the new article to the DOM (beyond the scope of this tutorial)
                console
.log('New article published to category "' + topic + '" : ' + data.update);
           
});
       
}
     
, function() {            // When the connection is closed
            console
.warn('WebSocket connection closed');
       
}
     
, {                       // Additional parameters, we're ignoring the WAMP sub-protocol for older browsers
           
'skipSubprotocolCheck': true
       
}
   
);
   
And the script that takes the ajax requests, sends message to push-server.php:

      $message
= "'". $NAME. "'". " spawned by user @". $CREATOR ;
      $matter
= array( 'channel' => 'kittensCategory',
               
'update' => $message );
      $data
= json_encode($matter);
      $length
= strlen($data);
      $socket
= socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
     
//socket_bind($socket, 0, $port);
      socket_connect
($socket, $host, $port);
      socket_write
($socket,$data,strlen($data));



The results:
In the browser console, no errors.The connection is made.
In the CLI, the following is printed:
     
 Subscription::kittensCategory
     
Whooops!
     
Fail!


I print these for debugging purposes, of course.
Shows that the subscription does take place, the IPC message is received, but the topic "kittensCategory"
is not found in the look-up array "$subscribedTopics".
This is it.commenting out

     
 if (!array_key_exists($entryData['channel'], $this->subscribedTopics)) {
            echo
"Fail\n";
           
return;
       
}


       
Is a bad idea, but I tried it anyway.Then:
    
   
 Subscription::kittensCategory
     
Whoops!
     
Notice: Undefined index: kittensCategory in C:\...Pusher.php on line 32
     
Fatal error: Call to a member function broadcast() on a non-object in C:\...Pusher.php on line 35.


     
My script is exactly like the one in the "Push-integration" tutorial, except for the non-ZeroMQ part, so
I believe that's where the problem is.
Thank you for reading aaall that!
Any help would be appreciated.

     

Grim Lodaf

unread,
Feb 27, 2014, 3:10:36 AM2/27/14
to ratch...@googlegroups.com
Any help, guys?

cboden

unread,
Mar 1, 2014, 10:28:39 AM3/1/14
to ratch...@googlegroups.com
I don't have Windows but I believe ZeroMQ will work on it. There are DLL downloads for the php extension on the PECL website: http://pecl.php.net/package/zmq

The reason the tutorial uses ZeroMQ instead of raw sockets is because they're message oriented where as sockets are stream oriented. With raw sockets TCP will fragment and concatenate data. This means when you send() a message you're writing bytes, not passing a whole string like a function call; the receiving end has to put it all back together properly, usually done by a messaging protocol. 

On Thursday, 27 February 2014 03:10:36 UTC-5, Grim Lodaf wrote:
Any help, guys?
Reply all
Reply to author
Forward
0 new messages