EzDevInfo.com

ratchet

Build mobile apps with simple HTML, CSS, and JavaScript components. Ratchet ratchet: build mobile apps with simple html, css, and js components.

Ratchet PHP WAMP - React / ZeroMQ - Specific user broadcast

Note: This is not the same as this question which utilises MessageComponentInterface. I am using WampServerInterface instead, so this question pertains to that part specifically. I need an answer with code examples and an explanation, as I can see this being helpful to others in the future.

Attempting looped pushes for individual users

I'm using the WAMP part of Ratchet and ZeroMQ, and I currently have a working version of the push integration tutorial.

I'm attempting to perform the following:

  • The zeromq server is up and running, ready to log subscribers and unsubscribers
  • A user connects in their browser over the websocket protocol
  • A loop is started which sends data to the specific user who requested it
  • When the user disconnects, the loop for that user's data is stopped

I have points (1) and (2) working, however the issue I have is with the third one:

Firstly: How can I send data to each specific user only? Broadcast sends it to everyone, unless maybe the 'topics' end up being individual user IDs maybe?

Secondly: I have a big security issue. If I'm sending which user ID wants to subscribe from the client-side, which it seems like I need to, then the user could just change the variable to another user's ID and their data is returned instead.

Thirdly: I'm having to run a separate php script containing the code for zeromq to start the actual looping. I'm not sure this is the best way to do this and I would rather having this working completely within the codebase as opposed to a separate php file. This is a major area I need sorted.

The following code shows what I currently have.

The server that just runs from console

I literally type php bin/push-server.php to run this. Subscriptions and un-subscriptions are output to this terminal for debugging purposes.

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

$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555');
$pull->on('message', array($pusher, 'onMessage'));

$webSock = new React\Socket\Server($loop);
$webSock->listen(8080, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(
    new Ratchet\WebSocket\WsServer(
        new Ratchet\Wamp\WampServer(
            $pusher
        )
    ),
    $webSock
);

$loop->run();

The Pusher that sends out data over websockets

I've omitted the useless stuff and concentrated on the onMessage() and onSubscribe() methods.

public function onSubscribe(ConnectionInterface $conn, $topic) 
{
    $subject = $topic->getId();
    $ip = $conn->remoteAddress;

    if (!array_key_exists($subject, $this->subscribedTopics)) 
    {
        $this->subscribedTopics[$subject] = $topic;
    }

    $this->clients[] = $conn->resourceId;

    echo sprintf("New Connection: %s" . PHP_EOL, $conn->remoteAddress);
}

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

    var_dump($entryData);

    if (!array_key_exists($entryData['topic'], $this->subscribedTopics)) {
        return;
    }

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

    // This sends out everything to multiple users, not what I want!!
    // I can't send() to individual connections from here I don't think :S
    $topic->broadcast($entryData);
}

The script to start using the above Pusher code in a loop

This is my issue - this is a separate php file that hopefully may be integrated into other code in the future, but currently I'm not sure how to use this properly. Do I grab the user's ID from the session? I still need to send it from client-side...

// Thought sessions might work here but they don't work for subscription
session_start();
$userId = $_SESSION['userId'];

$loop   = React\EventLoop\Factory::create();

$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher');
$socket->connect("tcp://localhost:5555");

$i = 0;
$loop->addPeriodicTimer(4, function() use ($socket, $loop, $userId, &$i) {

   $entryData = array(
       'topic'     => 'subscriptionTopicHere',
       'userId'    => $userId
    );
    $i++;

    // So it doesn't go on infinitely if run from browser
    if ($i >= 3)
    {
        $loop->stop();
    }

    // Send stuff to the queue
    $socket->send(json_encode($entryData));
});

Finally, the client-side js to subscribe with

$(document).ready(function() { 

    var conn = new ab.Session(
        'ws://localhost:8080' 
      , function() {            
            conn.subscribe('topicHere', function(topic, data) {
                console.log(topic);
                console.log(data);
            });
        }
      , function() {          
            console.warn('WebSocket connection closed');
        }
      , {                       
            'skipSubprotocolCheck': true
        }
    );
});

Conclusion

The above is working, but I really need to figure out the following:

  • How can I send individual messages to individual users? When they visit the page that starts the websocket connection in JS, should I also be starting the script that shoves stuff into the queue in PHP (the zeromq)? That's what I'm currently doing manually, and it just feels wrong.

  • When subscribing a user from JS, it can't be safe to grab the users id from the session and send that from client-side. This could be faked. Please tell me there is an easier way, and if so, how?


