123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- <?php
- namespace PHPSocketIO;
- use PHPSocketIO\Parser\Parser;
- class Client
- {
- public $server = null;
- public $conn = null;
- public $encoder = null;
- public $decoder = null;
- public $id = null;
- public $request = null;
- public $nsps = array();
- public $connectBuffer = array();
- public function __construct($server, $conn)
- {
- $this->server = $server;
- $this->conn = $conn;
- $this->encoder = new \PHPSocketIO\Parser\Encoder();
- $this->decoder = new \PHPSocketIO\Parser\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', array($this,'ondecoded'));
- $this->conn->on('data', array($this,'ondata'));
- $this->conn->on('error', array($this, 'onerror'));
- $this->conn->on('close' ,array($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(array('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, array($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 = array();
- }
- }
- /**
- * Disconnects from all namespaces and closes transport.
- *
- * @api private
- */
- public function disconnect()
- {
- foreach($this->sockets as $socket)
- {
- $socket->disconnect();
- }
- $this->sockets = array();
- $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]);
- } else {
- //echo('ignoring remove for '. $socket->id);
- }
- }
- /**
- * Closes the underlying connection.
- *
- * @api private
- */
- public function close()
- {
- if (empty($this->conn)) return;
- if('open' === $this->conn->readyState)
- {
- //echo('forcing transport close');
- $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);
- }
- } else {
- // todo check
- // echo('ignoring packet write ' . var_export($packet, true));
- }
- }
- public function writeToEngine($encodedPackets, $volatile = false)
- {
- if($volatile)echo new \Exception('volatile');
- if ($volatile && !$this->conn->transport->writable) return;
- // todo check
- 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);
- } else {
- //echo('no socket for namespace ' . $packet['nsp']);
- }
- }
- }
- /**
- * 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;
- }
- }
|