Moved frame logic to WebSocketCodec
This commit is contained in:
@ -27,6 +27,8 @@ class WebSocketConnection implements WebSocketInterface
|
||||
|
||||
private ?string $groupName = null;
|
||||
|
||||
private WebSocketCodec $codec;
|
||||
|
||||
private ?ConnectionGroup $group = null;
|
||||
|
||||
private GroupManager $groupManager;
|
||||
@ -43,6 +45,9 @@ class WebSocketConnection implements WebSocketInterface
|
||||
|
||||
public function __construct(ServerRequestInterface $request, ReadableStreamInterface $inStream, WritableStreamInterface $outStream, GroupManager $groupManager)
|
||||
{
|
||||
// The codec is used to encode and decode frames
|
||||
$this->codec = new WebSocketCodec();
|
||||
|
||||
$this->request = $request;
|
||||
$this->inStream = $inStream;
|
||||
$this->outStream = $outStream;
|
||||
@ -54,42 +59,10 @@ class WebSocketConnection implements WebSocketInterface
|
||||
private function onWebSocketData($data)
|
||||
{
|
||||
|
||||
// Keep track of the number of bytes in the header
|
||||
$header = 2;
|
||||
|
||||
// Peek at the first byte, holding flags and opcode
|
||||
$byte0 = ord($data[0]);
|
||||
$final = !!($byte0 & 0x80);
|
||||
$opcode = $byte0 & 0x0F;
|
||||
// Peek at the second byte, holding mask bit and len
|
||||
$byte1 = ord($data[1]);
|
||||
$masked = !!($byte1 & 0x80);
|
||||
$len = $byte1 & 0x7F;
|
||||
|
||||
// Read extended length if present
|
||||
if ($len == 126) {
|
||||
$len = (ord($data[$header+0]) << 8)
|
||||
| (ord($data[$header+1]));
|
||||
$header += 2;
|
||||
} elseif ($len == 127) {
|
||||
$len = (ord($data[$header+0]) << 24)
|
||||
| (ord($data[$header+1]) << 16)
|
||||
| (ord($data[$header+2]) << 8)
|
||||
| (ord($data[$header+3]));
|
||||
$header += 4;
|
||||
}
|
||||
|
||||
// Now for the masking
|
||||
if ($masked) {
|
||||
$mask = substr($data, $header, 4);
|
||||
$header += 4;
|
||||
}
|
||||
|
||||
// Extract and unmask payload
|
||||
$payload = substr($data, $header, $len);
|
||||
if ($masked) {
|
||||
$payload = $this->unmask($payload, $mask);
|
||||
}
|
||||
$decoded = $this->codec->decode($data);
|
||||
$opcode = $decoded['opcode'];
|
||||
$final = $decoded['final'];
|
||||
$payload = $decoded['payload'];
|
||||
|
||||
if (!$final) {
|
||||
if ($this->bufferedOp === null) {
|
||||
@ -111,7 +84,12 @@ class WebSocketConnection implements WebSocketInterface
|
||||
|
||||
switch ($opcode) {
|
||||
case self::OP_PING:
|
||||
$this->sendPong();
|
||||
$this->sendPong($payload);
|
||||
return;
|
||||
case self::OP_PONG:
|
||||
return;
|
||||
case self::OP_CLOSE:
|
||||
// TODO implement
|
||||
return;
|
||||
case self::OP_CONTINUATION:
|
||||
$this->buffer .= $payload;
|
||||
@ -125,24 +103,9 @@ class WebSocketConnection implements WebSocketInterface
|
||||
}
|
||||
}
|
||||
|
||||
private function unmask(string $payload, string $mask): string
|
||||
private function sendPong(string $data): void
|
||||
{
|
||||
$payloadData = array_map("ord", str_split($payload,1));
|
||||
$maskData = array_map("ord", str_split($mask,1));
|
||||
|
||||
//printf("Mask: %02x %02x %02x %02x\n", ...$maskData);
|
||||
|
||||
$unmasked = [];
|
||||
for ($n = 0; $n < count($payloadData); $n++) {
|
||||
$unmasked[] = $payloadData[$n] ^ $maskData[$n % 4];
|
||||
//printf("%02x ^ %02x = %02x %s\n", $payloadData[$n], $maskData[$n%4], $payloadData[$n]^$maskData[$n%4], chr($payloadData[$n]^$maskData[$n%4]));
|
||||
}
|
||||
return join("", array_map("chr", $unmasked));
|
||||
}
|
||||
|
||||
private function sendPong(): void
|
||||
{
|
||||
|
||||
$this->send(self::OP_PONG, $data, true);
|
||||
}
|
||||
|
||||
public function setGroup(?string $name): void
|
||||
@ -221,17 +184,15 @@ class WebSocketConnection implements WebSocketInterface
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function send(int $opcode, string $data, bool $final = true)
|
||||
public function send(int $opcode, string $data, bool $final = true, bool $masked = false)
|
||||
{
|
||||
$frame = chr(($final?0x80:0x00) | ($opcode & 0xF));
|
||||
|
||||
$len = strlen($data);
|
||||
if ($len > 126) {
|
||||
$frame .= chr(0x7E) . chr(($len >> 8) & 0xFF) . chr($len & 0xFF);
|
||||
} else {
|
||||
$frame .= chr($len);
|
||||
}
|
||||
$frame .= $data;
|
||||
|
||||
$frame = $this->codec->encode([
|
||||
'opcode' => $opcode,
|
||||
'payload' => $data,
|
||||
'final' => $final,
|
||||
'masked' => $masked
|
||||
]);
|
||||
|
||||
$this->outStream->write($frame);
|
||||
|
||||
|
Reference in New Issue
Block a user