Source: (StackOverflow)

Ratchet basic chat application giving error "Failed opening required"

I'm trying out the Ratchet library to use WebSockets located at http://socketo.me/ but am experiencing some problems when running the server script from the command line in Ubuntu.

After successfully installing composer and Ratchet I'm following the tutorial for a basic chat application at http://socketo.me/docs/hello-world and I'm at the Running It step. My file structure, with websockets being my project folder, is:

kingsconflict
   websockets
      chat.php
      chat-server.php
      composer.json
      vendor
         autoload.php
         (dependecies included by composer for Ratchet)

The error I get when typing "sudo php chat-server.php" is "PHP Fatal error: require(): Failed opening required '/var/www/kingsconflict/vendor/autoload.php' (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/kingsconflict/websockets/chat-server.php on line 5". It seems like it's trying to open /var/www/kingsconflict/vendor/autoload.php but the actual path is /var/www/kingsconflict/websockets/vendor/autoload.php, and I'm not sure why it's doing this.

chat-server.php

<?php
use Ratchet\Server\IoServer;
use MyApp\Chat;

    require dirname(__DIR__) . '/vendor/autoload.php';    // Error here

    $server = IoServer::factory(
        new Chat()
      , 8080
    );

    $server->run();

I tried subbing the errored line with the line below, and I stop getting the error but I get a new error "PHP Fatal error: Class 'MyApp\Chat' not found" which leads me to believe this fix isn't right.

require ('./vendor/autoload.php');

The code for the other files are the same as shown in the Ratchet tutorial, but just in case I'll post them below

chat.php

<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class Chat implements MessageComponentInterface {
    protected $clients;

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

    public function onOpen(ConnectionInterface $conn) {
        // Store the new connection to send messages to later
        $this->clients->attach($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 $client) {
            if ($from !== $client) {
                // The sender is not the receiver, send to each client connected
                $client->send($msg);
            }
        }
    }

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

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

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

        $conn->close();
    }
}

composer.json

{
    "autoload": {
        "psr-0": {
            "MyApp": "src"
        }
    },
    "require": {
        "cboden/Ratchet": "0.2.*"
    }
}

autoload.php (Didn't edit this but what the hell)

<?php

// autoload.php generated by Composer

require_once __DIR__ . '/composer' . '/autoload_real.php';

return ComposerAutoloaderInit0964ef3a5e66723368300f04c3206ca1::getLoader();

Source: (StackOverflow)

Advertisements

How do I keep a websocket server running, even after I close the SSH terminal?

So, I am using Ratchet with PHP, and have currently uploaded a successful websocket example to my server.

It works after I go to SSH, and then just manually run "php bin/chat-server.php".

What I was wondering is that, in a commercial situation, how do I keep the chat server running?

Thanks.


Source: (StackOverflow)

Programmatically load a url using Ratchet push.js

The Ratchet single-page application framework uses push.js to load new pages into view. For example:

<a rel='nofollow' href="link.html">link<a>

This will use push to replace everything in the .content div with the .content of link.html. It will also update .bar-title and .bar-tab if you have them on both pages.

I would like to use the same mechanism with a Javascript function call. Before I start patching Ratchet, is there an elegant way to do that?

Thanks!


Source: (StackOverflow)

Send user ID from browser to websocket server while opening connection

Before asking this question, I did my best by reading severel questions on SO (tagged Ratchet and dealing with similar issues but to no avail. I even asked a question which received no attention and I therefore deleted it to write another one (that hopefully is more clear).

My final goal is to build a one-to-one private chat application using Ratchet. Everything is working fine except that I can't send message to a specific user.

Every logged in user connects to the websocket server while accessing secured area of website:

$(document).ready(function() { 

    var conn = new WebSocket('ws://localhost:8080');
        conn.onopen = function(e) {
            console.log("Connection established!");

            // Here I need to send the logged in user_id to websocket server
            // and get it in onOpen method so that I can index my array 
            // of connections with user_id instead of
            //$connection->ResourceId, I explain more above

        };

        conn.onmessage = function(e) {
            console.log(e.data);
        };

});

When a user writes a message in the chat box, the message is sent via AJAX to web server then pushed to Websocket using ZeroMQ. In the controller:

// Persistence of Message(message_id, sender_id, receiver_id, message_text)
                .....

                $context = new \ZMQContext();
                $socket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'my pusher');
                $socket->connect("tcp://localhost:5555");

                $pushData = array(
                       'receiver_id' => $receiver_id,
                       'sender_id'  => $user->getId(),
                       'message'  => $message->getMessageText(),
                    );
                $socket->send(json_encode($pushData));

So at the end, my websocket server is able to know which is the id of receiver using the JSON. But how will he know which is the connection of that user? In other words, I need to store websocket connections in an array that is indexed by the user id.

<?php
namespace RealTime;

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Wamp\WampServerInterface;

class Pusher implements WampServerInterface, MessageComponentInterface{

    private $clients;

    public function onOpen(ConnectionInterface $conn) {

        $this->clients[$conn->resourceId] = $conn;
        // I need here to get the user_id received from browser while opening connection
    }

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

        //This is not what I need (It sends to all users in array)
        foreach ($this->clients as $key => $client) {

        $client->send($entryData['message']); 
        }
    }
    public function onMessage(ConnectionInterface $from, $msg) {
        echo $msg; 
    }
}

