11

I have a Ratchet server and chat app class which runs fine. My problem is how do I add a periodic loop?

I tried to follow the example in Periodically sending mesages to clients in Ratchet

But I have been getting nowhere. My goal like this guy, is for the server to check all clients are still alive. Everytime I try to use the addPeriodicTimer, I cant seem to access the $clients public property in chat.php like the guy from the link above could in order to send messages from the timer in server.php. The foreach loop in the periodic timer in server.php keeps complaining that it apparently has an "invalid argument".

Can anyone see what im doing wrong?

my server.php code:

<?php


require($_SERVER['DOCUMENT_ROOT'].'/var/www/html/vendor/autoload.php');
require_once($_SERVER['DOCUMENT_ROOT']."/var/www/html/bin/chat.php");

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ram\Chat;


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

 // Server timer <------ having trouble here
$server->loop->addPeriodicTimer(5, function () use ($server) {
foreach($server->app->clients as $client)
{
    //$client->send("[helloworld]");    
}
});


$server->run();
?>

and my chat.php:

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


error_reporting(E_ALL ^ E_NOTICE);
session_id($_GET['sessid']);
    if(!session_id)
        session_start();


    $userid = $_SESSION["userid"];
    $username = $_SESSION["username"];
    $isadmin = $_SESSION["isadmin"];
    $resources = array();





    class Users
    {
        public $name;
        public $resid;
        public $timestamp;



    }



class Chat implements MessageComponentInterface
{
    public $clients;








    var $users = array();



    /*
    function cmp($a, $b)
    {
        return strcmp($a->name, $b->name);
    }


    function removeObjectById(ConnectionInterface $id , $arr)
    {
         $array = $arr;

        foreach ( $array as $key => $element ) {
            if ( $id->resourceId == $element->resid ) 
            {
                unset($array[$key]);
                break;
            }
         }

         usort($array, "cmp");

         return $array;
    }

    */




    public function __construct()
    {

        $this->clients = new \SplObjectStorage; 






    }

    public function onOpen(ConnectionInterface $conn)
    {
        $this->clients->attach($conn);  





    }

    public function onClose(ConnectionInterface $conn)
    {

        //$users = removeObjectById($conn, $users);

        $this->clients->detach($conn);



    }

    public function onMessage(ConnectionInterface $conn, $msg)
    {
         $msgjson = json_decode($msg);
         $tag = $msgjson->tag;

         if($tag == "[msgsend]")
         {

            foreach($this->clients as $client)
            {
                  $client->send($msg);    
            }
     }
     else if($tag == "[bye]")
     {

         foreach($this->clients as $client)
         {
              $client->send($msg);    
         }

         $this->clients->detach($conn);
     }
     else if($tag == "[connected]")
     {
         //store client information
         $temp = new Users();
         $temp->name = $msgjson->uname;
         $temp->resid = $conn->resourceId;
         $temp->timestamp = date('Y-m-d H:i:s');

         $users[] = $temp;

         //usort($users, "cmp");


         //send out messages
          foreach($this->clients as $client)
         {
              $client->send($msg);    
         }



     }
     else if($tag == "[imalive]")
     {
         //update user timestamp who sent [imalive]
         if (is_array($users) || is_object($users))
         {
             foreach($users as $user)
             {
                if($msgjson->uname == $user->name)
                {
                        $user->timestamp = date('Y-m-d H:i:s'); 
                }
             }
         }
     }







}

public function onError(ConnectionInterface $conn, Exception $e)
{
    echo "Error: " . $e->getMessage(); 
    $conn -> close();   
}

}

?> 
Community
  • 1
  • 1
emjay
  • 219
  • 3
  • 12

2 Answers2

4

Why not define the Chat object instance before passing into HTTPServer:

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

// Server timer <------ having trouble here
$server->loop->addPeriodicTimer(5, function () use ($chat) {
foreach($chat->clients as $client)
{
    //$client->send("[helloworld]");    
}
});


$server->run();
mbonneau
  • 627
  • 3
  • 8
  • returns: `Cannot access protected property Chat\Chat::$clients` – maxisme Feb 16 '17 at 21:08
  • I made `$clients` public is this dangerous? – maxisme Feb 16 '17 at 21:14
  • It is not the best from a programming practices point of view - it would probably be better to add a `sendToAll` public method on `Chat` that does the iteration and sending. – mbonneau Feb 16 '17 at 21:18
  • 1
    Also, if you are just interested in having stale connections drop faster - consider using the 0.4 branch of ratchet and using `enableKeepAlive` on the `WsServer` which uses websocket ping frames. – mbonneau Feb 16 '17 at 21:22
  • can you expand on that. The whole point of this loop is to check when the client was last active and if it was more than 15 seconds ago close the connection. – maxisme Feb 16 '17 at 21:59
  • ? Can I install that with pods? – maxisme Feb 17 '17 at 17:21
0
<?php


require($_SERVER['DOCUMENT_ROOT'].'/var/www/html/vendor/autoload.php');
require_once($_SERVER['DOCUMENT_ROOT']."/var/www/html/bin/chat.php");

use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ram\Chat;


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

 // Server timer <------ having trouble here
$server->loop->addPeriodicTimer(5, function () use ($chat) {
foreach($chat->clients as $client)
{
//    $client->send("[helloworld]");    
}
});


$server->run();
?>