Run Ratchet php server without need of cli - php

I am implementing a websocket real time chat with Ratchet
It's working fine, The problem is that I need to run server.php via command line so this way the server will work, I can not run the file directly
I tried via:
exec()
And other methods but it fails to run the server, anyone have an alternative or a solution?
server.php
<?php
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
require 'vendor/autoload.php';
require 'class/SimpleChat.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new SimpleChat()
)
),
8080
);
$server->run();
/class/SimpleChat.php
<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class SimpleChat implements MessageComponentInterface
{
/** #var SplObjectStorage */
protected $clients;
/**
* SimpleChat constructor.
*/
public function __construct()
{
conectados
$this->clients = new \SplObjectStorage;
}
/**
* #param ConnectionInterface $conn
*/
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
echo "Cliente conectado ({$conn->resourceId})" . PHP_EOL;
}
/**
* #param ConnectionInterface $from
* #param string $data
*/
public function onMessage(ConnectionInterface $from, $data)
{
$data = json_decode($data);
$data->date = date('d/m/Y H:i:s');
foreach ($this->clients as $client) {
$client->send(json_encode($data));
}
echo "User {$from->resourceId} sent you a message" . PHP_EOL;
}
/**
* #param ConnectionInterface $conn
*/
public function onClose(ConnectionInterface $conn)
{
$this->clients->detach($conn);
echo "User {$conn->resourceId} Disconnected" . PHP_EOL;
}
/**
* #param ConnectionInterface $conn
* #param Exception $e
*/
public function onError(ConnectionInterface $conn, \Exception $e)
{
$conn->close();
echo "Error {$e->getMessage()}" . PHP_EOL;
}
}

I have been into the same problem. Solved it using cURL. Use the following command to
start ratchet server without the need of cli.
$handle = curl_init();
$url = 'Path-to-your-server-file/App/server.php';
curl_setopt($handle,CURLOPT_URL,$url);
curl_setopt($handle, CURLOPT_TIMEOUT, 1);
$data = curl_exec($handle);
curl_close($handle);
print_r($handle);

Related

How to use Ratchet Websocket with session provider and load balancer

I am trying to use websocket server with session handler of Ratchet. I am able to create a server and client and also able to work that locally. but It is not working on the server.
Because on server we have loadbalancer in place and we are storing all the sessions in Redis server.
So, Please let know if you have solution for that.
Adding my Files for the reference.
Reference Link : https://web.archive.org/web/20220520111956/http://socketo.me/docs/sessions
Server.php
use Ratchet\Session\SessionProvider;
use Symfony\Component\HttpFoundation\Session\Storage\Handler;
use App\MyApp;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
$memcache = new Memcache;
$memcache->connect('127.0.0.1', 11211);
$server = IoServer::factory(
new HttpServer(
new SessionProvider(
new WsServer(
new MyApp()
),
new Handler\MemcacheSessionHandler($memcache)
)
),
8080
);
$server->run();
MyApp.php
<?php
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
class MyApp implements MessageComponentInterface
{
public $clients;
public function __construct()
{
$this->clients = new \SplObjectStorage;
}
/**
* A new web socket connection
*
* #param ConnectionInterface $conn
*/
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
/**
* Handle message sending
*
* #param ConnectionInterface $from
* #param string $msg
*/
public function onMessage(ConnectionInterface $from, $msg)
{
$numRecv = count($this->clients) - 1;
foreach ($this->clients as $client) {
if ($from !== $client) {
$client->send($msg);
}
}
return;
}
/**
* A connection is closed
* #param ConnectionInterface $conn
*/
public function onClose(ConnectionInterface $conn)
{
// The connection is closed, remove it, as we can no longer send it messages
$this->clients->detach($conn);
}
/**
* Error handling
*
* #param ConnectionInterface $conn
* #param \Exception $e
*/
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo "An error has occurred: {$e->getMessage()}\n";
$conn->send("Error : " . $e->getMessage());
$conn->close();
}
}
I also tried to store connection data into Redis but was not able to do that.
So, Please help me to make this working with the loadbalancer.
Thanks in advance!

Pusher and laravel echo too slow or something wrong with my code?