And the websocket server:

  <?php
        require dirname(__DIR__) . '/vendor/autoload.php';
        use RealTime\Pusher;

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

        $context = new React\ZMQ\Context($loop);
        $pull = $context->getSocket(ZMQ::SOCKET_PULL);
        $pull->bind('tcp://127.0.0.1:5555'); 
        $pull->on('message', array($pusher, 'onMessageEntry'));


        $webSock = new React\Socket\Server($loop);
        $webSock->listen(8080, '0.0.0.0'); 
        $webServer = new Ratchet\Server\IoServer(
            new Ratchet\Http\HttpServer(
                new Ratchet\WebSocket\WsServer(
                    new Ratchet\Wamp\WampServer(
                        $pusher
                    )
                )
            ),
            $webSock
        );
        $loop->run();

        ?>

Questions:

  1. How to send the logged in user_id from client side while opening connection.I need to have the value in websocket server so that I can index my array of clients with it ($client[user_id]=$conn instead of $client[recourceId]=$conn). I tried the javascript function send but I don't know where to receive the sent data (even onMessage is not printing anything).

  2. Why the onMessage method is not executing even MessageComponentInterface implemented (Is it because I have onMessageEntry method + $pull->on('message', array($pusher, 'onMessageEntry')); line of code?

Thank you.


Source: (StackOverflow)

looking up data in splobjectstorage

Greetings people of stackoverflow, for the last days I have been looking at websockets and a PHP library called Ratchet (which is ideal for writing websockets server applications in PHP). In the Ratchet official docs they recommend using SplObjectStorage (which I had never heard of) for managing client connections objects.

In most server applications you probably need to keep some data about each client (e.g. in my case where I'm experimenting with writing a simple messaging server, I need to keep data like the client's nickname and perhaps something more), so as I understand it, I can add the client object and an array with the clients data to the SplObjectStorage when a new connection is opened like here below.

public function onOpen(ConnectionInterface $conn) {
    //$this->clients is the SplObjectStorage object
    $this->clients[$conn] = array('id' => $conn->resourceId, 'nickname' => '');

}

However, I'm not sure what is the best way to get an object from the SplObjectStorage by a value in the data array (like by a users nickname), one way to do it would be like this:

//$this->clients is my SplObjectStorage object where I keep all incoming connections
foreach($this->clients as $client){ 
    $data = $this->clients->offsetGet($client);

    if($data['nickname'] == $NickNameIAmLookingFor){
        //Return the $client object or do something nice
    }
}

But I sense there is a better way of doing this, so any advices would be greatly appreciated.

Thanks in advance.


Source: (StackOverflow)

Ratchet + nginx + SSL/secure websocket

I've been trying to run Ratchet.io over SSL (this problem: php ratchet websocket SSL connect?).

My webserver is running at myhost.mobi, and I have created a separate virtual host for websocket service "wws.myhost.mobi".

My web socket:

$webSock = new React\Socket\Server($loop);
$webSock->listen(8080, '0.0.0.0');
$webServer = new Ratchet\Server\IoServer(
    new Ratchet\Http\HttpServer(
        new Ratchet\WebSocket\WsServer(
            new Ratchet\Wamp\WampServer(
                $pusher
            )
        )
    ),
    $webSock
);

My nginx config (I'm on nginx 1.5.8):

upstream websocketserver {
        server localhost:8080;
}

server {
    server_name wss.myapp.mobi;

    listen 443;
    ssl on;
    ssl_certificate /etc/ssl/myapp-mobi-ssl.crt;
    ssl_certificate_key /etc/ssl/myapp-mobi.key;

    access_log /var/log/wss-access-ssl.log;
    error_log /var/log/wss-error-ssl.log;
    location / {
                proxy_pass http://websocketserver;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header Host $host;

                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto https;
                proxy_read_timeout 86400; # neccessary to avoid websocket timeout disconnect
                proxy_redirect off;
        }
}

My client-side script:

var conn = new ab.Session('wss://wss.myapp.mobi', function(o) {

    // ...

}, function() {
    console.warn('WebSocket connection closed');
}, {
    skipSubprotocolCheck: true
});

So, when I load the page in Firefox, I see an outgoing connection to wss://wss.myapp.mobi:8080/, which is hanging (the spinner) and never completes or dies. I do not see any trace of request arriving on the backend in the logs.

What am I missing there?

Thanks!

EDIT I have realized that I should be connecting to wss://wss.myapp.mobi, but now I am getting "101 Switching Protocols" status.

EDIT 2 Everything is working now with the config above. "101 Switching Protocols" status turns out to be a normal message. PROBLEM SOLVED!


Source: (StackOverflow)

How can I establish connection between a client and a server where the server sends new messages to the client?

I need to establish connection between a client and a server via PHP websocket.

The server will need to keeps checking with an external API for new messages and send them to the client.

I would like to understand the concept so I can code it. I have some questions to help me wrap it around my head.

The Client Side Do I keep making calls to the server via the websocket every second using javascript's setInterval() function or do I only make one call? How does the client know that the server have new messages?

The Server Side Do I create a script the runs an infinite loop to keep checking with the API and echo the results?

Websocket How does the websocket know which connection a message belong to?

I am not sure if it matter but I am going to use Ratchet for creating the websocket


Source: (StackOverflow)

Starting a session within a ratchet websocket connection

We have built a Ratchet websocket server that serves a standalone client application. The server is running on port 8080, and our Symfony app is running on port 80. It's critical that we have sessions working within the websocket server so we can uniquely identify each client. The problem is that Ratchet does not send a set-cookie header over port 8080.

Hoping to find a way to send the set-cookie header in response to the upgrade request on 8080, I tried to start a new session in onOpen():

use Symfony\Component\HttpFoundation\Session\Session;

class ClientApi implements MessageComponentInterface {
    /**
     * @inheritDoc
     */
    public function onOpen(ConnectionInterface $conn) {
        $conn->Session = new Session();
        $conn->Session->start();
    }
    ...

But this did not result in a set-cookie header being sent back in the response to the upgrade request.

We have a workaround where the client has to first do a GET on port 80 to get a cookie before sending the websocket upgrade request over 8080, so it can send the cookie with the upgrade request. I'm hoping to get something working like I tried above, so the client does not have to bother the web app on port 80.

Am I missing something?


Source: (StackOverflow)

how to get the connection object of a specific user?

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();

Source: (StackOverflow)

Access extra parameters in Ratchet web socket requests

I've set up Ratchet for websockets in PHP . It is connecting fine from my javascript client using (ws://localhost:8080) and successfully send/receive messages. But I want to pass some params like (ws://localhost:8080?param1=value). I'm not able to figure out how can I access param1 in my PHP script.

If possible in MessageComponentInterface::onOpen(ConnectionInterface $conn) method.

Or better: Can I associate those params with ConnectionInterface $conn. So that I've them for further communication.

I've followed http://socketo.me/docs/hello-world.


Source: (StackOverflow)

PHP Fatal error: Class 'MyApp\Chat' not found in /MyApp/chat-server.php

I am trying to run the Ratchet application demo but I can't execute the file

This is my file structure

/var/www/src/MyApp/
/var/www/src/MyApp/chat.php
/var/www/src/MyApp/chat-server.php
<?php
use Ratchet\Server\IoServer;
use MyApp\Chat;

#require "chat.php";

    require 'vendor/autoload.php';

    $server = IoServer::factory(
        new Chat(),
        8080
    );

    $server->run();
/var/www/src/MyApp/composer.json
{
    "autoload": {
        "psr-0": {
            "MyApp": "src"
        }
    },
    "require": {
        "cboden/Ratchet": "0.3.*"
    }
}

Vendor Folder is exist in this location

/var/www/src/MyApp/vendor/

Whenever I am executing the chat-server file in terminal I got the following error

PHP Fatal error:  Class 'MyApp\Chat' not found in /MyApp/chat-server.php

Please help me how to resolve this

Note: The complete code details are exist in this page

http://socketo.me/docs/hello-world

This question was asked but still no answer for that question too Class 'MyChat\Chat' not found in C:\wamp\www\bin\chat-server.php


Source: (StackOverflow)

Uncaugth reference error custom event not defind in the file ratchet

Hai i am new in phonegap and ratchet framework.I am trying to load external script with push.js. Here is my js file contents

function init(){
    document.addEventListener('deviceready', onDeviceReady, false);

    function onDeviceReady(){

        alert("device ready for use");
        }
       var checkPage = function(){

        alert("push");
        var scriptName; 
        var scriptsList = document.querySelectorAll('script.js-custom');  // Add a "js-custom" class to your script tag
        for (var i = 0; i<scriptsList.length;i++) {

            // Handle scripts in separate files by assigning the script file name to its id.
            // We save it in a variable because the ".done" callback is asynchronous.
            scriptName = scriptsList[i].id;  // IMPORTANT: Only one loadable script per page!
            $.getScript("js/" + scriptName)
              .done(function (script, textStatus) {
                  eval(script);
                  alert("ok");
              })
              .fail(function(){
                  alert("error");
              });

        }


    };   

    window.addEventListener('push', checkPage);

    } 

Here is my html file

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">  
    <title>Ratchet template page</title>

    <!-- Sets initial viewport load and disables zooming  -->
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">

    <!-- Makes your prototype chrome-less once bookmarked to your phone's home screen -->
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">

    <!-- Include the compiled Ratchet CSS -->
    <link rel='nofollow' href="css/ratchet.min.css" rel="stylesheet">

    <!-- Include the compiled Ratchet JS -->
    <script src="js/ratchet.min.js"></script> 
    <script src="js/jquery.js"></script>
     <script src="cordova.js"></script>

  </head>
  <body onload="init()">  

    <!-- Make sure all your bars are the first things in your <body> -->
    <header class="bar bar-nav">
      <h1 class="title">Ratchet</h1>
    </header>

    <!-- Wrap all non-bar HTML in the .content div (this is actually what scrolls) -->
    <div class="content">

      <div class="card">
        <ul class="table-view">
          <li class="table-view-cell">

            <a class="push-right" rel='nofollow' href="two.html">
              <strong>Another page</strong>
            </a>
          </li>  
          <li class="table-view-cell"> 
            <a class="push-right" rel='nofollow' href="https://github.com/twbs/ratchet/">
              <strong>Ratchet on Github</strong>
            </a>

      </div>
    </div>

Here is my two.html file

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Notes</title>
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">

    <!-- Roboto
    <link rel="stylesheet" rel='nofollow' href="//fonts.googleapis.com/css?family=Roboto:400,500,700"> -->

    <link rel="stylesheet" rel='nofollow' href="ratchet.min.css">
    <script src="ratchet.min.js"></script>
  </head>
  <body>
      <header class="bar bar-nav">
  <h1 class="title">Two</h1>
    </header>
  </body>
  <div class="content">
  <script src="js/sample.js" class="js-custom" id="sample.js"></script>
  </div>
</html>

But i run the project i get

Uncaught ReferenceError: CustomEvent is not defined at file:///android_asset/www/js/ratchet.min.js:10

please help me.


Source: (StackOverflow)

Using PHP Pthreads with Ratchet Websocket

I am making an html5 game www.titansoftime.com

I am using ratchet as a php websocket server solution. It works great! http://socketo.me/docs/push

I have done several standalone test using the php pthreads extension and have seen some very exciting results. It truly works and works well.. as long as websockets aren't in the mix.

Pthreads give php multithreading capabilities (it really does work and it's amazing). http://php.net/manual/en/book.pthreads.php

This is what I do:

/src/server.php This is the file that launches the daemon.

    <?php
    session_start();

    use Ratchet\Server\IoServer;
    use Ratchet\WebSocket\WsServer;
    use MyApp\Pusher;

    require __DIR__ . '/../vendor/autoload.php';

    require_once __DIR__ . '/../mysql.cls.php';
    require_once __DIR__ . '/../game.cls.php';
    require_once __DIR__ . '/../model.cls.php';

    $mysql = new mysql;
    $game  = new game;

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

    $loop->addPeriodicTimer(0.50, function() use($pusher){
        $pusher->load();
    });

    $webSock = new React\Socket\Server($loop);

    if ($loop instanceof \React\EventLoop\LibEventLoop) {
        echo "\n HAS LibEvent";
    }

    $webSock->listen(8080, '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($pusher)
            ),
            $webSock
    );

    $loop->run();

This all works fine.

/src/MyApp/Pusher.php This class pushes data to all connected users.

<?php
namespace MyApp;
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;

class AsyncThread extends \Thread{

    public $client;

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

    public function run(){

        // do work on $this->client
        $user = mysql::assoc('SELECT * from users WHERE connection_id = "'.$this->client->resourceId.'"');
        // etc..
        $this->client->send(json_encode(array('foo'=>'bar')));

    }

}

class Pusher implements MessageComponentInterface{

    public static $clients = array();

    #load
    public static function load(){

        $client_count = count(self::$clients);

        echo "\n\n\n".'Serving to '.$client_count.' clients. '.time();

        $start = $istart = microtime(true);

        if( !count(self::$clients) ){
            if( !mysql_ping() ){
                $game->connect();
            }
        }

        $threads = array();
        foreach( self::$clients as $key => $client ){       

            // HANDLE CLIENT

            // This works just fine, the only problem is that if I have lets say 50 simultaneous users, the people near the end of the clients array will have to wait till the other users have been processed. This is not desirable
            $client->send(json_encode('foo'=>'bar'));

           // So I tried this:
           $threads[$key] = new AsyncThread($client);
           $threads[$key]->start();

           // At this point the AsyncThread class will throw a fatal error complaining about not being able to serialize a closure. 
          // If I dont set "$this->data = $client;" in the thread constructor no error appears but now I cant use the data.

           // Also regardless of whether or not I bind the data in the AsyncThread constructor,
           // the connection disappears if I call "new AsyncThread($client)". I cannot explain this behavior.

        }

    }

    public function onMessage(ConnectionInterface $from, $msg) {
        global $game;
        if( $msg ){
            $data = json_decode($msg);
            if( $data ){    

                switch( $data->task ){

                    #connect
                    case 'connect':
                        echo "\n".'New connection! ('.$from->resourceId.') '.$from->remoteAddress;
                        self::$clients[] = $from;
                        break;

                    default:
                        self::closeConnection($from);
                        echo "\nNO TASK CLOSING";
                        break;

                }
            }else{
                echo "\n NO DATA";
                self::closeConnection($from);
            }
        }else{
            echo "\n NO MSG";
            self::closeConnection($from);
        }
    }

    public function closeConnection($conn){
        global $game;
        if( $conn ){
            if( $conn->resourceId ){
                $connid = $conn->resourceId;
                $conn->close(); 
                $new = array();
                foreach( self::$clients as $client ){
                    if( $client->resourceId != $connid ){
                        $new[] = $client;
                    }
                }
                self::$clients = $new;
                $game->query('UPDATE users set connection_id = 0 WHERE connection_id = "'.intval($connid).'" LIMIT 1');
                echo "\n".'Connection '.$connid.' has disconnected';
            }
        }
    }

    public function onClose(ConnectionInterface $conn) {
        echo "\nCLIENT DROPPED";
        self::closeConnection($conn);
    }

    public function onOpen(ConnectionInterface $conn) {
    }
    public function onError(ConnectionInterface $conn, \Exception $e) {
        echo "\nCLIENT ERRORED";
        self::closeConnection($conn);
    }
    public function onSubscribe(ConnectionInterface $conn, $topic) {
    }
    public function onUnSubscribe(ConnectionInterface $conn, $topic) {
    }
    public function onCall(ConnectionInterface $conn, $id, $topic, array $params) {
    }
    public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible) {
    }

}

This all works fine as long as I don't create a thread inside the event loop.

Am I going about this the wrong way or is php multithreading and websockets incompatible?


Source: (StackOverflow)

Node.js with Laravel 4.2

I currently working on php project - Laravel 4.2 framework. I need to use node.js. Need to real time update count of users that registered, on dashbord.

I tried with Ratchet , but I'm not clear following file path that we must edit.

  • /src/MyApp/Chat.php
  • /bin/chat-server.php

Does someone have experience working with node.js on Laravel? Please help me.


Source: (StackOverflow)