RU
apps/caramail-server / src / Net / TcpSession.php · commit 070afda
<?phpnamespace App\Net;use App\Chat\Frame;use App\Chat\Session;/** One TCP client: what it sent and is not a whole line yet, what waits to be written. */final class TcpSession implements Session{    public const MAX_OUTPUT = 1_048_576;    public string $buffer = '';    private string $output = '';    private bool $closed = false;    /** @param resource $stream */    public function __construct(public $stream, private readonly string $peer)    {    }    public function send(string $code, array $fields = []): void    {        if ($this->closed) {            return;        }        $this->output .= Frame::encode($code, $fields);        if (strlen($this->output) > self::MAX_OUTPUT) {            $this->close(); // a client that does not read any more            return;        }        $this->flush();    }    public function hasOutput(): bool    {        return $this->output !== '' && !$this->closed;    }    public function flush(): void    {        if ($this->closed || $this->output === '') {            return;        }        $written = @fwrite($this->stream, $this->output);        if ($written === false) {            $this->close();            return;        }        $this->output = (string)substr($this->output, $written);    }    public function close(): void    {        if ($this->closed) {            return;        }        $this->flush();        $this->closed = true;        if (is_resource($this->stream)) {            @fclose($this->stream);        }    }    public function isClosed(): bool    {        return $this->closed;    }    public function address(): string    {        return $this->peer;    }    public function ip(): string    {        return ClientIp::host($this->peer);    }}