groupManager = $groupManager ?? new GroupManager(); $this->websockets = new SplObjectStorage(); } public function addRoute(string $path, callable $handler, array $allowedOrigins=[]): void { // TODO implement or remove } public function __invoke(ServerRequestInterface $request, callable $next) { 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); }); // FIXME how to test with futureTick? //Loop::futureTick(function () use ($websocket) { $this->emit(self::EVENT_CONNECTION, [ $websocket ]); //}); // TODO would it be possible for the 'connection' event to set additional response headers to be sent here? // For example, to send back Sec-WebSocket-Protocol header. return new Response( Response::STATUS_SWITCHING_PROTOCOLS, array( 'Upgrade' => 'websocket', 'Connection' => 'upgrade', 'Sec-WebSocket-Accept' => $handshakeResponse, 'Sec-WebSocket-Version' => self::VERSION ), $stream ); } }