Refactoring

Refactored Command/Composite pattern, now as expected
Server recursively executes commands
Above changes fixed issues of server/client not being notified on forced disconnects
This commit is contained in:
Chris Boden 2011-11-07 16:02:01 -05:00
parent 66e656ec63
commit d880d29729
12 changed files with 89 additions and 35 deletions

View File

@ -1,12 +1,14 @@
<?php
namespace Ratchet\Command\Action;
use Ratchet\Command\CommandInterface;
use Ratchet\Command\ActionInterface;
use Ratchet\SocketInterface;
use Ratchet\SocketObserver;
/**
* Close the connection to the sockets passed in the constructor
* @todo The server does not seem to be notified when a resource is closed by this class...
*/
class CloseConnection implements CommandInterface {
class CloseConnection implements ActionInterface {
/**
* @var SocketInterface
*/
@ -16,7 +18,10 @@ class CloseConnection implements CommandInterface {
$this->_socket = $socket;
}
function execute() {
function execute(SocketObserver $scope = null) {
$ret = $scope->onClose($this->_socket);
$this->_socket->close();
return $ret;
}
}

View File

@ -1,15 +1,16 @@
<?php
namespace Ratchet\Command\Action;
use Ratchet\Command\CommandInterface;
use Ratchet\Command\ActionInterface;
use Ratchet\SocketInterface;
use Ratchet\SocketObserver;
/**
* Null pattern - execution does nothing, something needs to be passed back though
*/
class Null implements CommandInterface {
class Null implements ActionInterface {
public function __construct(SocketInterface $socket) {
}
public function execute() {
public function execute(SocketObserver $scope = null) {
}
}

View File

@ -1,9 +1,10 @@
<?php
namespace Ratchet\Command\Action;
use Ratchet\Command\CommandInterface;
use Ratchet\Command\ActionInterface;
use Ratchet\SocketInterface;
use Ratchet\SocketObserver;
class Runtime implements CommandInterface {
class Runtime implements ActionInterface {
/**
* @var SocketInterface
*/
@ -26,7 +27,7 @@ class Runtime implements CommandInterface {
$this->_command = $callback;
}
public function execute() {
public function execute(SocketObserver $scope = null) {
return call_user_func($this->_command, $socket);
}
}

View File

@ -1,12 +1,13 @@
<?php
namespace Ratchet\Command\Action;
use Ratchet\Command\CommandInterface;
use Ratchet\Command\ActionInterface;
use Ratchet\SocketInterface;
use Ratchet\SocketObserver;
/**
* Send text back to the client end of the socket(s)
*/
class SendMessage implements CommandInterface {
class SendMessage implements ActionInterface {
/**
* @var SocketInterface
*/
@ -42,7 +43,7 @@ class SendMessage implements CommandInterface {
/**
* @throws \UnexpectedValueException if a message was not set with setMessage()
*/
public function execute() {
public function execute(SocketObserver $scope = null) {
if (empty($this->_message)) {
throw new \UnexpectedValueException("Message is empty");
}

View File

@ -0,0 +1,11 @@
<?php
namespace Ratchet\Command;
use Ratchet\SocketInterface;
interface ActionInterface extends CommandInterface {
/**
* Pass the Sockets to execute the command on
* @param Ratchet\SocketInterface
*/
function __construct(SocketInterface $socket);
}

View File

@ -1,20 +1,14 @@
<?php
namespace Ratchet\Command;
use Ratchet\SocketInterface;
use Ratchet\SocketObserver;
/**
* Socket implementation of the Command Pattern
* User created applications are to return a Command to the server for execution
*/
interface CommandInterface {
/**
* Pass the Sockets to execute the command on
* @param Ratchet\SocketInterface
*/
function __construct(SocketInterface $socket);
/**
* The Server class will call the execution
*/
function execute();
function execute(SocketObserver $scope = null);
}

View File

@ -1,17 +1,35 @@
<?php
namespace Ratchet\Command;
use Ratchet\SocketInterface;
use Ratchet\SocketObserver;
class Composite extends \SplQueue {
class Composite extends \SplQueue implements CommandInterface {
public function enqueue(CommandInterface $command) {
return parent::enqueue($command);
if ($command instanceof Composite) {
foreach ($command as $cmd) {
$this->enqueue($cmd);
}
public function execute() {
return;
}
parent::enqueue($command);
}
public function execute(SocketObserver $scope = null) {
$this->setIteratorMode(static::IT_MODE_DELETE);
$recursive = new self;
foreach ($this as $command) {
$command->execute();
$ret = $command->execute($scope);
if ($ret instanceof CommandInterface) {
$recursive->enqueue($ret);
}
}
if (count($recursive) > 0) {
return $recursive;
}
}
}

View File

@ -98,7 +98,7 @@ class WebSocket implements ProtocolInterface {
}
} catch (\UnexpectedValueException $e) {
$cmd = new Composite;
$close = new \Ratchet\Command\Close($from);
$close = new \Ratchet\Command\Action\CloseConnection($from); // This is to change to Disconnect (proper protocol close)
$cmd->enqueue($close);
return $cmd;

View File

@ -0,0 +1,20 @@
<?php
namespace Ratchet\Protocol\WebSocket\Command\Action;
use Ratchet\SocketInterface;
use Ratchet\Command\Action\SendMessage;
use Ratchet\SocketObserver;
class Disconnect extends SendMessage {
protected $_code = 1000;
public function setStatusCode($code) {
$this->_code = (int)$code;
// re-do message based on code
}
public function execute(SocketObserver $scope = null) {
parent::execute();
$this->_socket->close();
}
}

View File

@ -1,12 +1,13 @@
<?php
namespace Ratchet\Command;
use Ratchet\SocketInterface;
use Ratchet\Command\CommandInterface;
use Ratchet\Command\ActionInterface;
use Ratchet\SocketObserver;
class Ping implements CommandInterface {
class Ping implements ActionInterface {
public function __construct(SocketInterface $socket) {
}
public function execute() {
public function execute(SocketObserver $scope = null) {
}
}

View File

@ -1,12 +1,13 @@
<?php
namespace Ratchet\Command;
use Ratchet\SocketInterface;
use Ratchet\Command\CommandInterface;
use Ratchet\Command\ActionInterface;
use Ratchet\SocketObserver;
class Pong implements CommandInterface {
class Pong implements ActionInterface {
public function __construct(SocketInterface $socket) {
}
public function execute() {
public function execute(SocketObserver $scope = null) {
}
}

View File

@ -4,7 +4,7 @@ use Ratchet\Server\Aggregator;
use Ratchet\Protocol\ProtocolInterface;
use Ratchet\Logging\LoggerInterface;
use Ratchet\Logging\NullLogger;
use Ratchet\Command\Composite;
use Ratchet\Command\CommandInterface;
/**
* Creates an open-ended socket to listen on a port for incomming connections. Events are delegated through this to attached applications
@ -72,6 +72,7 @@ class Server implements SocketObserver, \IteratorAggregate {
* @throws Exception
* @todo Validate address. Use socket_get_option, if AF_INET must be IP, if AF_UNIX must be path
* @todo Should I make handling open/close/msg an application?
* @todo Consider making the 4kb listener changable
*/
public function run($address = '127.0.0.1', $port = 1025) {
set_time_limit(0);
@ -107,8 +108,8 @@ class Server implements SocketObserver, \IteratorAggregate {
}
}
if ($res instanceof Composite) {
$res->execute();
while ($res instanceof CommandInterface) {
$res = $res->execute($this);
}
}
} catch (Exception $se) {