[WebSocket] Hixie refactoring

Created parent interface for messages and frames
Created Hixie Connection
Applied updated interfaces to Hixie versions
Removed __toString on msgs/frames since there could be 2-3 types returned
This commit is contained in:
Chris Boden 2012-06-14 15:07:52 -04:00
parent 439ac1234f
commit 49d68ba7df
14 changed files with 135 additions and 148 deletions

View File

@ -0,0 +1,28 @@
<?php
namespace Ratchet\WebSocket\Version;
interface DataInterface {
/**
* Determine if the message is complete or still fragmented
* @return bool
*/
function isCoalesced();
/**
* Get the number of bytes the payload is set to be
* @return int
*/
function getPayloadLength();
/**
* Get the payload (message) sent from peer
* @return string
*/
function getPayload();
/**
* Get raw contents of the message
* @return string
*/
function getContents();
}

View File

@ -1,29 +1,21 @@
<?php
namespace Ratchet\WebSocket\Version;
interface FrameInterface {
/**
* @return bool
*/
function isCoalesced();
interface FrameInterface extends DataInterface {
/**
* Add incoming data to the frame from peer
* @param string
* @todo Theoretically, there won't be a buffer overflow (end of frame + start of new frame) - but test later, return a string with overflow here
*/
function addBuffer($buf);
/**
* @return bool
*/
// function isFragment();
/**
* Is this the final frame in a fragmented message?
* @return bool
*/
function isFinal();
/**
* Was the payload masked?
* @return bool
*/
function isMasked();
@ -36,21 +28,11 @@ interface FrameInterface {
/**
* @return int
*/
function getPayloadLength();
/**
* @return int
*/
// function getReceivedPayloadLength();
//function getReceivedPayloadLength();
/**
* 32-big string
* @return string
*/
function getMaskingKey();
/**
* @param string
*/
function getPayload();
}

View File

@ -1,7 +1,11 @@
<?php
namespace Ratchet\WebSocket\Version;
use Ratchet\ConnectionInterface;
use Ratchet\MessageInterface;
use Ratchet\WebSocket\Version\Hixie76\Connection;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\Response;
use Ratchet\WebSocket\Version\Hixie76\Frame;
/**
* FOR THE LOVE OF BEER, PLEASE PLEASE PLEASE DON'T allow the use of this in your application!
@ -22,6 +26,9 @@ class Hixie76 implements VersionInterface {
return !(null === $request->getHeader('Sec-WebSocket-Key2', true));
}
/**
* {@inheritdoc}
*/
public function getVersionNumber() {
return 0;
}
@ -46,25 +53,47 @@ class Hixie76 implements VersionInterface {
return $response;
}
/**
* @return Hixie76\Message
*/
public function newMessage() {
return new Hixie76\Message;
}
/**
* @return Hixie76\Frame
*/
public function newFrame() {
return new Hixie76\Frame;
}
/**
* {@inheritdoc}
*/
public function frame($message, $mask = true) {
return chr(0) . $message . chr(255);
public function upgradeConnection(ConnectionInterface $conn, MessageInterface $coalescedCallback) {
$upgraded = new Connection($conn);
if (!isset($upgraded->WebSocket)) {
$upgraded->WebSocket = new \StdClass;
}
$upgraded->WebSocket->coalescedCallback = $coalescedCallback;
return $upgraded;
}
public function onMessage(ConnectionInterface $from, $data) {
$overflow = '';
if (!isset($from->WebSocket->frame)) {
$from->WebSocket->frame = $this->newFrame();
}
$from->WebSocket->frame->addBuffer($data);
if ($from->WebSocket->frame->isCoalesced()) {
$overflow = $from->WebSocket->frame->extractOverflow();
$parsed = $from->WebSocket->frame->getPayload();
unset($from->WebSocket->frame);
$from->WebSocket->coalescedCallback->onMessage($from, $parsed);
unset($from->WebSocket->frame);
}
if (strlen($overflow) > 0) {
$this->onMessage($from, $overflow);
}
}
public function newFrame() {
return new Frame;
}
public function generateKeyNumber($key) {

View File

@ -0,0 +1,16 @@
<?php
namespace Ratchet\WebSocket\Version\Hixie76;
use Ratchet\AbstractConnectionDecorator;
/**
* {@inheritdoc}
*/
class Connection extends AbstractConnectionDecorator {
public function send($msg) {
return $this->getConnection()->send(chr(0) . $msg . chr(255));
}
public function close() {
return $this->getConnection()->close();
}
}

View File

@ -75,4 +75,12 @@ class Frame implements FrameInterface {
return substr($this->_data, 1, strlen($this->_data) - 2);
}
public function getContents() {
return $this->_data;
}
public function extractOverflow() {
return '';
}
}

View File

@ -1,68 +0,0 @@
<?php
namespace Ratchet\WebSocket\Version\Hixie76;
use Ratchet\WebSocket\Version\MessageInterface;
use Ratchet\WebSocket\Version\FrameInterface;
class Message implements MessageInterface {
/**
* @var Ratchet\WebSocket\Version\FrameInterface
*/
protected $_frame = null;
/**
* {@inheritdoc}
*/
public function __toString() {
return $this->getPayload();
}
/**
* {@inheritdoc}
*/
public function isCoalesced() {
if (!($this->_frame instanceof FrameInterface)) {
return false;
}
return $this->_frame->isCoalesced();
}
/**
* {@inheritdoc}
*/
public function addFrame(FrameInterface $fragment) {
if (null !== $this->_frame) {
throw new \OverflowException('Hixie76 does not support multiple framing of messages');
}
$this->_frame = $fragment;
return $this;
}
/**
* {@inheritdoc}
*/
public function getOpcode() {
// Hixie76 only supported text messages
return 1;
}
/**
* {@inheritdoc}
*/
public function getPayloadLength() {
throw new \DomainException('Please sir, may I have some code? (' . __FUNCTION__ . ')');
}
/**
* {@inheritdoc}
*/
public function getPayload() {
if (!$this->isCoalesced()) {
throw new \UnderflowException('Message has not been fully buffered yet');
}
return $this->_frame->getPayload();
}
}

View File

@ -1,15 +1,7 @@
<?php
namespace Ratchet\WebSocket\Version;
/**
* @todo Consider making parent interface/composite for Message/Frame with (isCoalesced, getOpcdoe, getPayloadLength, getPayload)
*/
interface MessageInterface {
/**
* @return bool
*/
function isCoalesced();
interface MessageInterface extends DataInterface {
/**
* @param FragmentInterface
* @return MessageInterface
@ -20,14 +12,4 @@ interface MessageInterface {
* @return int
*/
function getOpcode();
/**
* @return int
*/
function getPayloadLength();
/**
* @return string
*/
function getPayload();
}

View File

@ -2,14 +2,14 @@
namespace Ratchet\WebSocket\Version\RFC6455;
use Ratchet\ConnectionInterface;
use Ratchet\AbstractConnectionDecorator;
use Ratchet\WebSocket\Version\FrameInterface;
use Ratchet\WebSocket\Version\DataInterface;
/**
* {@inheritdoc}
*/
class Connection extends AbstractConnectionDecorator {
public function send($msg) {
if (!($msg instanceof FrameInterface)) {
if (!($msg instanceof DataInterface)) {
$msg = new Frame($msg);
}

View File

@ -13,13 +13,6 @@ class Message implements MessageInterface {
$this->_frames = new \SplDoublyLinkedList;
}
/**
* {@inheritdoc}
*/
public function __toString() {
return $this->getPayload();
}
/**
* {@inheritdoc}
*/
@ -87,4 +80,21 @@ class Message implements MessageInterface {
return $buffer;
}
/**
* {@inheritdoc}
*/
public function getContents() {
if (!$this->isCoalesced()) {
throw new \UnderflowException("Message has not been put back together yet");
}
$buffer = '';
foreach ($this->_frames as $frame) {
$buffer .= $frame->getContents();
}
return $buffer;
}
}

View File

@ -1,6 +1,7 @@
<?php
namespace Ratchet\WebSocket\Version;
use Ratchet\MessageInterface;
use Ratchet\ConnectionInterface;
use Guzzle\Http\Message\RequestInterface;
/**
@ -25,20 +26,26 @@ interface VersionInterface extends MessageInterface {
* Perform the handshake and return the response headers
* @param Guzzle\Http\Message\RequestInterface
* @return Guzzle\Http\Message\Response
* @throws InvalidArgumentException If the HTTP handshake is mal-formed
* @throws UnderflowException If the message hasn't finished buffering (not yet implemented, theoretically will only happen with Hixie version)
*/
function handshake(RequestInterface $request);
/**
* @param Ratchet\ConnectionInterface
* @param Ratchet\MessageInterface
* @return Ratchet\ConnectionInterface
*/
function upgradeConnection(ConnectionInterface $conn, MessageInterface $coalescedCallback);
/**
* @return MessageInterface
*/
function newMessage();
//function newMessage();
/**
* @return FrameInterface
*/
function newFrame();
//function newFrame();
/**
* @param string

View File

@ -61,7 +61,7 @@ class WsServer implements MessageComponentInterface {
$this->versioner
->enableVersion(new Version\RFC6455($component))
->enableVersion(new Version\HyBi10($component))
//->enableVersion(new Version\Hixie76)
->enableVersion(new Version\Hixie76)
;
$this->_decorating = $component;

View File

@ -57,7 +57,7 @@ class HyBi10Test extends \PHPUnit_Framework_TestCase {
public function testUnframeMatchesPreFraming() {
$string = 'Hello World!';
$framed = $this->_version->frame($string);
$framed = $this->_version->newFrame($string)->getContents();
$frame = new Frame;
$frame->addBuffer($framed);

View File

@ -60,11 +60,4 @@ class MessageTest extends \PHPUnit_Framework_TestCase {
$this->assertEquals(28, $this->message->getPayloadLength());
}
public function testToString() {
$msg = 'Who likes short shorts?';
$this->message->addFrame(Frame::create($msg));
$this->assertEquals($msg, (string)$this->message);
}
}

View File

@ -50,7 +50,7 @@ class RFC6455Test extends \PHPUnit_Framework_TestCase {
public function testUnframeMatchesPreFraming() {
$string = 'Hello World!';
$framed = $this->version->frame($string);
$framed = $this->version->newFrame($string)->getContents();
$frame = new Frame;
$frame->addBuffer($framed);