I am using Laravel 5.3 on homestead. Here's the code that I am using for broadcasting an event through pusher and laravel echo, to notify the users of a new message in real time -
class NewMessageReceived implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;
public $message;
public $user;
public $sender;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message, User $user)
{
$this->message = $message;
$this->user = $user;
$this->sender = \Auth::user();
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('user.'. $this->user->id);
}
}
Here's the code that calls this event-
try{
$m = $privateChat->messages()->save($m);
if( isset(Auth::user()->guide))
event ( new NewMessageReceived( $m, $m->messageable->tourist->user ));
else
event ( new NewMessageReceived( $m, $m->messageable->guide->user ));
return $m;
}
catch(Exception $e){
return $e;
}
There's an ajax call in vue, which receives the response generated by above code i.e $m .
The problem is if I use the code below instead of the above code, response is recieved at least 5 times faster. I just need to remove the event-firing part to make it run faster (which is not desired, since I want to update user in real time)-
try{
$m = $privateChat->messages()->save($m);
return $m;
}
catch(Exception $e){
return $e;
}
It would be helpful if you could help me spot the reason behind this behaviour and how can I make it all happen in real time, instead of the delay existing now.
You should change ShouldBroadcast to ShouldBroadcastNow. That will solve the problem with delay.
Try this:
Move your if logic to event Class
class NewMessageReceived implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;
public $message;
public $user;
public $sender;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message)
{
$this->message = $message;
$this->user = isset(Auth::user()->guide)) ? $message->messageable->tourist->user : $this->user = $message->messageable->guide->user;
$this->sender = \Auth::user();
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('user.'. $this->user->id);
}
}
Now your event call.
$m = $privateChat->messages()->save($m);
event(new NewMessageReceived($m));
return $m;

PDO Database class not stopping at catching exception

I have the following code within a PDO database class
/**
* Class DB
*/
class DB{
/**
* #var DB The one and only instance of this class;
*/
private static $theOneAndOnly = null;
/**
* #var array
*/
private static $transactionalOptions = array( PDO::ATTR_AUTOCOMMIT => false, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC );
/**
* #var array
*/
private static $nonTransactionalOptions = array( PDO::ATTR_AUTOCOMMIT => true, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC );
/**
* #var PDO
*/
private $transactionalDatabase = null;
/**
* #var PDO
*/
private $nonTransactionalDatabase = null;
/**
* #var bool
*/
private $isConnected = false;
/**
* Initializes the connections to the database. One connection for transaction based operations and one connection
* for non-transactional operations;
*/
private function __construct(){
if($this->isConnected() !== true){
//connect
if($this->connect() !== true){
//connection failed
exit( 'An internal error occurred. Please contact Keyfort support:' );
}
}
}
/**
* #return bool
*/
public function isConnected(){
return $this->isConnected;
}
/**
* #return bool
*/
public function connect(){
try{
$this->transactionalDatabase = new PDO(Config::DB_TYPE . ':host=' . Config::DB_HOST . ';dbname=' . Config::$DB_NAME, Config::$DB_USER, Config::$DB_PASS, self::$transactionalOptions);
$this->nonTransactionalDatabase = new PDO(Config::DB_TYPE . ':host=' . Config::DB_HOST . ';dbname=' . Config::$DB_NAME, Config::$DB_USER, Config::$DB_PASS, self::$nonTransactionalOptions);
$this->isConnected = true;
return true;
} catch(PDOException $exception){
Log::error('Initializing the database connections failed:' . $exception->getTraceAsString());
die();
//return false;
}
}
/**
* #return DB
*/
public static function &getInstance(){
if(self::$theOneAndOnly === null){
self::$theOneAndOnly = new self();
}
return self::$theOneAndOnly;
}
public static function ParamMultiple($key){
return self::Param($key) . ', ';
}
public static function Param($key){
return ':' . $key;
}
/**
* Close all connections;
*/
public function __destruct(){
$this->disconnect();
}
/**
* #return void
*/
public function disconnect(){
$this->transactionalDatabase = null;
$this->nonTransactionalDatabase = null;
$this->isConnected = false;
}
/**
* #return PDO
*/
public function &getTransactional(){
if($this->isConnected() !== true){
$this->connect();
}
return $this->transactionalDatabase;
}
/**
* #return PDO
*/
public function &getBasic(){
if($this->isConnected() !== true){
$this->connect();
}
return $this->nonTransactionalDatabase;
}
}
It gets called via DB::getInstance();
The first time it gets called, it does not "die" if it errors.
I eventually get
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes) in C:\path\to\class\db.php on line 64
Line 64 is the $this->transactionalDatabase line.
It does log the exception in my error log (as in the catch).
I'm drawing a blank as to why its not "die"ing, I've tried alot of things, and I'm wondering if it could be starting 2 PDOs in the try?
[edit]
I'm running through the code with the wrong database user password currently. So I know what the error is caused by (it works ok when i put the correct password in), I just don't understand why it isn't processing the die() in the catch.
Use Fragment:
public static function GetByUsername($username){
$db = DB::getInstance();
$dbh = $db->getBasic();
$sql = 'SELECT * FROM ' . self::TABLE_NAME . ' WHERE ' . self::KEY_USERNAME . ' = ' . DB::Param(self::KEY_USERNAME);
$statement = $dbh->prepare($sql);
$statement->bindValue(DB::Param(self::KEY_USERNAME), $username);
if($statement->execute() === true){
$rawUser = $statement->fetch();
if($rawUser === null){
return null;
} else {
return self::CreateFromSelectResult($rawUser);
}
} else {
Log::error("Fetching user by username failed:" . print_r($dbh->errorInfo(), true));
return null;
}
}
Try using either transactionalDatabase or nonTransactionalDatabase, it should solve the problem.
Make sure your /tmp folder has space to cache queries.
The issue was within "Log::error();"
Log:error() also tries to use the database.
So the issue was an infinite loop that started before the die() line was reached.

