| 
<?php
 use GuzzleHttp\Psr7\Response;
 use Ratchet\RFC6455\Handshake\PermessageDeflateOptions;
 use Ratchet\RFC6455\Messaging\MessageBuffer;
 use Ratchet\RFC6455\Messaging\MessageInterface;
 use Ratchet\RFC6455\Messaging\FrameInterface;
 use Ratchet\RFC6455\Messaging\Frame;
 
 require_once __DIR__ . "/../bootstrap.php";
 
 $loop   = \React\EventLoop\Factory::create();
 
 $socket = new \React\Socket\Server('0.0.0.0:9001', $loop);
 
 $closeFrameChecker = new \Ratchet\RFC6455\Messaging\CloseFrameChecker;
 $negotiator = new \Ratchet\RFC6455\Handshake\ServerNegotiator(new \Ratchet\RFC6455\Handshake\RequestVerifier, PermessageDeflateOptions::permessageDeflateSupported());
 
 $uException = new \UnderflowException;
 
 
 $socket->on('connection', function (React\Socket\ConnectionInterface $connection) use ($negotiator, $closeFrameChecker, $uException, $socket) {
 $headerComplete = false;
 $buffer = '';
 $parser = null;
 $connection->on('data', function ($data) use ($connection, &$parser, &$headerComplete, &$buffer, $negotiator, $closeFrameChecker, $uException, $socket) {
 if ($headerComplete) {
 $parser->onData($data);
 return;
 }
 
 $buffer .= $data;
 $parts = explode("\r\n\r\n", $buffer);
 if (count($parts) < 2) {
 return;
 }
 $headerComplete = true;
 $psrRequest = \GuzzleHttp\Psr7\parse_request($parts[0] . "\r\n\r\n");
 $negotiatorResponse = $negotiator->handshake($psrRequest);
 
 $negotiatorResponse = $negotiatorResponse->withAddedHeader("Content-Length", "0");
 
 if ($negotiatorResponse->getStatusCode() !== 101 && $psrRequest->getUri()->getPath() === '/shutdown') {
 $connection->end(\GuzzleHttp\Psr7\str(new Response(200, [], 'Shutting down echo server.' . PHP_EOL)));
 $socket->close();
 return;
 };
 
 $connection->write(\GuzzleHttp\Psr7\str($negotiatorResponse));
 
 if ($negotiatorResponse->getStatusCode() !== 101) {
 $connection->end();
 return;
 }
 
 // there is no need to look through the client requests
 // we support any valid permessage deflate
 $deflateOptions = PermessageDeflateOptions::fromRequestOrResponse($psrRequest)[0];
 
 $parser = new \Ratchet\RFC6455\Messaging\MessageBuffer($closeFrameChecker,
 function (MessageInterface $message, MessageBuffer $messageBuffer) {
 $messageBuffer->sendMessage($message->getPayload(), true, $message->isBinary());
 }, function (FrameInterface $frame) use ($connection, &$parser) {
 switch ($frame->getOpCode()) {
 case Frame::OP_CLOSE:
 $connection->end($frame->getContents());
 break;
 case Frame::OP_PING:
 $connection->write($parser->newFrame($frame->getPayload(), true, Frame::OP_PONG)->getContents());
 break;
 }
 }, true, function () use ($uException) {
 return $uException;
 },
 null,
 null,
 [$connection, 'write'],
 $deflateOptions);
 
 array_shift($parts);
 $parser->onData(implode("\r\n\r\n", $parts));
 });
 });
 
 $loop->run();
 
 |