Basic react http server and websocket server at the same time - php

I managed to create a web service that listens on port 80 for http requests and handles ajax calls and also long polling.
But I'm stuck at creating a similar websocke server in the same php file
<?php
require_once('vendor/autoload.php');
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);
$conn->send('aa');
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();
}
}
$loop = React\EventLoop\Factory::create();
$swsa=new Chat;
$webSock = new React\Socket\Server($loop);
$webSock->listen(8687, '127.0.0.1'); // Binding to 0.0.0.0 means remotes can connect
$webServer = new Ratchet\Server\IoServer(
new Ratchet\Http\HttpServer(
new Ratchet\WebSocket\WsServer(
$swsa
)
),
$webSock
);
$app = function ($request, $response) {
//some code here to manage requests
$response->writeHead(200,array('Content-Type'=>'application/json'));
$response->end(json_encode(array('ok'=>'ok')));
};
$socket = new React\Socket\Server($loop);
$http = new React\Http\Server($socket, $loop);
$http->on('request', $app);
$socket->listen(8485);
$loop->run();
Code in browser:
var wsUri = "ws://127.0.0.1:8687/";
websocket = new WebSocket(wsUri);
This triggers an error in the browser
Firefox can't establish a connection to the server at ws://127.0.0.1:8687/

Your IoServer initialization is incorrect. If you check the code for IoServer class, you will find:
public function __construct(MessageComponentInterface $app,ServerInterface $socket, LoopInterface $loop = null)
and
public function run() {
if (null === $this->loop) {
throw new \RuntimeException("A React Loop was not provided during instantiation");
}
// #codeCoverageIgnoreStart
$this->loop->run();
// #codeCoverageIgnoreEnd
}
The IoServer class object has no loop assigned to it and hence it fails to execute. Try passing loop as your third argument.

Related

my ratchet websockets noot working on shared server

i am using php ratchet websockets on my shared server on one domain the ratchet websockets is working perfectly but when i run sockets on my other domain it give me some tcp errors both of my domains are on the same server.
That is my socket.php code many time I changes my port number also but nothing happended
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
require 'chat.php';
$loop = React\EventLoop\Factory::create();
// Run the server application through the WebSocket protocol on port 8888
$app = new Ratchet\App("example.com", 8888, '0.0.0.0',$loop);
$app->route('/chat', new Chat, array('*'));
$app->run();
$app->enableKeepAlive($app->loop, 10);
?>
and here is my chat.php code
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = array();
}
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients[$conn->resourceId] = $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 $key => $client) {
if ($from !== $client) {
// The sender is not the receiver, send to each client connected
$client->send($msg);
}
}
// Send a message to a known resourceId (in this example the sender)
$client = $this->clients[$from->resourceId];
$client->send("Message sent to $numRecv users.");
}
public function onClose(ConnectionInterface $conn) {
// The connection is closed, remove it, as we can no longer send it messages
unset($this->clients[$conn->resourceId]);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
}
?>
now when i run php socket.php on command line than it is not doing anything and when i run the socket.php url it shows this page isn't workingbelow is my composer.json code
{
"require": {
"cboden/ratchet": "^0.4.2",
"textalk/websocket": "^1.3"
}
}
I also installed mbstring and iconv in my domain.
The error is:
PHP Fatal error: Uncaught RuntimeException: Failed to listen on
"tcp://127.0.0.1:8843": Address already in use in
/home/example.com/public_html/test/rachet/vendor/react/socket/src/TcpServer.php:164

Ratchet PHP Websocket Library works fine but causing HTTP code 503 Service unavailable after running for for a few days

