-
-
Save Mevrael/6855dd47d45fa34ee7161c8e0d2d0e88 to your computer and use it in GitHub Desktop.
<?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'); |
<?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; | |
} | |
} |
<?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(); |
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];
}
}
foreach ($this->clients as $client) {
if ($con != $client) {
$params['other_clients'][] = $client;
} else {
$params['current_client'] = $client;
}
}
$wsrequest = $con->httpRequest;
$cookies = $wsrequest->getHeader("Cookie");
$cookies = \GuzzleHttp\Psr7\parse_header($cookies)[0];
$app = App::getInstance();
$kernel = $app->make(\Illuminate\Contracts\Http\Kernel::class);
$request = \Illuminate\Http\Request::create($route, 'GET', $params, $cookies);
$request->headers->set('Authorization', 'Bearer '.$cookies['X-Authorization'],);
$response = $kernel->handle(
$request
);
$response->getContent();
$controllerResult = $response->getContent();
// var_dump($controllerResult);
$kernel->terminate($request, $response);
return json_encode($controllerResult);`
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.
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
as mentioned at http://socketo.me/docs/migration-3 Guzzle Http API changed, so, getting cookies could be smth like