Internal Client on Thruway WAMP2

I am working on a sample for Internal Client + Authentication model like the one below.
Now I need to retrieve a list of connected sessions and intercept the close event of a session from Internal Client.
I want to ask if there's any method to archive that task? I was thinking about saving that list in redis, but it means I would have to re-write Thruway\Peer\Router classes, because the needed variables are now private, we don't have access to them to extends.
File server.php
<?php
/**
* server.php
*/
require "../bootstrap.php";
require 'InternalClient.php';
require 'SimpleAuthProviderClient.php';
use Thruway\Peer\Router;
use Thruway\Transport\RatchetTransportProvider;
use React\EventLoop\Factory;
use Thruway\Manager\ManagerClient;
use Thruway\Transport\InternalClientTransportProvider;
$manager = new ManagerClient();
$loop = Factory::create();
$router = new Router($loop, $manager);
$router->addTransportProvider(new InternalClientTransportProvider($manager));
$internalTransportProvider = new InternalClientTransportProvider(new \InternalClient());
$router->addTransportProvider($internalTransportProvider);
$authMgr = new \Thruway\Authentication\AuthenticationManager();
$router->setAuthenticationManager($authMgr);
$router->addTransportProvider(new InternalClientTransportProvider($authMgr));
//Provide authentication for the realm: 'somerealm'
$authProvClient = new SimpleAuthProviderClient(["somerealm"]);
$router->addTransportProvider(new InternalClientTransportProvider($authProvClient));
$transportProvider = new RatchetTransportProvider("127.0.0.1", 9090);
$router->addTransportProvider($transportProvider);
$router->start();
File SimpleAuthProviderClient.php
<?php
/**
* SimpleAuthProviderClient.php
*/
require "../bootstrap.php";
/**
* Class SimpleAuthProviderClient
*/
class SimpleAuthProviderClient extends \Thruway\Authentication\AbstractAuthProviderClient
{
/**
* #return string
*/
public function getMethodName()
{
return 'simplysimple';
}
/**
* #param mixed $signature
* #param null $extra
* #return array
*/
public function processAuthenticate($signature, $extra = null)
{
if ($signature == "letMeIn") {
return ["SUCCESS"];
} else {
return ["FAILURE"];
}
}
}
File InternalClient.php
<?php
/**
* InternalClient.php
*/
require "../bootstrap.php";
/**
* Class InternalClient
*/
class InternalClient extends Thruway\Peer\Client
{
function __construct()
{
parent::__construct("realm1");
}
/**
* #param \Thruway\AbstractSession $session
* #param \Thruway\Transport\TransportInterface $transport
*/
public function onSessionStart($session, $transport)
{
echo "--------------- Hello from InternalClient ------------";
$this->getCallee()->register($this->session, 'com.example.getphpversion', [$this, 'getPhpVersion']);
}
function start()
{
}
/**
* #return array
*/
function getPhpVersion()
{
return [phpversion()];
}
}
For reference purposes, this question was answered on Github.
If you subscribe to the events wamp.metaevent.session.on_join and wamp.metaevent.session.on_leave you will get notified. The event returns 1 argument similar to this:
{
"realm":"realm1",
"authprovider":null,
"authid":"username",
"authrole":"none",
"authmethod":"simplysimple",
"session":6016528494456948
}

