null , 'Hixie76' => null ); public function __construct(ApplicationInterface $app = null) { if (null === $app) { throw new \UnexpectedValueException("WebSocket requires an application to run"); } $this->_app = $app; $this->_factory = new Factory; } /** * @return array */ public static function getDefaultConfig() { return array( 'domain' => AF_INET , 'type' => SOCK_STREAM , 'protocol' => SOL_TCP , 'options' => array( SOL_SOCKET => array(SO_REUSEADDR => 1) ) ); } public function onOpen(Connection $conn) { $conn->WebSocket = new \stdClass; $conn->WebSocket->handshake = false; } public function onRecv(Connection $from, $msg) { if (true !== $from->WebSocket->handshake) { // need buffer checks in here $from->WebSocket->version = $this->getVersion($msg); $response = $from->WebSocket->version->handshake($msg); $from->WebSocket->handshake = true; if (is_array($response)) { $header = ''; foreach ($response as $key => $val) { if (!empty($key)) { $header .= "{$key}: "; } $header .= "{$val}\r\n"; } $header .= "\r\n"; } else { $header = $response; } $comp = $this->_factory->newComposite(); $comp->enqueue($this->_factory->newCommand('SendMessage', $from)->setMessage($header)); $comp->enqueue($this->prepareCommand($this->_app->onOpen($from, $msg))); // Need to send headers/handshake to application, let it have the cookies, etc return $comp; } // buffer! $msg = $from->WebSocket->version->unframe($msg); if (is_array($msg)) { // temporary $msg = $msg['payload']; } return $this->prepareCommand($this->_app->onRecv($from, $msg)); } public function onClose(Connection $conn) { return $this->prepareCommand($this->_app->onClose($conn)); } public function onError(Connection $conn, \Exception $e) { return $this->_app->onError($conn, $e); } /** * @param string */ public function setSubProtocol($name) { } /** * Checks if a return Command from your application is a message, if so encode it/them * @param Ratchet\Resource\Command\CommandInterface|NULL * @return Ratchet\Resource\Command\CommandInterface|NULL */ protected function prepareCommand(CommandInterface $command = null) { if ($command instanceof SendMessage) { $version = $command->getConnection()->WebSocket->version; return $command->setMessage($version->frame($command->getMessage())); } if ($command instanceof \Traversable) { foreach ($command as $cmd) { $cmd = $this->prepareCommand($cmd); } } return $command; } /** * @param array of HTTP headers * @return Version\VersionInterface */ protected function getVersion($message) { $headers = HTTP::getHeaders($message); if (isset($headers['Sec-Websocket-Version'])) { // HyBi if ($headers['Sec-Websocket-Version'] == '8') { return $this->versionFactory('HyBi10'); } } elseif (isset($headers['Sec-Websocket-Key2'])) { // Hixie return $this->versionFactory('Hixie76'); } throw new \UnexpectedValueException('Could not identify WebSocket protocol'); } /** * @return Version\VersionInterface */ protected function versionFactory($version) { if (null === $this->_versions[$version]) { $ns = __NAMESPACE__ . "\\Version\\{$version}"; $this->_version[$version] = new $ns; } return $this->_version[$version]; } }