I am using Ratchet for Websockets in my application. I am running the Websocket server in supervisor. The application runs well for sometime even when there is high traffic but after some time the server responds with a 503 service unavailable error when I try to access the application in the browser until I restart supervisor and It runs fine again for some time. This happens at times when there is low traffic to the sever so I do not think it a traffic problem.
Could I have missed a configuration somewhere during deployment of Ratchet because it is the only program that I am running in supervisor.
Thanks for your assistance.
I solved this by adding gc_collect_cycles() to the onClose function.
My code now looks like this:
<?php
//Pusher
namespace MyApp;
use Ratchet\ConnectionInterface;
use Ratchet\Wamp\WampServerInterface;
class Pusher implements WampServerInterface
{
//Array of channels with connected clients
protected $subscribed_channels= array();
protected $clients=array();
protected $connections;
public function __construct() {
$this->connections = new \SplObjectStorage;
}
//Accepts client connections and adds the channel subscribed to in the subscribed channels
public function onSubscribe(ConnectionInterface $conn, $channel)
{
$channel_id=$channel->getId();
$this->subscribed_channels[$channel_id] = $channel;
$connection_id=$conn->resourceId;
$this->clients[$connection_id]=array('channel'=>$channel);
$channel_subscriptions=$channel->count();
//echo "Client {$connection_id} has subscribed to {$channel_id} channel. {$channel_subscriptions} Cleints Subscribed \n";
}
//Accepts data as json containing the channel being pushed to, and the data being pushed.
public function onPush($request)
{
$request_array = json_decode($request, true);
if(!isset($request_array['channel']))
{
echo"Channel not sent by app \n";
return;
}
//Check if data has been sent by app
if(!isset($request_array['data']))
{
echo"Data not sent by app \n";
return;
}
// If the channel being pushed to has no subscribers, don't push
if (!array_key_exists($request_array['channel'], $this->subscribed_channels))
{
echo"{$request_array['channel']} channel has no subscribers \n";
return;
}
$channel = $this->subscribed_channels[$request_array['channel']];
// Foward the request to all the subscribers in the channel
$data=json_encode($request_array['data']);
$channel->broadcast($data);
//echo "Pushing data to {$request_array['channel']} channel at ".strftime('%Y-%m-%d %H:%M:%S')."\n";
}
public function onUnSubscribe(ConnectionInterface $conn, $channel)
{
$connection_id=$conn->resourceId;
$channel_id=$channel->getId();
$channel_subscriptions=$channel->count()-1;
if($channel_subscriptions==0)
{
unset($this->subscribed_channels[$channel_id]);
}
//echo "Client {$conn->resourceId} has disconnected from {$channel_id} channel. {$channel_subscriptions} Clients subscribed \n";
}
public function onOpen(ConnectionInterface $conn)
{
$this->connections->attach($conn);
}
public function onClose(ConnectionInterface $conn)
{
$connection_id=$conn->resourceId;
$channel=$this->clients[$connection_id]['channel'];
unset($this->clients[$connection_id]);
$this->onUnSubscribe($conn,$channel);
$this->connections->detach($conn);
gc_collect_cycles();
}
public function onCall(ConnectionInterface $conn, $id, $channel, array $params)
{
// In this application if clients send data it's because the user hacked around in console
$conn->callError($id, $channel, 'You are not allowed to make calls')->close();
}
public function onPublish(ConnectionInterface $conn, $channel, $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)
{
echo "An error has occurred: {$e->getMessage()}\n";
}
}
//Web socket server code
<?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
$context = new React\ZMQ\Context($loop);
$pull = $context->getSocket(ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself
$pull->on('message', array($pusher, 'onPush'));
//Replace the variables $my_ip and $my_port with your server $ip and $port.
$webSock = new React\Socket\Server('$my_ip:$my_port', $loop);
$webServer = new Ratchet\Server\IoServer(
new Ratchet\Http\HttpServer(
new Ratchet\WebSocket\WsServer(
new Ratchet\Wamp\WampServer(
$pusher
)
)
),
$webSock
);
$loop->run();
//My php app code
//You will need the zmq php module in your php for this to work
function push_to_socket($channel,$data)
{
$message = array(
'channel' => $channel
, 'data' => $data
);
$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher');
$socket->connect("tcp://localhost:5555");
$socket->send(json_encode($message));
}
//My Javascript code
//You need AutobahnJS for this to work.
//You might also need jQuery or else modify the code to eliminate jQuery syntax
//Replace 'channel' with a channel/topic name you want to use.
<script type="text/javascript">
$(document).ready(get_connected);
function get_connected()
{
var hasWs = 'WebSocket' in window || 'MozWebSocket' in window;
if (hasWs)
{
conn = new ab.Session('wss:{my_domain}/wss',
function()
{
conn.subscribe('channel', function(topic,message){
//Process your message
});
},
function() {
//console.warn('Connection closed');
get_connected();
},
{'skipSubprotocolCheck': true}
);
}
}
</script>

make a multi thread websocket

I made a Websocket server using ratchet and php it works fine but the problem is it's not multi thread and this makes the server replay late when multiple clients send messages to the server at the same time.
I want to know if there is any way to make it multi thread so each connection run on it's own thread or if it's not the right way give me a better one
Thanks!
Chat.php codes:
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
require 'vendor/autoload.php';
require(dirname(dirname(__FILE__)).'/inc/class/class-app_api.php');
class Chat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
echo 'server Started!';
}
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');
$obj = new \app_api($from, $msg);
$res = $obj->handleRequest();
if (is_array($res)) {
foreach ($this->clients as $client) {
if ($from != $client) {
// The sender is not the receiver, send to each client connected
$client->send($res['data']);
}
}
}else {
$from->send($res);
}
}
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";
$obj = new \venicehost_app_api($from);
$conn->send($obj->setError('An error has occurred:' . $e->getMessage()));
//$conn->close();
}
}
?>
Server.php codes:
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;
require_once("Chat.php");
//require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
port,
ip address
);
$server->run();
?>