PHP Ratchet websocket handshake failing

Just started using ratchet. When I firstly tested it, it worked fine with websockets, got requests etc. But now I am doing the same as I did, but the request (onOpen) isn't even getting requested, and I am getting this JS error:
WebSocket connection to 'ws://localhost:8080/' failed: Error during WebSocket handshake: Unexpected response code: 404
jscode:
var conn = new WebSocket("ws://localhost:8080");
conn.onopen = function(e) {
console.log("Connected!");
conn.send("hello server");
};
conn.onmessage = function (e) {
console.log(e.data);
};
And my source code:
Main file:
require __DIR__ . "../../library/loader.php";
require __DIR__ . "../../vendor/autoload.php";
error_reporting(E_ALL);
use Ratchet\WebSocket\WsServer,
Ratchet\Http\HttpServer,
Ratchet\Server\IoServer;
use bin\library\AsynChatServer;
$server = IoServer::factory(
new HttpServer(
new WsServer(
new AsynChatServer()
)), 8080);
$server->run();
And the server class:
namespace bin\library;
use Ratchet\MessageComponentInterface,
Ratchet\ConnectionInterface,
Ratchet\Server\IoConnection;
use bin\library\database\Db;
use bin\library\model\Client,
bin\library\model\PacketManager;
class AsynChatServer implements MessageComponentInterface {
private $clients;
/** #var Db */
private $database;
/** #var PacketManager */
private $packets;
function __construct()
{
$this->clients = array();
$this->database = new Db();
$this->packets = new PacketManager($this);
AsynChatServer::println("Server has started up.");
}
/**
* When a new connection is opened it will be passed to this method
* #param ConnectionInterface $conn The socket/connection that just connected to your application
* #throws \Exception
*/
function onOpen(ConnectionInterface $conn)
{
echo "request";
/** #var $client Client */
$client = new Client($conn);
$this->clients[$conn->resourceId] = $client;
AsynChatServer::println("New client accepted: " + $client->getClient()->getRemoteAddress());
}
/**
* This is called before or after a socket is closed (depends on how it's closed). SendMessage to $conn will not result in an error if it has already been closed.
* #param ConnectionInterface $conn The socket/connection that is closing/closed
* #throws \Exception
*/
function onClose(ConnectionInterface $conn)
{
// TODO: Implement onClose() method.
}
/**
* If there is an error with one of the sockets, or somewhere in the application where an Exception is thrown,
* the Exception is sent back down the stack, handled by the Server and bubbled back up the application through this method
* #param ConnectionInterface $conn
* #param \Exception $e
* #throws \Exception
*/
function onError(ConnectionInterface $conn, \Exception $e)
{
// TODO: Implement onError() method.
}
/**
* Triggered when a client sends data through the socket
* #param \Ratchet\ConnectionInterface $from The socket/connection that sent the message to your application
* #param string $msg The message received
* #throws \Exception
*/
function onMessage(ConnectionInterface $from, $msg)
{
/** #var $client Client */
$client = $this->clients[$from->resourceId];
AsynChatServer::println("Paccket received from: " . $client->getClient()->getRemoteAddress());
$this->packets->processPacket($client, $msg);
}
public static function println($message) {
echo $message . "\n";
}
public function getDB() {
return $this->database;
}
}
Is there something wrong? Could the library be corrupted so I need to re-set it up?
This is the output i get when I run:
c:\xampp1\php>php c:/xampp1/htdocs/AsynChat/bin/AsynChat.php
Server has started up.
Nothing else when I connect, no signle error.
What is wrong?
NETSTAT -A:
TCP 127.0.0.1:8080 Ben-╧╩:0 LISTENING
TCP 127.0.0.1:8080 Ben-╧╩:0 LISTENING
My App.php constructor:
public function __construct($httpHost = 'localhost', $port = 8080, $address = '127.0.0.1', LoopInterface $loop = null) {

Categories