You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
4.3 KiB
141 lines
4.3 KiB
<?php |
|
namespace Ratchet\Server; |
|
use Ratchet\MessageComponentInterface; |
|
use React\EventLoop\LoopInterface; |
|
use React\Socket\ServerInterface; |
|
use React\EventLoop\Factory as LoopFactory; |
|
use React\Socket\Server as Reactor; |
|
|
|
/** |
|
* Creates an open-ended socket to listen on a port for incoming connections. |
|
* Events are delegated through this to attached applications |
|
*/ |
|
class IoServer { |
|
/** |
|
* @var \React\EventLoop\LoopInterface |
|
*/ |
|
public $loop; |
|
|
|
/** |
|
* @var \Ratchet\MessageComponentInterface |
|
*/ |
|
public $app; |
|
|
|
/** |
|
* Array of React event handlers |
|
* @var \SplFixedArray |
|
*/ |
|
protected $handlers; |
|
|
|
/** |
|
* The socket server the Ratchet Application is run off of |
|
* @var \React\Socket\ServerInterface |
|
*/ |
|
public $socket; |
|
|
|
/** |
|
* @param \Ratchet\MessageComponentInterface $app The Ratchet application stack to host |
|
* @param \React\Socket\ServerInterface $socket The React socket server to run the Ratchet application off of |
|
* @param \React\EventLoop\LoopInterface|null $loop The React looper to run the Ratchet application off of |
|
*/ |
|
public function __construct(MessageComponentInterface $app, ServerInterface $socket, LoopInterface $loop = null) { |
|
if (false === strpos(PHP_VERSION, "hiphop")) { |
|
gc_enable(); |
|
} |
|
|
|
set_time_limit(0); |
|
ob_implicit_flush(); |
|
|
|
$this->loop = $loop; |
|
$this->app = $app; |
|
$this->socket = $socket; |
|
|
|
$socket->on('connection', array($this, 'handleConnect')); |
|
|
|
$this->handlers = new \SplFixedArray(3); |
|
$this->handlers[0] = array($this, 'handleData'); |
|
$this->handlers[1] = array($this, 'handleEnd'); |
|
$this->handlers[2] = array($this, 'handleError'); |
|
} |
|
|
|
/** |
|
* @param \Ratchet\MessageComponentInterface $component The application that I/O will call when events are received |
|
* @param int $port The port to server sockets on |
|
* @param string $address The address to receive sockets on (0.0.0.0 means receive connections from any) |
|
* @return IoServer |
|
*/ |
|
public static function factory(MessageComponentInterface $component, $port = 80, $address = '0.0.0.0') { |
|
$loop = LoopFactory::create(); |
|
$socket = new Reactor($loop); |
|
$socket->listen($port, $address); |
|
|
|
return new static($component, $socket, $loop); |
|
} |
|
|
|
/** |
|
* Run the application by entering the event loop |
|
* @throws \RuntimeException If a loop was not previously specified |
|
*/ |
|
public function run() { |
|
if (null === $this->loop) { |
|
throw new \RuntimeException("A React Loop was not provided during instantiation"); |
|
} |
|
|
|
// @codeCoverageIgnoreStart |
|
$this->loop->run(); |
|
// @codeCoverageIgnoreEnd |
|
} |
|
|
|
/** |
|
* Triggered when a new connection is received from React |
|
* @param \React\Socket\ConnectionInterface $conn |
|
*/ |
|
public function handleConnect($conn) { |
|
$conn->decor = new IoConnection($conn); |
|
|
|
$conn->decor->resourceId = (int)$conn->stream; |
|
$conn->decor->remoteAddress = $conn->getRemoteAddress(); |
|
|
|
$this->app->onOpen($conn->decor); |
|
|
|
$conn->on('data', $this->handlers[0]); |
|
$conn->on('end', $this->handlers[1]); |
|
$conn->on('error', $this->handlers[2]); |
|
} |
|
|
|
/** |
|
* Data has been received from React |
|
* @param string $data |
|
* @param \React\Socket\ConnectionInterface $conn |
|
*/ |
|
public function handleData($data, $conn) { |
|
try { |
|
$this->app->onMessage($conn->decor, $data); |
|
} catch (\Exception $e) { |
|
$this->handleError($e, $conn); |
|
} |
|
} |
|
|
|
/** |
|
* A connection has been closed by React |
|
* @param \React\Socket\ConnectionInterface $conn |
|
*/ |
|
public function handleEnd($conn) { |
|
try { |
|
$this->app->onClose($conn->decor); |
|
} catch (\Exception $e) { |
|
$this->handleError($e, $conn); |
|
} |
|
|
|
unset($conn->decor); |
|
} |
|
|
|
/** |
|
* An error has occurred, let the listening application know |
|
* @param \Exception $e |
|
* @param \React\Socket\ConnectionInterface $conn |
|
*/ |
|
public function handleError(\Exception $e, $conn) { |
|
$this->app->onError($conn->decor, $e); |
|
} |
|
}
|
|
|