3 Commits
0.1.2 ... 0.1.3

6 changed files with 28 additions and 43 deletions

5
doc/ObjectUserdata.md Normal file
View File

@ -0,0 +1,5 @@
# Object UserData
There is no support for userdata on `WebSocketInterface`, `WebSocketConnection` or `ConnectionGroup`.
The rationale for this is that the connections can be easily managed using `SplObjectStorage` to link to a data object. Similarly, for groups, the names should be unique and can be used for lookups.

View File

@ -1,28 +0,0 @@
<?php
namespace NoccyLabs\React\WebSocket\Debug;
trait HexDumpTrait
{
private function hexdump($data): void
{
printf("_____ *%4d\n", strlen($data));
$rows = str_split($data, 16);
$offs = 0;
foreach ($rows as $row) {
$h = []; $a = [];
for ($n = 0; $n < 16; $n++) {
if ($n < strlen($row)) {
$h[] = sprintf("%02x%s", ord($row[$n]), ($n==7)?" ":" ");
$a[] = sprintf("%s%s", (ctype_print($row[$n])?$row[$n]:"."), ($n==7)?" ":"");
} else {
$h[] = (($n==7)?" ":" ");
$a[] = (($n==7)?" ":" ");
}
}
printf("%04x | %s | %s\n", 16 * $offs++, join("", $h), join("", $a));
}
}
}

View File

@ -18,6 +18,7 @@ class WebSocketConnection implements WebSocketInterface
{ {
use EventEmitterTrait; use EventEmitterTrait;
// TODO maybe move constants to WebSocketProtocol?
const OP_CONTINUATION = 0x0; const OP_CONTINUATION = 0x0;
const OP_FRAME_TEXT = 0x1; const OP_FRAME_TEXT = 0x1;
const OP_FRAME_BINARY = 0x2; const OP_FRAME_BINARY = 0x2;
@ -58,10 +59,7 @@ class WebSocketConnection implements WebSocketInterface
$this->groupManager = $groupManager; $this->groupManager = $groupManager;
$this->inStream->on('data', $this->onWebSocketData(...)); $this->inStream->on('data', $this->onWebSocketData(...));
$this->inStream->on('close', function () { $this->inStream->on('close', $this->close(...));
$this->close();
$this->emit('close', []);
});
} }
private function onWebSocketData($data) private function onWebSocketData($data)
@ -79,16 +77,16 @@ class WebSocketConnection implements WebSocketInterface
} else { } else {
$this->buffer .= $payload; $this->buffer .= $payload;
} }
// Break out to avoid processing partial messages
return;
} }
if ($final) { if ($this->bufferedOp !== null) {
$payload = $this->buffer . $payload; $payload = $this->buffer . $payload;
$this->buffer = null; $this->buffer = null;
if ($this->bufferedOp !== null) {
$opcode = $this->bufferedOp; $opcode = $this->bufferedOp;
$this->bufferedOp = null; $this->bufferedOp = null;
} }
}
switch ($opcode) { switch ($opcode) {
case self::OP_PING: case self::OP_PING:
@ -165,6 +163,11 @@ class WebSocketConnection implements WebSocketInterface
return $this->group; return $this->group;
} }
public function getServerRequest(): ServerRequestInterface
{
return $this->request;
}
public function getRemoteAddress() public function getRemoteAddress()
{ {
return $this->request->getServerParams()['REMOTE_ADDR']; return $this->request->getServerParams()['REMOTE_ADDR'];
@ -252,15 +255,14 @@ class WebSocketConnection implements WebSocketInterface
*/ */
public function close() public function close()
{ {
// TODO send close
$this->outStream->close(); $this->outStream->close();
$this->inStream->close(); $this->inStream->close();
// TODO emit close event
$this->emit('close', []);
} }
public function closeWithReason(string $reason, int $code=1000) public function closeWithReason(string $reason, int $code=1000)
{ {
// TODO send close
$payload = chr(($code >> 8) & 0xFF) . chr($code & 0xFF) . $reason; $payload = chr(($code >> 8) & 0xFF) . chr($code & 0xFF) . $reason;
$this->send(self::OP_CLOSE, $payload); $this->send(self::OP_CLOSE, $payload);
} }
@ -270,7 +272,7 @@ class WebSocketConnection implements WebSocketInterface
*/ */
public function end($data = null) public function end($data = null)
{ {
// TODO implement me
} }
} }

View File

@ -25,4 +25,6 @@ interface WebSocketInterface extends ConnectionInterface
public function closeWithReason(string $reason, int $code=1000); public function closeWithReason(string $reason, int $code=1000);
public function getServerRequest(): ServerRequestInterface;
} }

View File

@ -3,11 +3,14 @@
namespace NoccyLabs\React\WebSocket\Group; namespace NoccyLabs\React\WebSocket\Group;
use NoccyLabs\React\WebSocket\WebSocketConnection; use NoccyLabs\React\WebSocket\WebSocketConnection;
use NoccyLabs\React\WebSocket\WebSocketProtocol;
use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\CoversClass;
use React\Http\Message\ServerRequest; use React\Http\Message\ServerRequest;
use React\Stream\ThroughStream; use React\Stream\ThroughStream;
#[CoversClass(ConnectionGroup::class)] #[CoversClass(ConnectionGroup::class)]
#[CoversClass(WebSocketConnection::class)]
#[CoversClass(WebSocketProtocol::class)]
class ConnectionGroupTest extends \PHPUnit\Framework\TestCase class ConnectionGroupTest extends \PHPUnit\Framework\TestCase
{ {

View File

@ -6,6 +6,7 @@ use PHPUnit\Framework\Attributes\CoversClass;
use React\Http\Message\ServerRequest; use React\Http\Message\ServerRequest;
#[CoversClass(WebSocketMiddleware::class)] #[CoversClass(WebSocketMiddleware::class)]
#[CoversClass(WebSocketConnection::class)]
class WebSocketMiddlewareTest extends \PHPUnit\Framework\TestCase class WebSocketMiddlewareTest extends \PHPUnit\Framework\TestCase
{ {