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) {
Related
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!
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);
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 ?
I have server login to my site. I use for API Restler 3 with OAuth2.
Server.php:
<?php
namespace Auth;
use Luracast\Restler\iAuthenticate;
use OAuth2\GrantType\UserCredentials;
use OAuth2\Storage\Pdo;
use OAuth2\Server as OAuth2Server;
use OAuth2\GrantType\AuthorizationCode;
use OAuth2\GrantType\ClientCredentials;
use OAuth2\Request;
use OAuth2\Response;
/**
* Class Server
*
* #package OAuth2
*
*/
class Server implements iAuthenticate
{
private $host = DB_HOST;
private $dbName = DB_NAME;
private $user = DB_LOGIN;
private $pass = DB_PASS;
/**
* #var OAuth2Server
*/
protected static $server;
/**
* #var Pdo
*/
protected static $storage;
/**
* #var Request
*/
protected static $request;
public function __construct()
{
$dns = "mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=utf8";
static::$storage = new PDO(
array('dsn' => $dns, 'username' => $this->user, 'password' => $this->pass)
);
$grantTypes = array(
'authorization_code' => new AuthorizationCode(static::$storage),
'user_credentials' => new UserCredentials(static::$storage),
);
static::$request = Request::createFromGlobals();
static::$server = new OAuth2Server(
static::$storage,
array('enforce_state' => true, 'allow_implicit' => true),
$grantTypes
);
$grantType = new ClientCredentials(static::$storage);
static::$server->addGrantType($grantType);
}
/**
* Stage 2: User response is captured here
*
* Success or failure is communicated back to the Client using the redirect
* url provided by the client
*
* On success authorization code is sent along
*
*
* #param bool $authorize
*
* #return \OAuth2\Response
*
* #format JsonFormat,UploadFormat
*/
public function postAuthorize($authorize = false)
{
static::$server->handleAuthorizeRequest(
static::$request,
new Response(),
(bool)$authorize
)->send();
exit;
}
/**
* Stage 3: Client directly calls this api to exchange access token
*
* It can then use this access token to make calls to protected api
*
* #format JsonFormat,UploadFormat
* #access public
* #url POST apiMobile/grand
* #url GET apiMobile/rer
*/
public function postGrant()
{
static::$server->handleTokenRequest(static::$request)->send();
exit;
}
/**
* Access verification method.
*
* API access will be denied when this method returns false
*
* #return boolean true when api access is allowed; false otherwise
*/
public function __isAllowed()
{
$token = static::$server->getAccessTokenData(Request::createFromGlobals());
global $idClient;
$idClient = $token['client_id'];
return self::$server->verifyResourceRequest(static::$request);
}
public function __getWWWAuthenticateString()
{
return 'auth string';
}
}
?>
And init.php:
<?php
use Luracast\Restler\Restler;
class ApiMode
{
private $class = '';
private $function = '';
public function __construct($controller = DEFAULT_CONTROLLER, $function = DEFAULT_FUNCTION)
{
$this->class = $controller;
$this->function = $function;
$controllerClass = ucfirst($this->class).CONTROLLER_TERMINAL;
$controllerPatch = CONTROLLER_DIR.'/'.$controllerClass.'.php';
require_once $controllerPatch;
require_once EXTERN_DIR.'/OAuth2/Autoloader.php';
OAuth2\Autoloader::register();
require_once EXTERN_DIR.'/vendor/restler.php';
require_once CLASS_DIR.'/Server.php';
$r = new Restler();
$r->addAuthenticationClass('Auth\\Server', '');
$r->setSupportedFormats('JsonFormat', 'XmlFormat');//,
$r->addAPIClass($controllerClass,'');
$r->setOverridingFormats('JsonFormat');
$r->setOverridingFormats('UploadFormat');
$r->handle();
}
}
?>
I use only Stage 3 - postGrand to get access token.
From web browser on http://mypage/apiMobile/rer.json (GET is for test from my web browser if GET work, POST work well) get:
local server Windows (this is OK):
{"error":"invalid_request","error_description":"The request method must be POST when requesting an access token","error_uri":"http:\/\/tools.ietf.org\/html\/rfc6749#section-3.2"}
web server (use https) Linux PHP 5.5.21 (fail):
{
"error": {
"code": 404,
"message": "Not Found"
},
"debug": {
"source": "Routes.php:438 at route stage",
"stages": {
"success": [
"get"
],
"failure": [
"route",
"negotiate",
"message"
]
}
}
}
On web server and local work all from API (address: mypage/apiMobile/myApi.json from controller):
$r->addAPIClass($controllerClass,'');
Main problem is with access to OAuth2 (I need access from http://mypage/apiMobile/rer.json). Any idea or tutorial?
Thanks.
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
}