Created
March 14, 2017 10:40
-
-
Save Mevrael/6855dd47d45fa34ee7161c8e0d2d0e88 to your computer and use it in GitHub Desktop.
Laravel + WebSocket (Ratchet/ReactPHP) integration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// add this to web routes | |
Route::get('/websocket/open', 'WebSocketController@onOpen'); | |
Route::get('/websocket/message', 'WebSocketController@onMessage'); | |
Route::get('/websocket/close', 'WebSocketController@onClose'); | |
Route::get('/websocket/error', 'WebSocketController@onError'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Controllers; | |
use Illuminate\Http\Request; | |
use Illuminate\Support\Facades\Auth; | |
use Illuminate\Support\Facades\Cookie; | |
use Illuminate\Support\Facades\Mail; | |
use Illuminate\Support\Facades\Session; | |
use Ratchet\WebSocket\Version\RFC6455\Connection; | |
class WebSocketController | |
{ | |
/** | |
* @var Connection | |
*/ | |
protected $connection = null; | |
/** | |
* @var array|mixed | |
*/ | |
protected $data = []; | |
/** | |
* @var Connection | |
*/ | |
protected $currentClient = null; | |
/** | |
* @var Connection[] | |
*/ | |
protected $otherClients = []; | |
public function __construct(Request $request) | |
{ | |
$this->connection = $request->get('connection'); | |
$this->data = $request->get('data'); | |
$this->currentClient = $request->get('current_client'); | |
$this->otherClients = $request->get('other_clients'); | |
} | |
public function sendToOthers(array $data) { | |
foreach ($this->otherClients as $client) { | |
$client->send(json_encode($data)); | |
} | |
} | |
public function onOpen(Request $request) | |
{ | |
if (!Auth::check()) { | |
$this->currentClient->close(); | |
return; | |
} | |
echo 'Opened' . PHP_EOL; | |
echo $request->ip() . PHP_EOL; | |
$this->sendToOthers([ | |
'type' => 'USER_CONNECTED', | |
]); | |
} | |
public function onMessage(Request $request) | |
{ | |
if (!Auth::check()) { | |
$this->currentClient->close(); | |
return; | |
} | |
echo 'New message' . PHP_EOL; | |
echo $request->ip() . PHP_EOL; | |
$this->sendToOthers([ | |
'type' => 'MESSAGE_RECEIVED', | |
'data' => [ | |
'user' => Auth::user()->name, | |
'message' => $this->data->message, | |
] | |
]); | |
} | |
public function onClose(Request $request) | |
{ | |
echo 'Closed' . PHP_EOL; | |
echo $request->ip() . PHP_EOL; | |
$this->sendToOthers([ | |
'type' => 'USER_DISCONNECTED', | |
]); | |
} | |
public function onError(Request $request) | |
{ | |
echo 'Error' . PHP_EOL; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// in Laravel project root create also wsserver.php | |
// use 'php wsserver' to launch Web Socket server | |
// Make sure composer dependencies have been installed | |
require __DIR__ . '/vendor/autoload.php'; | |
use App\User; | |
use Illuminate\Support\Facades\Auth; | |
use Illuminate\Support\Facades\Session; | |
use Ratchet\MessageComponentInterface; | |
use Ratchet\ConnectionInterface; | |
/** | |
* chat.php | |
* Send any incoming messages to all connected clients (except sender) | |
*/ | |
class WebSocketLaravelServer implements MessageComponentInterface | |
{ | |
protected $clients; | |
public function __construct() { | |
echo 'Creating app...' . PHP_EOL; | |
$this->clients = new \SplObjectStorage; | |
} | |
protected function handleLaravelRequest(ConnectionInterface $con, $route, $data = null) | |
{ | |
/** | |
* @var \Ratchet\WebSocket\Version\RFC6455\Connection $con | |
* @var \Guzzle\Http\Message\Request $wsrequest | |
* @var \Illuminate\Http\Response $response | |
*/ | |
$params = [ | |
'connection' => $con, | |
'other_clients' => [], | |
]; | |
if ($data !== null) { | |
if (is_string($data)) { | |
$params = ['data' => json_decode($data)]; | |
} else { | |
$params = ['data' => $data]; | |
} | |
} | |
foreach ($this->clients as $client) { | |
if ($con != $client) { | |
$params['other_clients'][] = $client; | |
} else { | |
$params['current_client'] = $client; | |
} | |
} | |
$wsrequest = $con->WebSocket->request; | |
$app = require __DIR__.'/bootstrap/app.php'; | |
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); | |
$response = $kernel->handle( | |
$request = Illuminate\Http\Request::create($route, 'GET', $params, $wsrequest->getCookies()) | |
); | |
//var_dump(Auth::id()); | |
$controllerResult = $response->getContent(); | |
$kernel->terminate($request, $response); | |
return json_encode($controllerResult); | |
} | |
public function onOpen(ConnectionInterface $con) | |
{ | |
$this->clients->attach($con); | |
$this->handleLaravelRequest($con, '/websocket/open'); | |
} | |
public function onMessage(ConnectionInterface $con, $msg) | |
{ | |
$this->handleLaravelRequest($con, '/websocket/message', $msg); | |
} | |
public function onClose(ConnectionInterface $con) | |
{ | |
$this->handleLaravelRequest($con, '/websocket/close'); | |
$this->clients->detach($con); | |
} | |
public function onError(ConnectionInterface $con, \Exception $e) | |
{ | |
$this->handleLaravelRequest($con, '/websocket/error'); | |
echo 'Error: ' . $e->getMessage() . PHP_EOL; | |
$con->close(); | |
} | |
} | |
// Run the server application through the WebSocket protocol on port 8080 | |
$app = new Ratchet\App('localhost', 8080); | |
$app->route('/echo', new WebSocketLaravelServer); | |
$app->run(); |
I've used this code and added few changes, but whatever I do, code
$response = $kernel->handle( $request );
is causing memory leak.
I've used this code and added few changes, but whatever I do, code
$response = $kernel->handle( $request );
is causing memory leak.
Yes, it causes memory leak.
Does anyone has solution?
I've used this code and added few changes, but whatever I do, code
$response = $kernel->handle( $request );
is causing memory leak.Yes, it causes memory leak.
Does anyone has solution?
Maybe this code will help you
<?php
use \League\OAuth2\Server\ResourceServer;
use \Laravel\Passport\TokenRepository;
use \Laravel\Passport\Guards\TokenGuard;
use \Laravel\Passport\ClientRepository;
use \Illuminate\Support\Facades\Auth;
use \Illuminate\Http\Request;
class UserGetter
{
public static function getUser($bearerToken)
{
$tokenguard = new TokenGuard(
\App::make(ResourceServer::class),
\Auth::createUserProvider('users'),
\App::make(TokenRepository::class),
\App::make(ClientRepository::class),
\App::make('encrypter')
);
$request = Request::create('/');
$request->headers->set('Authorization', $bearerToken);
return $tokenguard->user($request);
}
}
Also you have to use garbage collector like:
gc_collect_cycles();
after all because it still takes a lot of memory
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This kind of code didn't work for me immediately. BUT!
There are few changes to make it working with Bearer token.
Change handleLaravelRequest() method to:
`$params = [
'connection' => $con,
'other_clients' => [],
];
if ($data !== null) {
if (is_string($data)) {
$params = ['data' => json_decode($data)];
} else {
$params = ['data' => $data];
}
}
X-Authorization Cookie on the client side must contain actual Bearer token given by Laravel during auth.
Without this line
$request->headers->set('Authorization', 'Bearer '.$cookies['X-Authorization'],);
it's unable to make working 'auth:api' middleware properly. If header "Authorization" isn't present, you'll continiously get "Unauthorized". You'll even have no ability to use Auth::user()->id inside controller, because you'll get "Unauthorized message" before.