server = $server; $this->conn = $conn; $this->encoder = new Encoder(); $this->decoder = new Decoder(); $this->id = $conn->id; $this->request = $conn->request; $this->setup(); Debug::debug('Client __construct'); } public function __destruct() { Debug::debug('Client __destruct'); } /** * Sets up event listeners. * * @api private */ public function setup() { $this->decoder->on('decoded', [$this, 'ondecoded']); $this->conn->on('data', [$this, 'ondata']); $this->conn->on('error', [$this, 'onerror']); $this->conn->on('close', [$this, 'onclose']); } /** * Connects a client to a namespace. * * @param {String} namespace name * @api private */ public function connect($name) { if (! isset($this->server->nsps[$name])) { $this->packet(['type' => Parser::ERROR, 'nsp' => $name, 'data' => 'Invalid namespace']); return; } $nsp = $this->server->of($name); if ('/' !== $name && ! isset($this->nsps['/'])) { $this->connectBuffer[$name] = $name; return; } $nsp->add($this, $nsp, [$this, 'nspAdd']); } public function nspAdd($socket, $nsp) { $this->sockets[$socket->id] = $socket; $this->nsps[$nsp->name] = $socket; if ('/' === $nsp->name && $this->connectBuffer) { foreach ($this->connectBuffer as $name) { $this->connect($name); } $this->connectBuffer = []; } } /** * Disconnects from all namespaces and closes transport. * * @api private */ public function disconnect() { foreach ($this->sockets as $socket) { $socket->disconnect(); } $this->sockets = []; $this->close(); } /** * Removes a socket. Called by each `Socket`. * * @api private */ public function remove($socket) { if (isset($this->sockets[$socket->id])) { $nsp = $this->sockets[$socket->id]->nsp->name; unset($this->sockets[$socket->id]); unset($this->nsps[$nsp]); } } /** * Closes the underlying connection. * * @api private */ public function close() { if (empty($this->conn)) { return; } if ('open' === $this->conn->readyState) { $this->conn->close(); $this->onclose('forced server close'); } } /** * Writes a packet to the transport. * * @param {Object} packet object * @param {Object} options * @api private */ public function packet($packet, $preEncoded = false, $volatile = false) { if (! empty($this->conn) && 'open' === $this->conn->readyState) { if (! $preEncoded) { // not broadcasting, need to encode $encodedPackets = $this->encoder->encode($packet); $this->writeToEngine($encodedPackets, $volatile); } else { // a broadcast pre-encodes a packet $this->writeToEngine($packet); } } } public function writeToEngine($encodedPackets, $volatile = false) { if ($volatile) { echo new Exception('volatile'); } if ($volatile && ! $this->conn->transport->writable) { return; } if (isset($encodedPackets['nsp'])) { unset($encodedPackets['nsp']); } foreach ($encodedPackets as $packet) { $this->conn->write($packet); } } /** * Called with incoming transport data. * * @api private */ public function ondata($data) { try { // todo chek '2["chat message","2"]' . "\0" . '' $this->decoder->add(trim($data)); } catch (Exception $e) { $this->onerror($e); } } /** * Called when parser fully decodes a packet. * * @api private */ public function ondecoded($packet) { if (Parser::CONNECT == $packet['type']) { $this->connect($packet['nsp']); } else { if (isset($this->nsps[$packet['nsp']])) { $this->nsps[$packet['nsp']]->onpacket($packet); } } } /** * Handles an error. * * @param {Objcet} error object * @api private */ public function onerror($err) { foreach ($this->sockets as $socket) { $socket->onerror($err); } $this->onclose('client error'); } /** * Called upon transport close. * * @param {String} reason * @api private */ public function onclose($reason) { if (empty($this->conn)) { return; } // ignore a potential subsequent `close` event $this->destroy(); // `nsps` and `sockets` are cleaned up seamlessly foreach ($this->sockets as $socket) { $socket->onclose($reason); } $this->sockets = null; } /** * Cleans up event listeners. * * @api private */ public function destroy() { if (! $this->conn) { return; } $this->conn->removeAllListeners(); $this->decoder->removeAllListeners(); $this->encoder->removeAllListeners(); $this->server = $this->conn = $this->encoder = $this->decoder = $this->request = $this->nsps = null; } }