65 lines
1.7 KiB
PHP
65 lines
1.7 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace NoccyLabs\React\Protocol\Line;
|
||
|
|
|
||
|
|
use Closure;
|
||
|
|
use NoccyLabs\React\Protocol\ProtocolInterface;
|
||
|
|
|
||
|
|
class LineProtocol implements ProtocolInterface
|
||
|
|
{
|
||
|
|
public function __construct(
|
||
|
|
private readonly string $lineBreak = "\n",
|
||
|
|
private readonly bool $quoteStrings = false,
|
||
|
|
private readonly bool $escapeSpecial = false,
|
||
|
|
private readonly ?Closure $beforePackCb = null,
|
||
|
|
private readonly ?Closure $afterPackCb = null,
|
||
|
|
private readonly ?Closure $beforeUnpackCb = null,
|
||
|
|
private readonly ?Closure $afterUnpackCb = null,
|
||
|
|
)
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
public function packFrame(array $frame): string
|
||
|
|
{
|
||
|
|
if (is_callable($this->beforePackCb))
|
||
|
|
$frame = call_user_func($this->beforePackCb, $frame);
|
||
|
|
|
||
|
|
if ($this->escapeSpecial) {
|
||
|
|
$frame = array_map(quotemeta(...), $frame);
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($this->quoteStrings) {
|
||
|
|
$frame = array_map(fn($v) => is_string($v) ? ('"'.str_replace('"',"\\\"",$v).'"') : $v, $frame);
|
||
|
|
}
|
||
|
|
|
||
|
|
$data = join(" ", $frame);
|
||
|
|
$data .= $this->lineBreak;
|
||
|
|
|
||
|
|
if (is_callable($this->afterPackCb))
|
||
|
|
$data = call_user_func($this->afterPackCb, $data);
|
||
|
|
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function unpackFrame(string $data): array
|
||
|
|
{
|
||
|
|
return str_getcsv($data, ' ', '"', "\\");
|
||
|
|
}
|
||
|
|
|
||
|
|
public function consumeFrame(string &$data): ?array
|
||
|
|
{
|
||
|
|
// check for $this->lineBreak
|
||
|
|
$p = strpos($data, $this->lineBreak);
|
||
|
|
if ($p === false) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
// break on separator
|
||
|
|
$frame = substr($data, 0, $p);
|
||
|
|
$data = substr($data, $p + strlen($this->lineBreak));
|
||
|
|
|
||
|
|
return $this->unpackFrame($frame);
|
||
|
|
}
|
||
|
|
}
|