How to use Ratchet Websocket with session provider and load balancer - php

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!

Related

Laravel job Vonage notification try/catch doesn't go into catch statement

I'm trying to catch Vonage API errors in my Laravel job file so that I can determine whether to deduct credits from a user's account.
My job consists of a function called attemptSend. When I log the before and after, I can see that the message attempt, first and second logs are all logging, but not the message failed despite there being an exception thrown and logged by Laravel.
What am I missing here to catch this?
Here's my job file:
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Log;
use App\Notifications\Messages\SendMessageViaVonageEngine;
use App\Models\User;
use App\Models\Message;
use App\Models\Sanctum\PersonalAccessToken;
use Carbon\Carbon;
class ProcessMessage implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* The number of times the job may be attempted.
*
* #var int
*/
public $tries = 1;
/**
* The message id
*/
protected $messageId;
/**
* The user id
*/
protected $userId;
/**
* The API key's UUID.
*/
protected $apiKeyUuid;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($messageId, $userId, $apiKeyUuid)
{
$this->messageId = $messageId;
$this->userId = $userId;
$this->apiKeyUuid = $apiKeyUuid;
}
/**
* Get API key
*/
public function getApiKey()
{
return PersonalAccessToken::where('tokenable_id', $this->userId)
->where('uuid', $this->apiKeyUuid)
->withSum('credit_transactions AS credit_balance', 'delta')
->first();
}
/**
* Get the message
*/
public function getMessage()
{
return Message::where('id', $this->messageId)
->where('user_id', $this->userId)
->first();
}
/**
* Update message status
*/
public function updateMessageStatus($message, $status = 'sending', $reason = null)
{
$message->status = $status;
// set reason
if ($reason) {
$message->reason = $reason;
}
// mark the sent_at date
if (!$message->sent_at && $status == 'sending') {
$message->sent_at = Carbon::now();
}
$message->save();
}
/**
* Attempt to send
*/
public function attemptSend($message)
{
Log::debug('MESSAGE:ATTEMPT');
try {
Log::debug('MESSAGE:SUCCESS-FIRST');
$sent = Notification::route('vonage', $message->send_to)
->notify(new SendMessageViaVonageEngine($message));
Log::debug('MESSAGE:SUCCESS-SECOND', [
'sent' => $sent
]);
} catch (\Exception $e) {
Log::debug('MESSAGE:FAILED');
throw new \Exception($e->getMessage());
}
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$apiKey = $this->getApiKey();
$message = $this->getMessage();
if (! $message) {
throw new \Exception("Message can't be found, was it deleted? Unable to send message.");
return;
}
if (! $apiKey) {
$this->updateMessageStatus($message, 'dead', "API key not found");
throw new \Exception("API key can't be found, was it deleted? Unable to send message.");
return;
}
if (! $apiKey->credit_balance || $apiKey->credit_balance <= 0) {
$this->updateMessageStatus($message, 'dead', "Insufficient credits");
throw new \Exception("API key: $apiKey->uuid has run out of credits. Unable to send message.");
return;
}
$this->updateMessageStatus($message, 'sending', "Attempting to send");
$this->attemptSend($message);
}
}

Run Ratchet php server without need of cli

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

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;

Laravel error with message 'A facade root has not been set

I have recently installed Ratchet on my laravel installation to enable push services over sockets.
This is what my SocketController class looks like (note: it does NOT extend controller)
class SocketController implements WampServerInterface
{
/**
* A lookup of all the topics clients have subscribed to
*/
protected $subscribedTopics = array();
public function onSubscribe(ConnectionInterface $conn, $topic) {
echo"\n SUBSCRING TOPIC: $topic";
echo " hi \n";
try {
JWTAuth::parseToken("okay");
} catch (TokenExpiredException $e) {
echo "hi" ;
} catch (TokenInvalidException $e) {
echo "hi" ;
} catch (JWTException $e) {
echo "hi" ;
}
catch(\Exception $q){
echo $q;
}
$this->subscribedTopics[$topic->getId()] = $topic;
}
/**
* #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['category'], $this->subscribedTopics)) {
return;
}
$topic = $this->subscribedTopics[$entryData['category']];
// re-send the data to all the clients subscribed to that category
$topic->broadcast(rand(5,666666));
}
public function onUnSubscribe(ConnectionInterface $conn, $topic) {
}
public function onOpen(ConnectionInterface $conn) {
echo"open";
}
public function onClose(ConnectionInterface $conn) {
echo "close";
}
/* The rest of our methods were as they were, omitted from docs to save space */
/**
* 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.
}
/**
* An RPC call has been received
* #param \Ratchet\ConnectionInterface $conn
* #param string $id The unique ID of the RPC, required to respond to
* #param string|Topic $topic The topic to execute the call against
* #param array $params Call parameters received from the client
*/
function onCall(ConnectionInterface $conn, $id, $topic, array $params)
{
// TODO: Implement onCall() method.
}
/**
* A client is attempting to publish content to a subscribed connections on a URI
* #param \Ratchet\ConnectionInterface $conn
* #param string|Topic $topic The topic the user has attempted to publish to
* #param string $event Payload of the publish
* #param array $exclude A list of session IDs the message should be excluded from (blacklist)
* #param array $eligible A list of session Ids the message should be send to (whitelist)
*/
function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible)
{
// TODO: Implement onPublish() method.
}
I am using the JWT library, and just to check,have the line
JWTAuth::parseToken("okay");
But that line throws an error:
exception 'RuntimeException' with message 'A facade root has not been
set.'
How do I include JWT auth into my own class ?

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