Files
fast/vendor/workerman/phpsocket.io/src/Client.php
xiadc c6a4e1f5f6 init
- 框架初始化
 - 安装插件
 - 修复PHP8.4报错
2025-04-19 17:21:20 +08:00

251 lines
6.0 KiB
PHP

<?php
namespace PHPSocketIO;
use Exception;
use PHPSocketIO\Parser\Decoder;
use PHPSocketIO\Parser\Encoder;
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 = [];
public $connectBuffer = [];
/**
* @var array|mixed|null
*/
public $sockets;
public function __construct($server, $conn)
{
$this->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;
}
}