Deploy Ratchet Server on google app engine and listen

I am creating a ratchet chat application. It is currently on my localhost 8080 however I want to connect it to my google app engine project what can I do
Here is my Ratchet code:
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 . " Hello ");
}
}
}
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();
}
}
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8080
);
$server->run();
Does App Engine support that, if not what other alternatives can I use to deploy my chat on a live application

PHP WebSocket Server: Unable to connect clients

I have a PHP based Websocket server that is used to connect web clients. The WebSocket server itself serving as a Client for WhatsApp. I want when server goes up, it then make a call to WhatsApp and make a live connection. Below is my WebSocket Class. Since there's an infinite While loop, other things are not being called; like connecting a client.
How do I make it that when Web Socket server loads up, it makes a connection to WhatsApp server as well and then let other clients to connect Web Socket server
Chat.php
#!/usr/local/bin/php
<?php
ini_set('display_errors',1);
error_reporting(E_ALL);
require_once __DIR__.'/vendor/autoload.php';
require_once 'vendor/whatsapp/chat-api/src/whatsprot.class.php';
require_once 'vendor/whatsapp/chat-api/src/events/MyEvents.php';
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Guzzle\Http\Client;
use Guzzle\Http\EntityBody;
use Guzzle\Http\Message\Request;
use Guzzle\Http\Message\Response;
class Chat implements MessageComponentInterface {
protected $clients;
protected $message;
protected $client_info = []; //To hold which agent was connected
protected $username = 'xx';
protected $password = 'xx=';
protected $nickname = 'xx Number';
protected $target = "xx";
protected $debug = false;
public function __construct() {
$this->clients = new \SplObjectStorage;
print("..Server is coming up..\n");
echo "[] Logging in as '$this->nickname' ($this->username)\n";
$w = new WhatsProt($this->username, $this->nickname, $this->debug,true,__DIR__.'/wadata/');
$events = new MyEvents($w);
$events->setEventsToListenFor($events->activeEvents);
$w->connect();
$w->loginWithPassword($this->password);
print("..Accepting WhatsApp Messages...\n");
while (1) {
$w->pollMessage();
}
}
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients->attach($conn);
//Identity Message
$this->message = json_encode(['STATUS'=> 'CONNECTED','CLIENT_ID' => $conn->resourceId]);
$conn->send($this->message);
$this->message = json_encode(['STATUS' => 'NEW', 'TYPE'=> 'TEXT','MESSAGE' => "This is by customer"]);
//Actual WhatsApp message
$conn->send($this->message);
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
print("CLIENT SAYS:- ".$msg."\n");
foreach ($this->clients as $client) {
if ($from === $client) {
$msg = 'WA Server responds:- '.$msg;
$client->send($this->message);
}
}
}
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();
}
}
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8080
);
$server->run();

Categories