Command Refactoring
Refactored Command namespace; reusing more code, standardized interfaces WebSocket handles wrapping messages better/properly now
This commit is contained in:
parent
c45962c7b4
commit
1d14119bb5
@ -1,25 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Command\Action;
|
namespace Ratchet\Command\Action;
|
||||||
use Ratchet\Command\ActionInterface;
|
use Ratchet\Command\ActionTemplate;
|
||||||
use Ratchet\SocketInterface;
|
|
||||||
use Ratchet\SocketObserver;
|
use Ratchet\SocketObserver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the connection to the sockets passed in the constructor
|
* Close the connection to the sockets passed in the constructor
|
||||||
*/
|
*/
|
||||||
class CloseConnection implements ActionInterface {
|
class CloseConnection extends ActionTemplate {
|
||||||
/**
|
|
||||||
* @var SocketInterface
|
|
||||||
*/
|
|
||||||
protected $_socket;
|
|
||||||
|
|
||||||
public function __construct(SocketInterface $socket) {
|
|
||||||
$this->_socket = $socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
function execute(SocketObserver $scope = null) {
|
function execute(SocketObserver $scope = null) {
|
||||||
$ret = $scope->onClose($this->_socket);
|
$ret = $scope->onClose($this->getSocket());
|
||||||
$this->_socket->close();
|
$this->getSocket()->close();
|
||||||
|
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Command\Action;
|
namespace Ratchet\Command\Action;
|
||||||
use Ratchet\Command\ActionInterface;
|
use Ratchet\Command\ActionTemplate;
|
||||||
use Ratchet\SocketInterface;
|
|
||||||
use Ratchet\SocketObserver;
|
use Ratchet\SocketObserver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Null pattern - execution does nothing, something needs to be passed back though
|
* Null pattern - execution does nothing, something needs to be passed back though
|
||||||
*/
|
*/
|
||||||
class Null implements ActionInterface {
|
class Null extends ActionTemplate {
|
||||||
public function __construct(SocketInterface $socket) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(SocketObserver $scope = null) {
|
public function execute(SocketObserver $scope = null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,26 +1,16 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Command\Action;
|
namespace Ratchet\Command\Action;
|
||||||
use Ratchet\Command\ActionInterface;
|
use Ratchet\Command\ActionTemplate;
|
||||||
use Ratchet\SocketInterface;
|
|
||||||
use Ratchet\SocketObserver;
|
use Ratchet\SocketObserver;
|
||||||
|
|
||||||
class Runtime implements ActionInterface {
|
class Runtime extends ActionTemplate {
|
||||||
/**
|
|
||||||
* @var SocketInterface
|
|
||||||
*/
|
|
||||||
protected $_socket;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Closure
|
* @var Closure
|
||||||
*/
|
*/
|
||||||
protected $_command = null;
|
protected $_command = null;
|
||||||
|
|
||||||
public function __construct(SocketInterface $socket) {
|
|
||||||
$this->_socket = $socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Your closure should accept a single \Ratchet\Socket parameter
|
* Your closure should accept a single \Ratchet\SocketInterface parameter and return a CommandInterface or NULL
|
||||||
* @param Closure Your closure/lambda to execute when the time comes
|
* @param Closure Your closure/lambda to execute when the time comes
|
||||||
*/
|
*/
|
||||||
public function setCommand(\Closure $callback) {
|
public function setCommand(\Closure $callback) {
|
||||||
@ -28,6 +18,6 @@ class Runtime implements ActionInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function execute(SocketObserver $scope = null) {
|
public function execute(SocketObserver $scope = null) {
|
||||||
return call_user_func($this->_command, $socket);
|
return call_user_func($this->_command, $this->getSocket());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,27 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Ratchet\Command\Action;
|
namespace Ratchet\Command\Action;
|
||||||
use Ratchet\Command\ActionInterface;
|
use Ratchet\Command\ActionTemplate;
|
||||||
use Ratchet\SocketInterface;
|
|
||||||
use Ratchet\SocketObserver;
|
use Ratchet\SocketObserver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send text back to the client end of the socket(s)
|
* Send text back to the client end of the socket(s)
|
||||||
*/
|
*/
|
||||||
class SendMessage implements ActionInterface {
|
class SendMessage extends ActionTemplate {
|
||||||
/**
|
|
||||||
* @var SocketInterface
|
|
||||||
*/
|
|
||||||
public $_socket;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $_message = '';
|
protected $_message = '';
|
||||||
|
|
||||||
public function __construct(SocketInterface $socket) {
|
|
||||||
$this->_socket = $socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message to send to the socket(s)
|
* The message to send to the socket(s)
|
||||||
* @param string
|
* @param string
|
||||||
@ -48,6 +38,6 @@ class SendMessage implements ActionInterface {
|
|||||||
throw new \UnexpectedValueException("Message is empty");
|
throw new \UnexpectedValueException("Message is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_socket->write($this->_message, strlen($this->_message));
|
$this->getSocket()->write($this->_message, strlen($this->_message));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,4 +8,9 @@ interface ActionInterface extends CommandInterface {
|
|||||||
* @param Ratchet\SocketInterface
|
* @param Ratchet\SocketInterface
|
||||||
*/
|
*/
|
||||||
function __construct(SocketInterface $socket);
|
function __construct(SocketInterface $socket);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Ratchet\SocketInterface
|
||||||
|
*/
|
||||||
|
function getSocket();
|
||||||
}
|
}
|
18
lib/Ratchet/Command/ActionTemplate.php
Normal file
18
lib/Ratchet/Command/ActionTemplate.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
namespace Ratchet\Command;
|
||||||
|
use Ratchet\SocketInterface;
|
||||||
|
|
||||||
|
abstract class ActionTemplate implements ActionInterface {
|
||||||
|
/**
|
||||||
|
* @var Ratchet\SocketInterface
|
||||||
|
*/
|
||||||
|
protected $_socket;
|
||||||
|
|
||||||
|
public function __construct(SocketInterface $socket) {
|
||||||
|
$this->_socket = $socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSocket() {
|
||||||
|
return $this->_socket;
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,8 @@ use Ratchet\SocketObserver;
|
|||||||
interface CommandInterface {
|
interface CommandInterface {
|
||||||
/**
|
/**
|
||||||
* The Server class will call the execution
|
* The Server class will call the execution
|
||||||
|
* @param Ratchet\SocketObserver Scope to execute the command under
|
||||||
|
* @return CommandInterface|NULL
|
||||||
*/
|
*/
|
||||||
function execute(SocketObserver $scope = null);
|
function execute(SocketObserver $scope = null);
|
||||||
}
|
}
|
@ -3,8 +3,13 @@ namespace Ratchet\Command;
|
|||||||
use Ratchet\SocketObserver;
|
use Ratchet\SocketObserver;
|
||||||
|
|
||||||
class Composite extends \SplQueue implements CommandInterface {
|
class Composite extends \SplQueue implements CommandInterface {
|
||||||
public function enqueue(CommandInterface $command) {
|
/**
|
||||||
if ($command instanceof Composite) {
|
* Add another Command to the stack
|
||||||
|
* Unlike a true composite the enqueue flattens a composite parameter into leafs
|
||||||
|
* @param CommandInterface
|
||||||
|
*/
|
||||||
|
public function enqueue(CommandInterface $command = null) {
|
||||||
|
if ($command instanceof self) {
|
||||||
foreach ($command as $cmd) {
|
foreach ($command as $cmd) {
|
||||||
$this->enqueue($cmd);
|
$this->enqueue($cmd);
|
||||||
}
|
}
|
||||||
@ -12,8 +17,10 @@ class Composite extends \SplQueue implements CommandInterface {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null !== $command) {
|
||||||
parent::enqueue($command);
|
parent::enqueue($command);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function execute(SocketObserver $scope = null) {
|
public function execute(SocketObserver $scope = null) {
|
||||||
$this->setIteratorMode(static::IT_MODE_DELETE);
|
$this->setIteratorMode(static::IT_MODE_DELETE);
|
||||||
@ -21,11 +28,7 @@ class Composite extends \SplQueue implements CommandInterface {
|
|||||||
$recursive = new self;
|
$recursive = new self;
|
||||||
|
|
||||||
foreach ($this as $command) {
|
foreach ($this as $command) {
|
||||||
$ret = $command->execute($scope);
|
$recursive->enqueue($command->execute($scope));
|
||||||
|
|
||||||
if ($ret instanceof CommandInterface) {
|
|
||||||
$recursive->enqueue($ret);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($recursive) > 0) {
|
if (count($recursive) > 0) {
|
||||||
|
@ -4,9 +4,9 @@ use Ratchet\Protocol\WebSocket\Client;
|
|||||||
use Ratchet\Protocol\WebSocket\VersionInterface;
|
use Ratchet\Protocol\WebSocket\VersionInterface;
|
||||||
use Ratchet\SocketInterface;
|
use Ratchet\SocketInterface;
|
||||||
use Ratchet\SocketObserver;
|
use Ratchet\SocketObserver;
|
||||||
|
use Ratchet\Command\Factory;
|
||||||
use Ratchet\Command\CommandInterface;
|
use Ratchet\Command\CommandInterface;
|
||||||
use Ratchet\Command\Action\SendMessage;
|
use Ratchet\Command\Action\SendMessage;
|
||||||
use Ratchet\Command\Composite;
|
|
||||||
use Ratchet\Protocol\WebSocket\Util\HTTP;
|
use Ratchet\Protocol\WebSocket\Util\HTTP;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,8 +15,14 @@ use Ratchet\Protocol\WebSocket\Util\HTTP;
|
|||||||
* @link http://ca.php.net/manual/en/ref.http.php
|
* @link http://ca.php.net/manual/en/ref.http.php
|
||||||
* @todo Make sure this works both ways (client/server) as stack needs to exist on client for framing
|
* @todo Make sure this works both ways (client/server) as stack needs to exist on client for framing
|
||||||
* @todo Make sure all SendMessage Commands are framed, not just ones received from onRecv
|
* @todo Make sure all SendMessage Commands are framed, not just ones received from onRecv
|
||||||
|
* @todo Learn about closing the socket. A message has to be sent prior to closing - does the message get sent onClose event or CloseConnection command?
|
||||||
*/
|
*/
|
||||||
class WebSocket implements ProtocolInterface {
|
class WebSocket implements ProtocolInterface {
|
||||||
|
/**
|
||||||
|
* @var Ratchet\Command\Factory
|
||||||
|
*/
|
||||||
|
protected $_factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup for connected clients
|
* Lookup for connected clients
|
||||||
* @type SplObjectStorage
|
* @type SplObjectStorage
|
||||||
@ -40,6 +46,7 @@ class WebSocket implements ProtocolInterface {
|
|||||||
public function __construct(SocketObserver $application) {
|
public function __construct(SocketObserver $application) {
|
||||||
$this->_clients = new \SplObjectStorage;
|
$this->_clients = new \SplObjectStorage;
|
||||||
$this->_app = $application;
|
$this->_app = $application;
|
||||||
|
$this->_factory = new Factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,12 +90,8 @@ class WebSocket implements ProtocolInterface {
|
|||||||
$header = $response;
|
$header = $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
$cmds = new Composite;
|
// here, need to send headers/handshake to application, let it have the cookies, etc
|
||||||
$mess = new SendMessage($from);
|
return $this->_factory->newCommand('SendMessage', $from)->setMessage($header);
|
||||||
$mess->setMessage($header);
|
|
||||||
$cmds->enqueue($mess);
|
|
||||||
|
|
||||||
return $cmds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -97,26 +100,11 @@ class WebSocket implements ProtocolInterface {
|
|||||||
$msg = $msg['payload'];
|
$msg = $msg['payload'];
|
||||||
}
|
}
|
||||||
} catch (\UnexpectedValueException $e) {
|
} catch (\UnexpectedValueException $e) {
|
||||||
$cmd = new Composite;
|
return $this->_factory->newCommand('CloseConnection', $from);
|
||||||
$close = new \Ratchet\Command\Action\CloseConnection($from); // This is to change to Disconnect (proper protocol close)
|
|
||||||
$cmd->enqueue($close);
|
|
||||||
|
|
||||||
return $cmd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$cmds = $this->_app->onRecv($from, $msg);
|
$cmds = $this->_app->onRecv($from, $msg);
|
||||||
if ($cmds instanceof Composite) {
|
return $this->prepareCommand($cmds);
|
||||||
foreach ($cmds as $cmd) {
|
|
||||||
if ($cmd instanceof SendMessage) {
|
|
||||||
$sock = $cmd->_socket; // bad
|
|
||||||
$clnt = $this->_clients[$sock];
|
|
||||||
|
|
||||||
$cmd->setMessage($clnt->getVersion()->frame($cmd->getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $cmds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,16 +123,23 @@ class WebSocket implements ProtocolInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Ratchet\Command\CommandInterface
|
* Checks if a return Command from your application is a message, if so encode it/them
|
||||||
* @param Version\VersionInterface
|
* @param Ratchet\Command\CommandInterface|NULL
|
||||||
* @return \Ratchet\Command\CommandInterface
|
* @return Ratchet\Command\CommandInterface|NULL
|
||||||
*/
|
*/
|
||||||
protected function prepareCommand(CommandInterface $cmd, VersionInterface $version) {
|
protected function prepareCommand(CommandInterface $command = null) {
|
||||||
if ($cmd instanceof SendMessage) {
|
if ($command instanceof SendMessage) {
|
||||||
$cmd->setMessage($version->frame($cmd->getMessage()));
|
$version = $this->_clients[$command->getSocket()]->getVersion();
|
||||||
|
return $command->setMessage($version->frame($command->getMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $cmd;
|
if ($command instanceof \Traversable) {
|
||||||
|
foreach ($command as $cmd) {
|
||||||
|
$cmd = $this->prepareCommand($cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $command;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user