App -> Component Refactoring

Updating namespacing and conventions as per ticket #1
This commit is contained in:
Chris Boden 2012-01-31 08:37:51 -05:00
parent 451f7f4235
commit e1c7ce361f
23 changed files with 126 additions and 52 deletions

View File

@ -0,0 +1,14 @@
<?php
namespace Ratchet\Component;
use Ratchet\Resource\ConnectionInterface;
interface MessageComponentInterface extends ComponentInterface {
/**
* Triggered when a client sends data through the socket
* @param Ratchet\Resource\ConnectionInterface The socket/connection that sent the message to your application
* @param string The message received
* @return Ratchet\Resource\Command\CommandInterface|null
* @throws Exception
*/
function onMessage(ConnectionInterface $from, $msg);
}

View File

@ -1,6 +1,6 @@
<?php <?php
namespace Ratchet\Component\Server; namespace Ratchet\Component\Server;
use Ratchet\Component\ComponentInterface; use Ratchet\Component\MessageComponentInterface;
use Ratchet\SocketInterface; use Ratchet\SocketInterface;
use Ratchet\Resource\ConnectionInterface; use Ratchet\Resource\ConnectionInterface;
use Ratchet\Resource\Connection; use Ratchet\Resource\Connection;
@ -8,9 +8,8 @@ use Ratchet\Resource\Command\CommandInterface;
/** /**
* Creates an open-ended socket to listen on a port for incomming connections. Events are delegated through this to attached applications * Creates an open-ended socket to listen on a port for incomming connections. Events are delegated through this to attached applications
* @todo With all these options for the server I should probably use a DIC
*/ */
class App implements ComponentInterface { class App implements MessageComponentInterface {
/** /**
* @var array of Socket Resources * @var array of Socket Resources
*/ */
@ -25,7 +24,7 @@ class App implements ComponentInterface {
* The decorated application to send events to * The decorated application to send events to
* @var Ratchet\Component\ComponentInterface * @var Ratchet\Component\ComponentInterface
*/ */
protected $_app; protected $_decorating;
/** /**
* Number of bytes to read in the TCP buffer at a time * Number of bytes to read in the TCP buffer at a time
@ -42,8 +41,8 @@ class App implements ComponentInterface {
*/ */
protected $_run = true; protected $_run = true;
public function __construct(ComponentInterface $application) { public function __construct(MessageComponentInterface $component) {
$this->_app = $application; $this->_decorating = $component;
} }
/** /**
@ -68,8 +67,6 @@ class App implements ComponentInterface {
* @param mixed The address to listen for incoming connections on. "0.0.0.0" to listen from anywhere * @param mixed The address to listen for incoming connections on. "0.0.0.0" to listen from anywhere
* @param int The port to listen to connections on (make sure to run as root if < 1000) * @param int The port to listen to connections on (make sure to run as root if < 1000)
* @throws Ratchet\Exception * @throws Ratchet\Exception
* @todo Validate address. Use socket_get_option, if AF_INET must be IP, if AF_UNIX must be path
* @todo Consider making the 4kb listener changable
*/ */
public function run(SocketInterface $host, $address = '127.0.0.1', $port = 1025) { public function run(SocketInterface $host, $address = '127.0.0.1', $port = 1025) {
$this->_connections[$host->getResource()] = new Connection($host); $this->_connections[$host->getResource()] = new Connection($host);
@ -156,17 +153,17 @@ class App implements ComponentInterface {
$this->_resources[] = $new_connection->getSocket()->getResource(); $this->_resources[] = $new_connection->getSocket()->getResource();
$this->_connections[$new_connection->getSocket()->getResource()] = $new_connection; $this->_connections[$new_connection->getSocket()->getResource()] = $new_connection;
return $this->_app->onOpen($new_connection); return $this->_decorating->onOpen($new_connection);
} }
public function onMessage(ConnectionInterface $from, $msg) { public function onMessage(ConnectionInterface $from, $msg) {
return $this->_app->onMessage($from, $msg); return $this->_decorating->onMessage($from, $msg);
} }
public function onClose(ConnectionInterface $conn) { public function onClose(ConnectionInterface $conn) {
$resource = $conn->getSocket()->getResource(); $resource = $conn->getSocket()->getResource();
$cmd = $this->_app->onClose($conn); $cmd = $this->_decorating->onClose($conn);
unset($this->_connections[$resource], $this->_resources[array_search($resource, $this->_resources)]); unset($this->_connections[$resource], $this->_resources[array_search($resource, $this->_resources)]);
@ -174,6 +171,6 @@ class App implements ComponentInterface {
} }
public function onError(ConnectionInterface $conn, \Exception $e) { public function onError(ConnectionInterface $conn, \Exception $e) {
return $this->_app->onError($conn, $e); return $this->_decorating->onError($conn, $e);
} }
} }

View File

@ -25,7 +25,7 @@ use Ratchet\Component\WAMP\Command\Action\Prefix;
* @link http://www.tavendo.de/autobahn/protocol.html * @link http://www.tavendo.de/autobahn/protocol.html
* @link https://raw.github.com/oberstet/Autobahn/master/lib/javascript/autobahn.js * @link https://raw.github.com/oberstet/Autobahn/master/lib/javascript/autobahn.js
*/ */
class App implements WebSocketAppInterface { class WAMPComponent implements WebSocketAppInterface {
const MSG_WELCOME = 0; const MSG_WELCOME = 0;
const MSG_PREFIX = 1; const MSG_PREFIX = 1;
const MSG_CALL = 2; const MSG_CALL = 2;
@ -36,7 +36,7 @@ class App implements WebSocketAppInterface {
const MSG_PUBLISH = 7; const MSG_PUBLISH = 7;
const MSG_EVENT = 8; const MSG_EVENT = 8;
protected $_app; protected $_decorating;
/** /**
* Any server to client prefixes are stored here * Any server to client prefixes are stored here
@ -78,7 +78,7 @@ class App implements WebSocketAppInterface {
$wamp->addPrefix($conn, $curie, $uri, true); $wamp->addPrefix($conn, $curie, $uri, true);
}; };
return $this->_app->onOpen($conn); return $this->_decorating->onOpen($conn);
} }
/** /**
@ -105,19 +105,19 @@ class App implements WebSocketAppInterface {
$json = $json[0]; $json = $json[0];
} }
$ret = $this->_app->onCall($from, $callID, $procURI, $json); $ret = $this->_decorating->onCall($from, $callID, $procURI, $json);
break; break;
case static::MSG_SUBSCRIBE: case static::MSG_SUBSCRIBE:
$ret = $this->_app->onSubscribe($from, $this->getUri($from, $json[1])); $ret = $this->_decorating->onSubscribe($from, $this->getUri($from, $json[1]));
break; break;
case static::MSG_UNSUBSCRIBE: case static::MSG_UNSUBSCRIBE:
$ret = $this->_app->onUnSubscribe($from, $this->getUri($from, $json[1])); $ret = $this->_decorating->onUnSubscribe($from, $this->getUri($from, $json[1]));
break; break;
case static::MSG_PUBLISH: case static::MSG_PUBLISH:
$ret = $this->_app->onPublish($from, $this->getUri($from, $json[1]), $json[2]); $ret = $this->_decorating->onPublish($from, $this->getUri($from, $json[1]), $json[2]);
break; break;
default: default:
@ -152,16 +152,16 @@ class App implements WebSocketAppInterface {
return $stack; return $stack;
} }
public function __construct(ServerInterface $app) { public function __construct(WAMPServerComponentInterface $server_component) {
$this->_app = $app; $this->_decorating = $server_component;
$this->_msg_buffer = new Composite; $this->_msg_buffer = new Composite;
} }
public function onClose(ConnectionInterface $conn) { public function onClose(ConnectionInterface $conn) {
return $this->_app->onClose($conn); return $this->_decorating->onClose($conn);
} }
public function onError(ConnectionInterface $conn, \Exception $e) { public function onError(ConnectionInterface $conn, \Exception $e) {
return $this->_app->onError($conn, $e); return $this->_decorating->onError($conn, $e);
} }
} }

View File

@ -7,7 +7,7 @@ use Ratchet\Resource\ConnectionInterface;
* onMessage is replaced by various types of messages for this protocol (pub/sub or rpc) * onMessage is replaced by various types of messages for this protocol (pub/sub or rpc)
* @todo Thought: URI as class. Class has short and long version stored (if as prefix) * @todo Thought: URI as class. Class has short and long version stored (if as prefix)
*/ */
interface ServerInterface { interface WAMPServerComponentInterface {
/** /**
* When a new connection is opened it will be passed to this method * When a new connection is opened it will be passed to this method
* @param Ratchet\Resource\Connection * @param Ratchet\Resource\Connection

View File

@ -12,16 +12,14 @@ use Ratchet\Component\WebSocket\Guzzle\Http\Message\RequestFactory;
* The adapter to handle WebSocket requests/responses * The adapter to handle WebSocket requests/responses
* This is a mediator between the Server and your application to handle real-time messaging through a web browser * This is a mediator between the Server and your application to handle real-time messaging through a web browser
* @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 * @link http://dev.w3.org/html5/websockets/
* @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?
* @todo Consider chaning this class to a State Pattern. If a WS App interface is passed use different state for additional methods used
*/ */
class App implements ComponentInterface { class WebSocketComponent implements ComponentInterface {
/** /**
* Decorated application * Decorated component
* @var Ratchet\Component\ComponentInterface * @var Ratchet\Component\ComponentInterface
*/ */
protected $_app; protected $_decorating;
/** /**
* Creates commands/composites instead of calling several classes manually * Creates commands/composites instead of calling several classes manually
@ -42,16 +40,20 @@ class App implements ComponentInterface {
protected $_mask_payload = false; protected $_mask_payload = false;
/** /**
* For now, array_push accepted subprotocols to this array
* @deprecated * @deprecated
* @temporary * @temporary
*/ */
public $accepted_subprotocols = array(); public $accepted_subprotocols = array();
public function __construct(ComponentInterface $app) { public function __construct(ComponentInterface $component) {
$this->_app = $app; $this->_decorating = $component;
$this->_factory = new Factory; $this->_factory = new Factory;
} }
/**
* @{inheritdoc}
*/
public function onOpen(ConnectionInterface $conn) { public function onOpen(ConnectionInterface $conn) {
$conn->WebSocket = new \stdClass; $conn->WebSocket = new \stdClass;
$conn->WebSocket->handshake = false; $conn->WebSocket->handshake = false;
@ -60,8 +62,6 @@ class App implements ComponentInterface {
/** /**
* Do handshake, frame/unframe messages coming/going in stack * Do handshake, frame/unframe messages coming/going in stack
* @todo This needs some major refactoring
* @todo "Once the client's opening handshake has been sent, the client MUST wait for a response from the server before sending any further data."
*/ */
public function onMessage(ConnectionInterface $from, $msg) { public function onMessage(ConnectionInterface $from, $msg) {
if (true !== $from->WebSocket->handshake) { if (true !== $from->WebSocket->handshake) {
@ -107,7 +107,7 @@ class App implements ComponentInterface {
$comp = $this->_factory->newComposite(); $comp = $this->_factory->newComposite();
$comp->enqueue($this->_factory->newCommand('SendMessage', $from)->setMessage($header)); $comp->enqueue($this->_factory->newCommand('SendMessage', $from)->setMessage($header));
$comp->enqueue($this->prepareCommand($this->_app->onOpen($from, $msg))); // Need to send headers/handshake to application, let it have the cookies, etc $comp->enqueue($this->prepareCommand($this->_decorating->onOpen($from, $msg))); // Need to send headers/handshake to application, let it have the cookies, etc
return $comp; return $comp;
} }
@ -136,7 +136,7 @@ class App implements ComponentInterface {
} }
if ($from->WebSocket->message->isCoalesced()) { if ($from->WebSocket->message->isCoalesced()) {
$cmds = $this->prepareCommand($this->_app->onMessage($from, (string)$from->WebSocket->message)); $cmds = $this->prepareCommand($this->_decorating->onMessage($from, (string)$from->WebSocket->message));
unset($from->WebSocket->message); unset($from->WebSocket->message);
return $cmds; return $cmds;
@ -144,14 +144,14 @@ class App implements ComponentInterface {
} }
public function onClose(ConnectionInterface $conn) { public function onClose(ConnectionInterface $conn) {
return $this->prepareCommand($this->_app->onClose($conn)); return $this->prepareCommand($this->_decorating->onClose($conn));
} }
/** /**
* @todo Shouldn't I be using prepareCommand() on the return? look into this * @todo Shouldn't I be using prepareCommand() on the return? look into this
*/ */
public function onError(ConnectionInterface $conn, \Exception $e) { public function onError(ConnectionInterface $conn, \Exception $e) {
return $this->_app->onError($conn, $e); return $this->_decorating->onError($conn, $e);
} }
/** /**

View File

@ -7,7 +7,7 @@ use Ratchet\Component\ComponentInterface;
* @todo WebSocket checks if instanceof AppInterface, if so uses getSubProtocol() when doing handshake * @todo WebSocket checks if instanceof AppInterface, if so uses getSubProtocol() when doing handshake
* @todo Pick a better name for this... * @todo Pick a better name for this...
*/ */
interface WebSocketAppInterface extends ComponentInterface { interface WebSocketComponentInterface extends ComponentInterface {
/** /**
* Currently instead of this, I'm setting header in the Connection object passed around...not sure which I like more * Currently instead of this, I'm setting header in the Connection object passed around...not sure which I like more
* @param string * @param string

View File

@ -1,5 +1,5 @@
<?php <?php
namespace Ratchet\Resource\Command; namespace Ratchet\Resource\Command\Action;
use Ratchet\Resource\ConnectionInterface; use Ratchet\Resource\ConnectionInterface;
/** /**

View File

@ -1,5 +1,5 @@
<?php <?php
namespace Ratchet\Resource\Command; namespace Ratchet\Resource\Command\Action;
use Ratchet\Resource\ConnectionInterface; use Ratchet\Resource\ConnectionInterface;
abstract class ActionTemplate implements ActionInterface { abstract class ActionTemplate implements ActionInterface {

View File

@ -1,6 +1,5 @@
<?php <?php
namespace Ratchet\Resource\Command\Action; namespace Ratchet\Resource\Command\Action;
use Ratchet\Resource\Command\ActionTemplate;
use Ratchet\Component\ComponentInterface; use Ratchet\Component\ComponentInterface;
use Ratchet\Resource\ConnectionInterface; use Ratchet\Resource\ConnectionInterface;
use Ratchet\Resource\Command\CommandInterface; use Ratchet\Resource\Command\CommandInterface;

View File

@ -1,10 +1,9 @@
<?php <?php
namespace Ratchet\Resource\Command\Action; namespace Ratchet\Resource\Command\Action;
use Ratchet\Resource\Command\ActionTemplate;
use Ratchet\Component\ComponentInterface; use Ratchet\Component\ComponentInterface;
/** /**
* Null pattern - execution does nothing, something needs to be passed back though * Null pattern - execution does nothing, used when something needs to be passed back
*/ */
class Null extends ActionTemplate { class Null extends ActionTemplate {
public function execute(ComponentInterface $scope = null) { public function execute(ComponentInterface $scope = null) {

View File

@ -1,10 +1,13 @@
<?php <?php
namespace Ratchet\Resource\Command\Action; namespace Ratchet\Resource\Command\Action;
use Ratchet\Resource\Command\ActionTemplate;
use Ratchet\Component\ComponentInterface; use Ratchet\Component\ComponentInterface;
/**
* This allows you to create a run-time command by using a closure
*/
class Runtime extends ActionTemplate { class Runtime extends ActionTemplate {
/** /**
* The stored closure command to execude
* @var Closure * @var Closure
*/ */
protected $_command = null; protected $_command = null;
@ -17,7 +20,12 @@ class Runtime extends ActionTemplate {
$this->_command = $callback; $this->_command = $callback;
} }
/**
* @{inheritdoc}
*/
public function execute(ComponentInterface $scope = null) { public function execute(ComponentInterface $scope = null) {
return call_user_func($this->_command, $this->getConnection(), $scope); $cmd = $this->_command;
return $cmd($this->getConnection(), $scope);
} }
} }

View File

@ -1,6 +1,5 @@
<?php <?php
namespace Ratchet\Resource\Command\Action; namespace Ratchet\Resource\Command\Action;
use Ratchet\Resource\Command\ActionTemplate;
use Ratchet\Component\ComponentInterface; use Ratchet\Component\ComponentInterface;
/** /**
@ -31,6 +30,7 @@ class SendMessage extends ActionTemplate {
} }
/** /**
* @{inheritdoc}
* @throws \UnexpectedValueException if a message was not set with setMessage() * @throws \UnexpectedValueException if a message was not set with setMessage()
*/ */
public function execute(ComponentInterface $scope = null) { public function execute(ComponentInterface $scope = null) {

View File

@ -2,7 +2,7 @@
namespace Ratchet\Tests\Application\Server; namespace Ratchet\Tests\Application\Server;
use Ratchet\Component\Server\App as ServerApp; use Ratchet\Component\Server\App as ServerApp;
use Ratchet\Tests\Mock\FakeSocket as Socket; use Ratchet\Tests\Mock\FakeSocket as Socket;
use Ratchet\Tests\Mock\Application as TestApp; use Ratchet\Tests\Mock\Component as TestApp;
/** /**
* @covers Ratchet\Component\Server\App * @covers Ratchet\Component\Server\App
@ -17,7 +17,7 @@ class AppTest extends \PHPUnit_Framework_TestCase {
$this->_app = new TestApp; $this->_app = new TestApp;
$this->_server = new ServerApp($this->_app); $this->_server = new ServerApp($this->_app);
$ref = new \ReflectionClass('\Ratchet\Component\Server\App'); $ref = new \ReflectionClass('\\Ratchet\\Component\\Server\\App');
$prop = $ref->getProperty('_run'); $prop = $ref->getProperty('_run');
$prop->setAccessible(true); $prop->setAccessible(true);
$prop->setValue($this->_server, false); $prop->setValue($this->_server, false);

View File

@ -1,10 +1,10 @@
<?php <?php
namespace Ratchet\Tests\Mock; namespace Ratchet\Tests\Mock;
use Ratchet\Component\ComponentInterface; use Ratchet\Component\MessageComponentInterface;
use Ratchet\Tests\Mock\Socket as MockSocket; use Ratchet\Tests\Mock\Socket as MockSocket;
use Ratchet\Resource\ConnectionInterface; use Ratchet\Resource\ConnectionInterface;
class Application implements ComponentInterface { class Component implements MessageComponentInterface {
public $_app; public $_app;
public $_conn_open; public $_conn_open;

2
vendor/.composer/ClassLoader.php vendored Normal file
View File

@ -0,0 +1,2 @@
<?php
namespace Composer\Autoload; class ClassLoader { private $prefixes = array(); private $fallbackDirs = array(); public function getPrefixes() { return $this->prefixes; } public function getFallbackDirs() { return $this->fallbackDirs; } public function add($prefix, $paths) { if (!$prefix) { $this->fallbackDirs = (array) $paths; return; } if (isset($this->prefixes[$prefix])) { $this->prefixes[$prefix] = array_merge( $this->prefixes[$prefix], (array) $paths ); } else { $this->prefixes[$prefix] = (array) $paths; } } public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); } public function loadClass($class) { if ($file = $this->findFile($class)) { require $file; return true; } } public function findFile($class) { if ('\\' == $class[0]) { $class = substr($class, 1); } if (false !== $pos = strrpos($class, '\\')) { $classPath = DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos)); $className = substr($class, $pos + 1); } else { $classPath = null; $className = $class; } $classPath .= DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; foreach ($this->prefixes as $prefix => $dirs) { foreach ($dirs as $dir) { if (0 === strpos($class, $prefix)) { if (file_exists($dir . $classPath)) { return $dir . $classPath; } } } } foreach ($this->fallbackDirs as $dir) { if (file_exists($dir . $classPath)) { return $dir . $classPath; } } } }

22
vendor/.composer/autoload.php vendored Normal file
View File

@ -0,0 +1,22 @@
<?php
// autoload.php generated by Composer
if (!class_exists('Composer\\Autoload\\ClassLoader', false)) {
require __DIR__.'/ClassLoader.php';
}
$__composer_autoload_init = function() {
$loader = new \Composer\Autoload\ClassLoader();
$map = require __DIR__.'/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->add($namespace, $path);
}
$loader->register();
return $loader;
};
return $__composer_autoload_init();

View File

@ -0,0 +1,11 @@
<?php
// autoload_namespace.php generated by Composer
$vendorDir = dirname(__DIR__);
return array(
'Ratchet\\Tests' => dirname($vendorDir) . '/tests',
'Ratchet' => dirname($vendorDir) . '/lib',
'Guzzle' => $vendorDir . '/guzzle/src',
);

22
vendor/.composer/installed.json vendored Normal file
View File

@ -0,0 +1,22 @@
[
{
"name": "guzzle",
"version": "2.0.2",
"version_normalized": "2.0.2.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/guzzle\/guzzle.git",
"reference": "ac64abc2c05b921efc4623379c1674a282475ae5"
},
"type": "library",
"names": [
"guzzle"
],
"installation-source": "source",
"autoload": {
"psr-0": {
"Guzzle": "src"
}
}
}
]