[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 f0a277cec9
commit 8770c361bc
11 changed files with 133 additions and 139 deletions

28
Version/DataInterface.php Normal file
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 <?php
namespace Ratchet\WebSocket\Version; namespace Ratchet\WebSocket\Version;
interface FrameInterface { interface FrameInterface extends DataInterface {
/**
* @return bool
*/
function isCoalesced();
/** /**
* Add incoming data to the frame from peer
* @param string * @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); function addBuffer($buf);
/** /**
* @return bool * Is this the final frame in a fragmented message?
*/
// function isFragment();
/**
* @return bool * @return bool
*/ */
function isFinal(); function isFinal();
/** /**
* Was the payload masked?
* @return bool * @return bool
*/ */
function isMasked(); function isMasked();
@ -36,21 +28,11 @@ interface FrameInterface {
/** /**
* @return int * @return int
*/ */
function getPayloadLength(); //function getReceivedPayloadLength();
/**
* @return int
*/
// function getReceivedPayloadLength();
/** /**
* 32-big string * 32-big string
* @return string * @return string
*/ */
function getMaskingKey(); function getMaskingKey();
/**
* @param string
*/
function getPayload();
} }

View File

@ -1,7 +1,11 @@
<?php <?php
namespace Ratchet\WebSocket\Version; 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\RequestInterface;
use Guzzle\Http\Message\Response; 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! * 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)); return !(null === $request->getHeader('Sec-WebSocket-Key2', true));
} }
/**
* {@inheritdoc}
*/
public function getVersionNumber() { public function getVersionNumber() {
return 0; return 0;
} }
@ -46,25 +53,47 @@ class Hixie76 implements VersionInterface {
return $response; return $response;
} }
/**
* @return Hixie76\Message
*/
public function newMessage() {
return new Hixie76\Message;
}
/**
* @return Hixie76\Frame
*/
public function newFrame() {
return new Hixie76\Frame;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function frame($message, $mask = true) { public function upgradeConnection(ConnectionInterface $conn, MessageInterface $coalescedCallback) {
return chr(0) . $message . chr(255); $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) { 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); 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 <?php
namespace Ratchet\WebSocket\Version; namespace Ratchet\WebSocket\Version;
/** interface MessageInterface extends DataInterface {
* @todo Consider making parent interface/composite for Message/Frame with (isCoalesced, getOpcdoe, getPayloadLength, getPayload)
*/
interface MessageInterface {
/**
* @return bool
*/
function isCoalesced();
/** /**
* @param FragmentInterface * @param FragmentInterface
* @return MessageInterface * @return MessageInterface
@ -20,14 +12,4 @@ interface MessageInterface {
* @return int * @return int
*/ */
function getOpcode(); function getOpcode();
/**
* @return int
*/
function getPayloadLength();
/**
* @return string
*/
function getPayload();
} }

View File

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

View File

@ -13,13 +13,6 @@ class Message implements MessageInterface {
$this->_frames = new \SplDoublyLinkedList; $this->_frames = new \SplDoublyLinkedList;
} }
/**
* {@inheritdoc}
*/
public function __toString() {
return $this->getPayload();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -87,4 +80,21 @@ class Message implements MessageInterface {
return $buffer; 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 <?php
namespace Ratchet\WebSocket\Version; namespace Ratchet\WebSocket\Version;
use Ratchet\MessageInterface; use Ratchet\MessageInterface;
use Ratchet\ConnectionInterface;
use Guzzle\Http\Message\RequestInterface; use Guzzle\Http\Message\RequestInterface;
/** /**
@ -25,20 +26,26 @@ interface VersionInterface extends MessageInterface {
* Perform the handshake and return the response headers * Perform the handshake and return the response headers
* @param Guzzle\Http\Message\RequestInterface * @param Guzzle\Http\Message\RequestInterface
* @return Guzzle\Http\Message\Response * @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) * @throws UnderflowException If the message hasn't finished buffering (not yet implemented, theoretically will only happen with Hixie version)
*/ */
function handshake(RequestInterface $request); function handshake(RequestInterface $request);
/**
* @param Ratchet\ConnectionInterface
* @param Ratchet\MessageInterface
* @return Ratchet\ConnectionInterface
*/
function upgradeConnection(ConnectionInterface $conn, MessageInterface $coalescedCallback);
/** /**
* @return MessageInterface * @return MessageInterface
*/ */
function newMessage(); //function newMessage();
/** /**
* @return FrameInterface * @return FrameInterface
*/ */
function newFrame(); //function newFrame();
/** /**
* @param string * @param string

View File

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