null , 'Hixie76' => null ); public function __construct(SocketObserver $application) { $this->_clients = new \SplObjectStorage; $this->_app = $application; } /** * @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(SocketInterface $conn) { $this->_clients[$conn] = new Client; return $this->_app->onOpen($conn); } public function onRecv(SocketInterface $from, $msg) { $client = $this->_clients[$from]; if (true !== $client->isHandshakeComplete()) { $response = $client->setVersion($this->getVersion($msg))->doHandshake($msg); 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; } $cmds = new Composite; $mess = new SendMessage($from); $mess->setMessage($header); $cmds->enqueue($mess); return $cmds; } try { $msg = $client->getVersion()->unframe($msg); if (is_array($msg)) { // temporary $msg = $msg['payload']; } } catch (\UnexpectedValueException $e) { $cmd = new Composite; $close = new \Ratchet\Command\Close($from); $cmd->enqueue($close); return $cmd; } $cmds = $this->_app->onRecv($from, $msg); if ($cmds instanceof Composite) { foreach ($cmds as $cmd) { if ($cmd instanceof SendMessage) { $sock = $cmd->_socket; $clnt = $this->_clients[$sock]; $cmd->setMessage($clnt->getVersion()->frame($cmd->getMessage())); } } } return $cmds; } /** * @todo Wrap any SendMessage commands */ public function onClose(SocketInterface $conn) { $cmd = $this->_app->onClose($conn); unset($this->_clients[$conn]); return $cmd; } /** * @param string */ public function setSubProtocol($name) { } /** * @param \Ratchet\Command\CommandInterface * @param Version\VersionInterface * @return \Ratchet\Command\CommandInterface */ protected function prepareCommand(CommandInterface $cmd, VersionInterface $version) { if ($cmd instanceof SendMessage) { $cmd->setMessage($version->frame($cmd->getMessage())); } return $cmd; } /** * @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 = __CLASS__ . "\\Version\\{$version}"; $this->_version[$version] = new $ns; } return $this->_version[$version]; } }