2024-02-21 02:03:08 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace NoccyLabs\React\WebSocket;
|
|
|
|
|
|
|
|
use Evenement\EventEmitterInterface;
|
|
|
|
use Evenement\EventEmitterTrait;
|
|
|
|
use NoccyLabs\React\WebSocket\Group\GroupManager;
|
|
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
|
|
use React\EventLoop\Loop;
|
|
|
|
use React\Http\Message\Response;
|
|
|
|
use React\Stream\CompositeStream;
|
|
|
|
use React\Stream\ThroughStream;
|
|
|
|
use SplObjectStorage;
|
|
|
|
|
|
|
|
class WebSocketMiddleware implements EventEmitterInterface
|
|
|
|
{
|
2024-02-21 20:38:57 +00:00
|
|
|
const EVENT_CONNECTION = 'connection';
|
|
|
|
|
2024-02-21 02:03:08 +00:00
|
|
|
const MAGIC = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
|
|
|
|
|
|
|
|
use EventEmitterTrait;
|
|
|
|
|
|
|
|
private GroupManager $groupManager;
|
|
|
|
|
|
|
|
private SplObjectStorage $websockets;
|
|
|
|
|
|
|
|
public function __construct(?GroupManager $groupManager = null)
|
|
|
|
{
|
|
|
|
$this->groupManager = $groupManager ?? new GroupManager();
|
|
|
|
$this->websockets = new SplObjectStorage();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function addRoute(string $path, callable $handler, array $allowedOrigins=[]): void
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public function __invoke(ServerRequestInterface $request, callable $next)
|
|
|
|
{
|
2024-02-21 21:26:06 +00:00
|
|
|
|
2024-02-21 02:03:08 +00:00
|
|
|
if ($request->getHeaderLine('upgrade') !== 'websocket') {
|
|
|
|
return $next($request);
|
|
|
|
}
|
|
|
|
|
|
|
|
$handshakeKey = trim($request->getHeaderLine('sec-websocket-key'));
|
|
|
|
$handshakeResponse = base64_encode(sha1($handshakeKey.self::MAGIC,true));
|
|
|
|
|
|
|
|
// Create the streams we need to pass the websocket data back and forth.
|
|
|
|
// This is returned with the response, and passed to the WebSocketConnection.
|
|
|
|
$inStream = new ThroughStream();
|
|
|
|
$outStream = new ThroughStream();
|
|
|
|
$stream = new CompositeStream($outStream, $inStream);
|
|
|
|
|
|
|
|
$websocket = new WebSocketConnection($request, $inStream, $outStream, $this->groupManager);
|
|
|
|
$this->websockets->attach($websocket);
|
|
|
|
$websocket->on('close', function () use ($websocket) {
|
|
|
|
$this->websockets->detach($websocket);
|
|
|
|
});
|
|
|
|
|
2024-02-21 21:26:06 +00:00
|
|
|
// FIXME how to test with futureTick?
|
|
|
|
//Loop::futureTick(function () use ($websocket) {
|
2024-02-21 20:38:57 +00:00
|
|
|
$this->emit(self::EVENT_CONNECTION, [ $websocket ]);
|
2024-02-21 21:26:06 +00:00
|
|
|
//});
|
2024-02-21 02:03:08 +00:00
|
|
|
|
|
|
|
return new Response(
|
|
|
|
Response::STATUS_SWITCHING_PROTOCOLS,
|
|
|
|
array(
|
|
|
|
'Upgrade' => 'websocket',
|
|
|
|
'Connection' => 'upgrade',
|
|
|
|
'Sec-WebSocket-Accept' => $handshakeResponse
|
|
|
|
),
|
|
|
|
$stream
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|