From 8ab79d217faaeb10ea6199d467e2adaf81eca1a4 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Fri, 4 May 2012 18:17:23 -0400 Subject: [PATCH 01/22] Guzzle update Updated Guzzle to 2.4.1 Fixed code to pass unit tests from update --- composer.json | 2 +- composer.lock | 16 +++++++++++++--- .../Version/RFC6455/HandshakeVerifier.php | 10 ++++------ .../Component/WebSocket/Version/RFC6455Test.php | 2 +- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 40a7dba..3273137 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ } , "require": { "php": ">=5.3.2" - , "guzzle/guzzle": "v2.0.2" + , "guzzle/guzzle": "2.4.*" , "symfony/http-foundation": "2.1.*" } } \ No newline at end of file diff --git a/composer.lock b/composer.lock index 496e1fb..8acd009 100644 --- a/composer.lock +++ b/composer.lock @@ -1,14 +1,24 @@ { - "hash": "c4bc28d46c32e18713efab25a77428e6", + "hash": "8cea9930a3f96f47c598f35e2ea96a85", "packages": [ { "package": "doctrine/common", "version": "2.2.x-dev", "source-reference": "1e0aa60d109c630d19543d999f12e2852ef8f932" }, + { + "package": "evenement/evenement", + "version": "dev-master", + "source-reference": "808e3aaea8d4f908e455b0e047cc1acc46b38d44" + }, { "package": "guzzle/guzzle", - "version": "v2.0.2" + "version": "v2.4.1" + }, + { + "package": "igorw/socket-server", + "version": "dev-master", + "source-reference": "e813968da434ed45219718bc2db29a01174045b6" }, { "package": "symfony/event-dispatcher", @@ -24,7 +34,7 @@ { "package": "symfony/validator", "version": "dev-master", - "source-reference": "704f655d060b14475d7bd2a0b6d653c70f88218a" + "source-reference": "dac248b43b62d30023dd9b73ad7e5b7bc1128e5e" } ], "packages-dev": null, diff --git a/src/Ratchet/Component/WebSocket/Version/RFC6455/HandshakeVerifier.php b/src/Ratchet/Component/WebSocket/Version/RFC6455/HandshakeVerifier.php index fd342a3..3c634e6 100644 --- a/src/Ratchet/Component/WebSocket/Version/RFC6455/HandshakeVerifier.php +++ b/src/Ratchet/Component/WebSocket/Version/RFC6455/HandshakeVerifier.php @@ -14,17 +14,15 @@ class HandshakeVerifier { * @return bool TRUE if all headers are valid, FALSE if 1 or more were invalid */ public function verifyAll(RequestInterface $request) { - $headers = $request->getHeaders(); - $passes = 0; $passes += (int)$this->verifyMethod($request->getMethod()); $passes += (int)$this->verifyHTTPVersion($request->getProtocolVersion()); $passes += (int)$this->verifyRequestURI($request->getPath()); - $passes += (int)$this->verifyHost($headers['Host']); - $passes += (int)$this->verifyUpgradeRequest($headers['Upgrade']); - $passes += (int)$this->verifyConnection($headers['Connection']); - $passes += (int)$this->verifyKey($headers['Sec-WebSocket-Key']); + $passes += (int)$this->verifyHost($request->getHeader('Host', true)); + $passes += (int)$this->verifyUpgradeRequest($request->getHeader('Upgrade', true)); + $passes += (int)$this->verifyConnection($request->getHeader('Connection', true)); + $passes += (int)$this->verifyKey($request->getHeader('Sec-WebSocket-Key', true)); //$passes += (int)$this->verifyVersion($headers['Sec-WebSocket-Version']); // Temporarily breaking functionality return (7 === $passes); diff --git a/tests/Ratchet/Tests/Component/WebSocket/Version/RFC6455Test.php b/tests/Ratchet/Tests/Component/WebSocket/Version/RFC6455Test.php index 68d468b..3b22481 100644 --- a/tests/Ratchet/Tests/Component/WebSocket/Version/RFC6455Test.php +++ b/tests/Ratchet/Tests/Component/WebSocket/Version/RFC6455Test.php @@ -116,7 +116,7 @@ class RFC6455Test extends \PHPUnit_Framework_TestCase { * @dataProvider headerHandshakeProvider */ public function testVariousHeadersToCheckHandshakeTolerance($pass, $header) { - $request = RequestFactory::fromMessage($header); + $request = RequestFactory::getInstance()->fromMessage($header); if ($pass) { $this->assertInstanceOf('\\Guzzle\\Http\\Message\\Response', $this->_version->handshake($request)); From 8404f911a345338167c03c47b7c09961d625f29a Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Fri, 4 May 2012 21:00:55 -0400 Subject: [PATCH 02/22] Fixes from Guzzle update Updated RequestFactory to match updated Guzzle RequestFactory API --- composer.lock | 10 ----- .../Guzzle/Http/Message/RequestFactory.php | 38 ++++--------------- .../WebSocket/WebSocketComponent.php | 2 +- 3 files changed, 8 insertions(+), 42 deletions(-) diff --git a/composer.lock b/composer.lock index 8acd009..8b37a34 100644 --- a/composer.lock +++ b/composer.lock @@ -6,20 +6,10 @@ "version": "2.2.x-dev", "source-reference": "1e0aa60d109c630d19543d999f12e2852ef8f932" }, - { - "package": "evenement/evenement", - "version": "dev-master", - "source-reference": "808e3aaea8d4f908e455b0e047cc1acc46b38d44" - }, { "package": "guzzle/guzzle", "version": "v2.4.1" }, - { - "package": "igorw/socket-server", - "version": "dev-master", - "source-reference": "e813968da434ed45219718bc2db29a01174045b6" - }, { "package": "symfony/event-dispatcher", "version": "dev-master", diff --git a/src/Ratchet/Component/WebSocket/Guzzle/Http/Message/RequestFactory.php b/src/Ratchet/Component/WebSocket/Guzzle/Http/Message/RequestFactory.php index 2bc0ab2..fcecde8 100644 --- a/src/Ratchet/Component/WebSocket/Guzzle/Http/Message/RequestFactory.php +++ b/src/Ratchet/Component/WebSocket/Guzzle/Http/Message/RequestFactory.php @@ -4,40 +4,16 @@ use Guzzle\Http\Message\RequestFactory as gReqFac; use Guzzle\Http\Url; /** - * Just slighly changing the Guzzle fromMessage() method to always return an EntityEnclosingRequest instance instead of Request + * Just slighly changing the Guzzle RequestFactory to always return an EntityEnclosingRequest instance instead of Request */ class RequestFactory extends gReqFac { - /** - * @param string - * @return Guzzle\Http\Message\RequestInterface - */ - public static function fromRequest($message) { - $parsed = static::parseMessage($message); - - if (!$parsed) { - return false; + public static function getInstance() { + static $instance = null; + if (null === $instance) { + $instance = parent::getInstance(); + static::$instance->requestClass = static::$instance->entityEnclosingRequestClass; } - return self::fromRequestParts( - $parsed['method'], - $parsed['parts'], - $parsed['headers'], - $parsed['body'], - $parsed['protocol'], - $parsed['protocol_version'] - ); - } - - protected static function fromRequestParts($method, array $parts, $headers = null, $body = null, $protocol = 'HTTP', $protocolVersion = '1.1') { - return self::requestCreate($method, Url::buildUrl($parts, true), $headers, $body) - ->setProtocolVersion($protocolVersion); - } - - protected static function requestCreate($method, $url, $headers = null, $body = null) { - $c = static::$entityEnclosingRequestClass; - $request = new $c($method, $url, $headers); - $request->setBody($body); - - return $request; + return $instance; } } \ No newline at end of file diff --git a/src/Ratchet/Component/WebSocket/WebSocketComponent.php b/src/Ratchet/Component/WebSocket/WebSocketComponent.php index c85b28a..24b4b7c 100644 --- a/src/Ratchet/Component/WebSocket/WebSocketComponent.php +++ b/src/Ratchet/Component/WebSocket/WebSocketComponent.php @@ -72,7 +72,7 @@ class WebSocketComponent implements MessageComponentInterface { return; } - $headers = RequestFactory::fromRequest($from->WebSocket->headers); + $headers = RequestFactory::getInstance()->fromMessage($from->WebSocket->headers); $from->WebSocket->version = $this->getVersion($headers); $from->WebSocket->headers = $headers; } From dbc40b821d1a2d8aef997041da53ce13b52a736e Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sun, 6 May 2012 13:18:21 -0400 Subject: [PATCH 03/22] ConnectionInterface updates Added write/end methods to Connections Created decorator class implementing ConnectionInterface --- .../Resource/AbstractConnectionDecorator.php | 43 +++++++ src/Ratchet/Resource/Connection.php | 20 ++++ src/Ratchet/Resource/ConnectionInterface.php | 10 ++ src/Ratchet/Resource/Socket/BSDSocket.php | 2 +- tests/Ratchet/Tests/Mock/Connection.php | 13 +++ .../Tests/Mock/ConnectionDecorator.php | 22 ++++ .../AbstractConnectionDecoratorTest.php | 109 ++++++++++++++++++ 7 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 src/Ratchet/Resource/AbstractConnectionDecorator.php create mode 100644 tests/Ratchet/Tests/Mock/ConnectionDecorator.php create mode 100644 tests/Ratchet/Tests/Resource/AbstractConnectionDecoratorTest.php diff --git a/src/Ratchet/Resource/AbstractConnectionDecorator.php b/src/Ratchet/Resource/AbstractConnectionDecorator.php new file mode 100644 index 0000000..3ae5472 --- /dev/null +++ b/src/Ratchet/Resource/AbstractConnectionDecorator.php @@ -0,0 +1,43 @@ +wrappedConn = $conn; + } + + /** + * @return ConnectionInterface + */ + protected function getConnection() { + return $this->wrappedConn; + } + + public function __set($name, $value) { + $this->wrappedConn->$name = $value; + } + + /** + * @todo trigger_error() instead - Have it the same as if called from a POPO + */ + public function __get($name) { + if (!$this->__isset($name)) { + throw new \InvalidArgumentException("Attribute '{$name}' not found in Connection {$this->getID()}"); + } + + return $this->wrappedConn->$name; + } + + public function __isset($name) { + return isset($this->wrappedConn->$name); + } + + public function __unset($name) { + unset($this->wrappedConn->$name); + } +} \ No newline at end of file diff --git a/src/Ratchet/Resource/Connection.php b/src/Ratchet/Resource/Connection.php index 4f1485c..def516b 100644 --- a/src/Ratchet/Resource/Connection.php +++ b/src/Ratchet/Resource/Connection.php @@ -1,6 +1,7 @@ _socket = $socket; } + /** + * {@inheritdoc} + */ + public function write($data) { + return $this->_socket->deliver($data); + } + + /** + * {@inheritdoc} + */ + public function end() { + try { + $this->_socket->shutdown(); + } catch (BSDSocketException $e) { + } + + $this->_socket->close(); + } + /** * This is here because I couldn't figure out a better/easier way to tie a connection and socket together for the server and commands * Anyway, if you're here, it's not recommended you use this/directly interact with the socket in your App... diff --git a/src/Ratchet/Resource/ConnectionInterface.php b/src/Ratchet/Resource/ConnectionInterface.php index e754de8..f53df88 100644 --- a/src/Ratchet/Resource/ConnectionInterface.php +++ b/src/Ratchet/Resource/ConnectionInterface.php @@ -4,4 +4,14 @@ namespace Ratchet\Resource; const VERSION = 'Ratchet/0.1'; interface ConnectionInterface { + /** + * Send data to the connection + * @param string + */ + function write($data); + + /** + * End the connection + */ + function end(); } \ No newline at end of file diff --git a/src/Ratchet/Resource/Socket/BSDSocket.php b/src/Ratchet/Resource/Socket/BSDSocket.php index 353054a..d66c371 100644 --- a/src/Ratchet/Resource/Socket/BSDSocket.php +++ b/src/Ratchet/Resource/Socket/BSDSocket.php @@ -157,7 +157,7 @@ class BSDSocket implements SocketInterface { $num = socket_select($read, $write, $except, $tv_sec, $tv_usec); if (false === $num) { - throw new BSDException($this); + throw new BSDSocketException($this); } return $num; diff --git a/tests/Ratchet/Tests/Mock/Connection.php b/tests/Ratchet/Tests/Mock/Connection.php index 7c321f3..47f4da1 100644 --- a/tests/Ratchet/Tests/Mock/Connection.php +++ b/tests/Ratchet/Tests/Mock/Connection.php @@ -3,5 +3,18 @@ namespace Ratchet\Tests\Mock; use Ratchet\Resource\ConnectionInterface; class Connection implements ConnectionInterface { + public $last = array( + 'write' => '' + , 'end' => false + ); + public $remoteAddress = '127.0.0.1'; + + public function write($data) { + $this->last[__FUNCTION__] = $data; + } + + public function end() { + $this->last[__FUNCTION__] = true; + } } \ No newline at end of file diff --git a/tests/Ratchet/Tests/Mock/ConnectionDecorator.php b/tests/Ratchet/Tests/Mock/ConnectionDecorator.php new file mode 100644 index 0000000..60e0862 --- /dev/null +++ b/tests/Ratchet/Tests/Mock/ConnectionDecorator.php @@ -0,0 +1,22 @@ + '' + , 'end' => false + ); + + public function write($data) { + $this->last[__FUNCTION__] = $data; + + $this->getConnection()->write($data); + } + + public function end() { + $this->last[__FUNCTION__] = true; + + $this->getConnection()->end(); + } +} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Resource/AbstractConnectionDecoratorTest.php b/tests/Ratchet/Tests/Resource/AbstractConnectionDecoratorTest.php new file mode 100644 index 0000000..46cf6d7 --- /dev/null +++ b/tests/Ratchet/Tests/Resource/AbstractConnectionDecoratorTest.php @@ -0,0 +1,109 @@ +mock = new Connection; + $this->l1 = new ConnectionDecorator($this->mock); + $this->l2 = new ConnectionDecorator($this->l1); + } + + public function testGet() { + $var = 'hello'; + $val = 'world'; + + $this->mock->$var = $val; + + $this->assertEquals($val, $this->l1->$var); + $this->assertEquals($val, $this->l2->$var); + } + + public function testSet() { + $var = 'Chris'; + $val = 'Boden'; + + $this->l1->$var = $val; + + $this->assertEquals($val, $this->mock->$var); + } + + public function testSetLevel2() { + $var = 'Try'; + $val = 'Again'; + + $this->l2->$var = $val; + + $this->assertEquals($val, $this->mock->$var); + } + + public function testIsSetTrue() { + $var = 'PHP'; + $val = 'Ratchet'; + + $this->mock->$var = $val; + + $this->assertTrue(isset($this->l1->$var)); + $this->assertTrue(isset($this->l2->$var)); + } + + public function testIsSetFalse() { + $var = 'herp'; + $val = 'derp'; + + $this->assertFalse(isset($this->l1->$var)); + $this->assertFalse(isset($this->l2->$var)); + } + + public function testUnset() { + $var = 'Flying'; + $val = 'Monkey'; + + $this->mock->$var = $val; + unset($this->l1->$var); + + $this->assertFalse(isset($this->mock->$var)); + } + + public function testUnsetLevel2() { + $var = 'Flying'; + $val = 'Monkey'; + + $this->mock->$var = $val; + unset($this->l2->$var); + + $this->assertFalse(isset($this->mock->$var)); + } + + public function testGetConnection() { + $class = new \ReflectionClass('\\Ratchet\\Resource\\AbstractConnectionDecorator'); + $method = $class->getMethod('getConnection'); + $method->setAccessible(true); + + $conn = $method->invokeArgs($this->l1, array()); + + $this->assertSame($this->mock, $conn); + } + + public function testGetConnectionLevel2() { + $class = new \ReflectionClass('\\Ratchet\\Resource\\AbstractConnectionDecorator'); + $method = $class->getMethod('getConnection'); + $method->setAccessible(true); + + $conn = $method->invokeArgs($this->l2, array()); + + $this->assertSame($this->l1, $conn); + } + + public function testWarningGettingNothing() { + $this->markTestSkipped('Functionality not in class yet'); + } +} \ No newline at end of file From af35aab345b6bc511138dd9b9b1f9a7bcd44dc55 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Sun, 6 May 2012 14:27:14 -0400 Subject: [PATCH 04/22] True errors --- .../Resource/AbstractConnectionDecorator.php | 7 ---- .../AbstractConnectionDecoratorTest.php | 40 ++++++++++++++++++- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/Ratchet/Resource/AbstractConnectionDecorator.php b/src/Ratchet/Resource/AbstractConnectionDecorator.php index 3ae5472..c4ea479 100644 --- a/src/Ratchet/Resource/AbstractConnectionDecorator.php +++ b/src/Ratchet/Resource/AbstractConnectionDecorator.php @@ -22,14 +22,7 @@ abstract class AbstractConnectionDecorator implements ConnectionInterface { $this->wrappedConn->$name = $value; } - /** - * @todo trigger_error() instead - Have it the same as if called from a POPO - */ public function __get($name) { - if (!$this->__isset($name)) { - throw new \InvalidArgumentException("Attribute '{$name}' not found in Connection {$this->getID()}"); - } - return $this->wrappedConn->$name; } diff --git a/tests/Ratchet/Tests/Resource/AbstractConnectionDecoratorTest.php b/tests/Ratchet/Tests/Resource/AbstractConnectionDecoratorTest.php index 46cf6d7..5333093 100644 --- a/tests/Ratchet/Tests/Resource/AbstractConnectionDecoratorTest.php +++ b/tests/Ratchet/Tests/Resource/AbstractConnectionDecoratorTest.php @@ -103,7 +103,45 @@ class AbstractConnectionDecoratorTest extends \PHPUnit_Framework_TestCase { $this->assertSame($this->l1, $conn); } + public function testWrapperCanStoreSelfInDecorator() { + $this->mock->decorator = $this->l1; + + $this->assertSame($this->l1, $this->l2->decorator); + } + + public function testDecoratorRecursion() { + $this->mock->decorator = new \stdClass; + $this->mock->decorator->conn = $this->l1; + + $this->assertSame($this->l1, $this->mock->decorator->conn); + $this->assertSame($this->l1, $this->l1->decorator->conn); + $this->assertSame($this->l1, $this->l2->decorator->conn); + } + + public function testDecoratorRecursionLevel2() { + $this->mock->decorator = new \stdClass; + $this->mock->decorator->conn = $this->l2; + + $this->assertSame($this->l2, $this->mock->decorator->conn); + $this->assertSame($this->l2, $this->l1->decorator->conn); + $this->assertSame($this->l2, $this->l2->decorator->conn); + + // just for fun + $this->assertSame($this->l2, $this->l2->decorator->conn->decorator->conn->decorator->conn); + } + public function testWarningGettingNothing() { - $this->markTestSkipped('Functionality not in class yet'); + $this->setExpectedException('PHPUnit_Framework_Error'); + $var = $this->mock->nonExistant; + } + + public function testWarningGettingNothingLevel1() { + $this->setExpectedException('PHPUnit_Framework_Error'); + $var = $this->l1->nonExistant; + } + + public function testWarningGettingNothingLevel2() { + $this->setExpectedException('PHPUnit_Framework_Error'); + $var = $this->l2->nonExistant; } } \ No newline at end of file From d30c8358efa3cb8ba5d01dc243197c1b02c5c4ad Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Mon, 7 May 2012 18:49:13 -0400 Subject: [PATCH 05/22] [BCB] [WIP] Overhaul React at the core of Ratchet, refs #6 Removed Commands (except WAMP), refs #22 Updated Guzzle to 2.4 branch, refs #20 Fixed some Hixie bugs, refs #21 --- README.md | 45 ++-- composer.json | 21 ++ composer.lock | 19 +- .../Component/Server/IOServerComponent.php | 216 +++------------ src/Ratchet/Component/Server/IoConnection.php | 40 +++ .../Component/Server/IpBlackListComponent.php | 3 +- .../Component/WAMP/Resource/Connection.php | 28 ++ .../WebSocket/Command/Action/Disconnect.php | 22 -- .../WebSocket/Command/Action/Ping.php | 12 - .../WebSocket/Command/Action/Pong.php | 12 - .../Guzzle/Http/Message/RequestFactory.php | 223 +++++++++++++++- .../Component/WebSocket/Version/Hixie76.php | 8 +- .../WebSocket/WebSocketComponent.php | 79 ++---- .../Component/WebSocket/WsConnection.php | 33 +++ src/Ratchet/Resource/Connection.php | 49 ---- src/Ratchet/Resource/ConnectionInterface.php | 6 +- src/Ratchet/Resource/Socket/BSDSocket.php | 245 ------------------ .../Resource/Socket/BSDSocketException.php | 26 -- .../Resource/Socket/SocketInterface.php | 151 ----------- .../Server/IOServerComponentTest.php | 65 ----- .../Server/IpBlackListComponentTest.php | 4 +- .../WAMP/WAMPServerComponentTest.php | 12 +- tests/Ratchet/Tests/Mock/Connection.php | 8 +- .../Tests/Mock/ConnectionDecorator.php | 8 +- tests/Ratchet/Tests/Mock/FakeSocket.php | 100 ------- .../Tests/Resource/Command/CompositeTest.php | 5 +- .../Ratchet/Tests/Resource/ConnectionTest.php | 62 ----- .../Tests/Resource/Socket/BSDSocketTest.php | 68 ----- 28 files changed, 449 insertions(+), 1121 deletions(-) create mode 100644 src/Ratchet/Component/Server/IoConnection.php create mode 100644 src/Ratchet/Component/WAMP/Resource/Connection.php delete mode 100644 src/Ratchet/Component/WebSocket/Command/Action/Disconnect.php delete mode 100644 src/Ratchet/Component/WebSocket/Command/Action/Ping.php delete mode 100644 src/Ratchet/Component/WebSocket/Command/Action/Pong.php create mode 100644 src/Ratchet/Component/WebSocket/WsConnection.php delete mode 100644 src/Ratchet/Resource/Connection.php delete mode 100644 src/Ratchet/Resource/Socket/BSDSocket.php delete mode 100644 src/Ratchet/Resource/Socket/BSDSocketException.php delete mode 100644 src/Ratchet/Resource/Socket/SocketInterface.php delete mode 100644 tests/Ratchet/Tests/Component/Server/IOServerComponentTest.php delete mode 100644 tests/Ratchet/Tests/Mock/FakeSocket.php delete mode 100644 tests/Ratchet/Tests/Resource/ConnectionTest.php delete mode 100644 tests/Ratchet/Tests/Resource/Socket/BSDSocketTest.php diff --git a/README.md b/README.md index 570456d..752cbaa 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ #Ratchet -A PHP 5.3 (PSR-0 compliant) component library for serving sockets and building socket based applications. +A PHP 5.3 (PSR-0) component library for serving sockets and building socket based applications. Build up your application through simple interfaces using the decorator and command patterns. Re-use your application without changing any of its code just by combining different components. @@ -32,57 +32,46 @@ See https://github.com/cboden/Ratchet-examples for some out-of-the-box working d ```php _clients = new \SplObjectStorage; + public function __construct() { + $this->clients = new \SplObjectStorage; } public function onOpen(ConnectionInterface $conn) { - $this->_clients->attach($conn); + $this->clients->attach($conn); } public function onMessage(ConnectionInterface $from, $msg) { - $commands = new Cmds; - - foreach ($this->_clients as $client) { + foreach ($this->clients as $client) { if ($from != $client) { - $msg_cmd = new SendMessage($client); - $msg_cmd->setMessage($msg); - - $commands->enqueue($msg_cmd); + $client->send($msg); } } - - return $commands; } public function onClose(ConnectionInterface $conn) { - $this->_clients->detach($conn); + $this->clients->detach($conn); } public function onError(ConnectionInterface $conn, \Exception $e) { - return new CloseConnection($conn); + $conn->close(); } } -// Run the server application through the WebSocket protocol -$server = new IOServerComponent(new WebSocketComponent(new Chat)); -$server->run(8000); + // Run the server application through the WebSocket protocol + $server = new IoServer(new WsServer(new Chat)); + $server->run(8000); ``` # php chat.php \ No newline at end of file diff --git a/composer.json b/composer.json index 3273137..3088f92 100644 --- a/composer.json +++ b/composer.json @@ -23,5 +23,26 @@ "php": ">=5.3.2" , "guzzle/guzzle": "2.4.*" , "symfony/http-foundation": "2.1.*" + , "evenement/evenement": "dev-master" + , "cboden/react": "dev-master" } + , "repositories": [ + { + "type": "package" + , "package": { + "name": "cboden/react" + , "version": "dev-master" + , "autoload": { + "psr-0": { + "React": "src" + } + } + , "source": { + "url": "git@github.com:cboden/SocketServer.git" + , "type": "git" + , "reference": "ratchet" + } + } + } + ] } \ No newline at end of file diff --git a/composer.lock b/composer.lock index 8b37a34..4e5ff35 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,20 @@ { - "hash": "8cea9930a3f96f47c598f35e2ea96a85", + "hash": "ae2788962867b06b14a9e473cdd71ebd", "packages": [ + { + "package": "cboden/react", + "version": "dev-master", + "source-reference": "ratchet" + }, { "package": "doctrine/common", - "version": "2.2.x-dev", - "source-reference": "1e0aa60d109c630d19543d999f12e2852ef8f932" + "version": "dev-master", + "source-reference": "717ea940ff8fa0854e84a2249edadfb998f91406" + }, + { + "package": "evenement/evenement", + "version": "dev-master", + "source-reference": "808e3aaea8d4f908e455b0e047cc1acc46b38d44" }, { "package": "guzzle/guzzle", @@ -23,8 +33,7 @@ }, { "package": "symfony/validator", - "version": "dev-master", - "source-reference": "dac248b43b62d30023dd9b73ad7e5b7bc1128e5e" + "version": "v2.0.10" } ], "packages-dev": null, diff --git a/src/Ratchet/Component/Server/IOServerComponent.php b/src/Ratchet/Component/Server/IOServerComponent.php index 15bb5f5..2ba7109 100644 --- a/src/Ratchet/Component/Server/IOServerComponent.php +++ b/src/Ratchet/Component/Server/IOServerComponent.php @@ -1,199 +1,57 @@ loop = $loop; - /** - * Number of bytes to read in the TCP buffer at a time - * Default is (currently) 4kb - * @var int - */ - protected $_buffer_size = 4096; + $that = $this; - /** - * After run() is called, the server will loop as long as this is true - * This is here for unit testing purposes - * @var bool - * @internal - */ - protected $_run = true; + $socket->on('connect', function($conn) use ($app, $that) { + $decor = new IoConnection($conn, $that); - public function __construct(MessageComponentInterface $component) { - $this->_decorating = $component; + $decor->resourceId = (int)$conn->socket; + $decor->remoteAddress = '127.0.0.1'; // todo + + $app->onOpen($decor); + + $conn->on('data', function($data) use ($decor, $app) { + $app->onMessage($decor, $data); + }); + + $conn->on('error', function($e) use ($decor, $app) { + $app->onError($decor, $e); + }); + + $conn->on('end', function() use ($decor, $app) { + $app->onClose($decor); + }); + }); } - /** - * Set the incoming buffer size in bytes - * @param int - * @return App - * @throws InvalidArgumentException If the parameter is less than 1 - */ - public function setBufferSize($recv_bytes) { - if ((int)$recv_bytes < 1) { - throw new \InvalidArgumentException('Invalid number of bytes set, must be more than 0'); - } + public static function factory(MessageComponentInterface $component, $port = 80, $address = '0.0.0.0') { + $loop = LoopFactory::create(); + $socket = new Reactor($loop); + $socket->listen($port, $address); + $server = new self($component, $socket, $loop); - $this->_buffer_size = (int)$recv_bytes; - - return $this; + return $server; } - /* - * Run the server infinitely - * @param int The port to listen to connections on (make sure to run as root if < 1000) - * @param mixed The address to listen for incoming connections on. "0.0.0.0" to listen from anywhere - * @param Ratchet\Resource\Socket\SocketInterface - * @throws Ratchet\Exception - */ - public function run($port, $address = '0.0.0.0', SocketInterface $host = null) { - if (null === $host) { - $host = new BSDSocket; - $host->set_option(SOL_SOCKET, SO_REUSEADDR, 1); - } - - $this->_connections[$host->getResource()] = new Connection($host); - $this->_resources[] = $host->getResource(); - - gc_enable(); - set_time_limit(0); - ob_implicit_flush(); - - declare(ticks = 1); - - $host->set_option(SOL_SOCKET, SO_SNDBUF, $this->_buffer_size); - $host->set_nonblock()->bind($address, (int)$port)->listen(); - - do { - $this->loop($host); - } while ($this->_run); - } - - protected function loop(SocketInterface $host) { - $changed = $this->_resources; - - try { - $write = $except = null; - - $num_changed = $host->select($changed, $write, $except, null); - } catch (Exception $e) { - // master had a problem?...what to do? - return; - } - - foreach($changed as $resource) { - try { - $conn = $this->_connections[$resource]; - - if ($host->getResource() === $resource) { - $res = $this->onOpen($conn); - } else { - $data = $buf = ''; - $bytes = $conn->getSocket()->recv($buf, $this->_buffer_size, MSG_DONTWAIT); - if ($bytes > 0) { - $data = $buf; - - // This idea works* but... - // 1) A single DDOS attack will block the entire application (I think) - // 2) What if the last message in the frame is equal to $recv_bytes? Would loop until another msg is sent - // 3) This failed...an intermediary can set their buffer lower and this still propagates a fragment - // Need to 1) proc_open the recv() calls. 2) ??? - - /* - while ($bytes === $recv_bytes) { - $bytes = $conn->recv($buf, $recv_bytes, 0); - $data .= $buf; - } - */ - - $res = $this->onMessage($conn, $data); - } else { - $res = $this->onClose($conn); - } - } - } catch (\Exception $e) { - $res = $this->onError($conn, $e); - } - - while ($res instanceof CommandInterface) { - try { - $new_res = $res->execute($this); - } catch (\Exception $e) { - break; - // trigger new error - // $new_res = $this->onError($e->getSocket()); ??? - // this is dangerous territory...could get in an infinte loop...Exception might not be Ratchet\Exception...$new_res could be ActionInterface|Composite|NULL... - } - - $res = $new_res; - } - } - } - - /** - * {@inheritdoc} - */ - public function onOpen(ConnectionInterface $conn) { - $new_socket = clone $conn->getSocket(); - $new_socket->set_nonblock(); - $new_connection = new Connection($new_socket); - - $new_connection->remoteAddress = $new_socket->getRemoteAddress(); - $new_connection->resourceId = (int)substr((string)$new_socket->getResource(), strrpos((string)$new_socket->getResource(), '#') + 1); - - $this->_resources[] = $new_connection->getSocket()->getResource(); - $this->_connections[$new_connection->getSocket()->getResource()] = $new_connection; - - return $this->_decorating->onOpen($new_connection); - } - - /** - * {@inheritdoc} - */ - public function onMessage(ConnectionInterface $from, $msg) { - return $this->_decorating->onMessage($from, $msg); - } - - /** - * {@inheritdoc} - */ - public function onClose(ConnectionInterface $conn) { - $resource = $conn->getSocket()->getResource(); - - $cmd = $this->_decorating->onClose($conn); - - unset($this->_connections[$resource], $this->_resources[array_search($resource, $this->_resources)]); - - return $cmd; - } - - /** - * {@inheritdoc} - */ - public function onError(ConnectionInterface $conn, \Exception $e) { - return $this->_decorating->onError($conn, $e); + public function run() { + $this->loop->run(); } } \ No newline at end of file diff --git a/src/Ratchet/Component/Server/IoConnection.php b/src/Ratchet/Component/Server/IoConnection.php new file mode 100644 index 0000000..c14303e --- /dev/null +++ b/src/Ratchet/Component/Server/IoConnection.php @@ -0,0 +1,40 @@ +conn = $conn; + $this->server = $server; + } + + /** + * {@inheritdoc} + */ + public function send($data) { + return $this->conn->write($data); + } + + /** + * {@inheritdoc} + */ + public function close() { + $this->server->onClose($this); + $this->conn->end(); + } +} \ No newline at end of file diff --git a/src/Ratchet/Component/Server/IpBlackListComponent.php b/src/Ratchet/Component/Server/IpBlackListComponent.php index 5e2d06c..ad2e38d 100644 --- a/src/Ratchet/Component/Server/IpBlackListComponent.php +++ b/src/Ratchet/Component/Server/IpBlackListComponent.php @@ -2,7 +2,6 @@ namespace Ratchet\Component\Server; use Ratchet\Component\MessageComponentInterface; use Ratchet\Resource\ConnectionInterface; -use Ratchet\Resource\Command\Action\CloseConnection; class IpBlackListComponent implements MessageComponentInterface { /** @@ -74,7 +73,7 @@ class IpBlackListComponent implements MessageComponentInterface { */ function onOpen(ConnectionInterface $conn) { if ($this->isBlocked($conn->remoteAddress)) { - return new CloseConnection($conn); + return $conn->close(); } return $this->_decorating->onOpen($conn); diff --git a/src/Ratchet/Component/WAMP/Resource/Connection.php b/src/Ratchet/Component/WAMP/Resource/Connection.php new file mode 100644 index 0000000..4bff525 --- /dev/null +++ b/src/Ratchet/Component/WAMP/Resource/Connection.php @@ -0,0 +1,28 @@ +_code = (int)$code; - - // re-do message based on code - } - - public function execute(ComponentInterface $scope = null) { - parent::execute(); - $this->_socket->close(); - } -} \ No newline at end of file diff --git a/src/Ratchet/Component/WebSocket/Command/Action/Ping.php b/src/Ratchet/Component/WebSocket/Command/Action/Ping.php deleted file mode 100644 index bac184d..0000000 --- a/src/Ratchet/Component/WebSocket/Command/Action/Ping.php +++ /dev/null @@ -1,12 +0,0 @@ -requestClass = static::$instance->entityEnclosingRequestClass; +class RequestFactory implements RequestFactoryInterface +{ + /** + * @var Standard request headers + */ + protected static $requestHeaders = array( + 'accept', 'accept-charset', 'accept-encoding', 'accept-language', + 'authorization', 'cache-control', 'connection', 'cookie', + 'content-length', 'content-type', 'date', 'expect', 'from', 'host', + 'if-match', 'if-modified-since', 'if-none-match', 'if-range', + 'if-unmodified-since', 'max-forwards', 'pragma', 'proxy-authorization', + 'range', 'referer', 'te', 'transfer-encoding', 'upgrade', 'user-agent', + 'via', 'warning' + ); + + /** + * @var RequestFactory Singleton instance of the default request factory + */ + protected static $instance; + + /** + * @var string Class to instantiate for GET, HEAD, and DELETE requests + */ + protected $requestClass = 'Guzzle\\Http\\Message\\EntityEnclosingRequest'; + + /** + * @var string Class to instantiate for POST and PUT requests + */ + protected $entityEnclosingRequestClass = 'Guzzle\\Http\\Message\\EntityEnclosingRequest'; + + /** + * Get a cached instance of the default request factory + * + * @return RequestFactory + */ + public static function getInstance() + { + // @codeCoverageIgnoreStart + if (!self::$instance) { + self::$instance = new self(); + } + // @codeCoverageIgnoreEnd + + return self::$instance; + } + + /** + * {@inheritdoc} + */ + public function parseMessage($message) + { + if (!$message) { + return false; } - return $instance; + $headers = new Collection(); + $scheme = $host = $body = $method = $user = $pass = $query = $port = $version = $protocol = ''; + $path = '/'; + + // Inspired by https://github.com/kriswallsmith/Buzz/blob/message-interfaces/lib/Buzz/Message/Parser/Parser.php#L16 + $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE); + for ($i = 0, $c = count($lines); $i < $c; $i += 2) { + + $line = $lines[$i]; + + // If two line breaks were encountered, then this is the body + if (empty($line)) { + $body = implode('', array_slice($lines, $i + 2)); + break; + } + + // Parse message headers + $matches = array(); + if (!$method && preg_match('#^(?P[A-Za-z]+)\s+(?P/.*)\s+(?P\w+)/(?P\d\.\d)\s*$#i', $line, $matches)) { + $method = strtoupper($matches['method']); + $protocol = strtoupper($matches['protocol']); + $path = $matches['path']; + $version = $matches['version']; + $scheme = 'http'; + } else if (strpos($line, ':')) { + list($key, $value) = explode(':', $line, 2); + $key = trim($key); + // Normalize standard HTTP headers + if (in_array(strtolower($key), self::$requestHeaders)) { + $key = str_replace(' ', '-', ucwords(str_replace('-', ' ', $key))); + } + // Headers are case insensitive + $headers->add($key, trim($value)); + } + } + + // Check for the Host header + if (isset($headers['Host'])) { + $host = $headers['Host']; + } + + if (strpos($host, ':')) { + list($host, $port) = array_map('trim', explode(':', $host)); + if ($port == 443) { + $scheme = 'https'; + } + } else { + $port = ''; + } + + // Check for basic authorization + $auth = isset($headers['Authorization']) ? $headers['Authorization'] : ''; + + if ($auth) { + list($type, $data) = explode(' ', $auth); + if (strtolower($type) == 'basic') { + $data = base64_decode($data); + list($user, $pass) = explode(':', $data); + } + } + + // Check if a query is present + $qpos = strpos($path, '?'); + if ($qpos) { + $query = substr($path, $qpos); + $path = substr($path, 0, $qpos); + } + + return array( + 'method' => $method, + 'protocol' => $protocol, + 'protocol_version' => $version, + 'parts' => array( + 'scheme' => $scheme, + 'host' => $host, + 'port' => $port, + 'user' => $user, + 'pass' => $pass, + 'path' => $path, + 'query' => $query + ), + 'headers' => $headers->getAll(), + 'body' => $body + ); + } + + /** + * {@inheritdoc} + */ + public function fromMessage($message) + { + $parsed = $this->parseMessage($message); + + if (!$parsed) { + return false; + } + + $request = $this->fromParts($parsed['method'], $parsed['parts'], + $parsed['headers'], $parsed['body'], $parsed['protocol'], + $parsed['protocol_version']); + + // EntityEnclosingRequest adds an "Expect: 100-Continue" header when + // using a raw request body for PUT or POST requests. This factory + // method should accurately reflect the message, so here we are + // removing the Expect header if one was not supplied in the message. + if (!isset($parsed['headers']['Expect'])) { + $request->removeHeader('Expect'); + } + + return $request; + } + + /** + * {@inheritdoc} + */ + public function fromParts($method, array $parts, $headers = null, $body = null, $protocol = 'HTTP', $protocolVersion = '1.1') + { + return $this->create($method, Url::buildUrl($parts, true), $headers, $body) + ->setProtocolVersion($protocolVersion); + } + + /** + * {@inheritdoc} + */ + public function create($method, $url, $headers = null, $body = null) + { + if ($method != 'POST' && $method != 'PUT' && $method != 'PATCH') { + $c = $this->requestClass; + $request = new $c($method, $url, $headers); + if ($body) { + $request->setBody(EntityBody::factory($body)); + } + } else { + $c = $this->entityEnclosingRequestClass; + $request = new $c($method, $url, $headers); + + if ($body) { + if ($method == 'POST' && (is_array($body) || $body instanceof Collection)) { + $request->addPostFields($body); + } else if (is_resource($body) || $body instanceof EntityBody) { + $request->setBody($body, (string) $request->getHeader('Content-Type')); + } else { + $request->setBody((string) $body, (string) $request->getHeader('Content-Type')); + } + } + + // Fix chunked transfers based on the passed headers + if (isset($headers['Transfer-Encoding']) && $headers['Transfer-Encoding'] == 'chunked') { + $request->removeHeader('Content-Length') + ->setHeader('Transfer-Encoding', 'chunked'); + } + } + + return $request; } } \ No newline at end of file diff --git a/src/Ratchet/Component/WebSocket/Version/Hixie76.php b/src/Ratchet/Component/WebSocket/Version/Hixie76.php index 1bbbd03..2732a04 100644 --- a/src/Ratchet/Component/WebSocket/Version/Hixie76.php +++ b/src/Ratchet/Component/WebSocket/Version/Hixie76.php @@ -20,7 +20,7 @@ class Hixie76 implements VersionInterface { * {@inheritdoc} */ public static function isProtocol(RequestInterface $request) { - return !(null === $request->getHeader('Sec-WebSocket-Key2')); + return !(null === $request->getHeader('Sec-WebSocket-Key2', true)); } /** @@ -28,13 +28,13 @@ class Hixie76 implements VersionInterface { * @return string */ public function handshake(RequestInterface $request) { - $body = $this->sign($request->getHeader('Sec-WebSocket-Key1'), $request->getHeader('Sec-WebSocket-Key2'), $request->getBody()); + $body = $this->sign($request->getHeader('Sec-WebSocket-Key1', true), $request->getHeader('Sec-WebSocket-Key2', true), (string)$request->getBody()); $headers = array( 'Upgrade' => 'WebSocket' , 'Connection' => 'Upgrade' - , 'Sec-WebSocket-Origin' => $request->getHeader('Origin') - , 'Sec-WebSocket-Location' => 'ws://' . $request->getHeader('Host') . $request->getPath() + , 'Sec-WebSocket-Origin' => $request->getHeader('Origin', true) + , 'Sec-WebSocket-Location' => 'ws://' . $request->getHeader('Host', true) . $request->getPath() ); $response = new Response('101', $headers, $body); diff --git a/src/Ratchet/Component/WebSocket/WebSocketComponent.php b/src/Ratchet/Component/WebSocket/WebSocketComponent.php index 24b4b7c..1cdbdd6 100644 --- a/src/Ratchet/Component/WebSocket/WebSocketComponent.php +++ b/src/Ratchet/Component/WebSocket/WebSocketComponent.php @@ -2,15 +2,13 @@ namespace Ratchet\Component\WebSocket; use Ratchet\Component\MessageComponentInterface; use Ratchet\Resource\ConnectionInterface; -use Ratchet\Resource\Command\Factory; -use Ratchet\Resource\Command\CommandInterface; -use Ratchet\Resource\Command\Action\SendMessage; use Guzzle\Http\Message\RequestInterface; use Ratchet\Component\WebSocket\Guzzle\Http\Message\RequestFactory; /** * 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 + * @todo Separate this class into a two classes: Component and a protocol handler * @link http://ca.php.net/manual/en/ref.http.php * @link http://dev.w3.org/html5/websockets/ */ @@ -22,10 +20,9 @@ class WebSocketComponent implements MessageComponentInterface { protected $_decorating; /** - * Creates commands/composites instead of calling several classes manually - * @var Ratchet\Resource\Command\Factory + * @var SplObjectStorage */ - protected $_factory; + protected $connections; /** * Re-entrant instances of protocol version classes @@ -48,7 +45,7 @@ class WebSocketComponent implements MessageComponentInterface { public function __construct(MessageComponentInterface $component) { $this->_decorating = $component; - $this->_factory = new Factory; + $this->connections = new \SplObjectStorage; } /** @@ -96,11 +93,12 @@ class WebSocketComponent implements MessageComponentInterface { $response->setHeader('X-Powered-By', \Ratchet\Resource\VERSION); $header = (string)$response; - $comp = $this->_factory->newComposite(); - $comp->enqueue($this->_factory->newCommand('SendMessage', $from)->setMessage($header)); - $comp->enqueue($this->prepareCommand($this->_decorating->onOpen($from, $msg))); // Need to send headers/handshake to application, let it have the cookies, etc + $from->send($header); - return $comp; + $conn = new WsConnection($from); + $this->connections->attach($from, $conn); + + return $this->_decorating->onOpen($conn); } if (!isset($from->WebSocket->message)) { @@ -115,6 +113,7 @@ class WebSocketComponent implements MessageComponentInterface { $from->WebSocket->frame->addBuffer($msg); if ($from->WebSocket->frame->isCoalesced()) { if ($from->WebSocket->frame->getOpcode() > 2) { + $from->end(); throw new \UnexpectedValueException('Control frame support coming soon!'); } // Check frame @@ -127,10 +126,8 @@ class WebSocketComponent implements MessageComponentInterface { } if ($from->WebSocket->message->isCoalesced()) { - $cmds = $this->prepareCommand($this->_decorating->onMessage($from, (string)$from->WebSocket->message)); + $this->_decorating->onMessage($this->connections[$from], (string)$from->WebSocket->message); unset($from->WebSocket->message); - - return $cmds; } } @@ -138,57 +135,23 @@ class WebSocketComponent implements MessageComponentInterface { * {@inheritdoc} */ public function onClose(ConnectionInterface $conn) { - return $this->prepareCommand($this->_decorating->onClose($conn)); + // WS::onOpen is not called when the socket connects, it's call when the handshake is done + // The socket could close before WS calls onOpen, so we need to check if we've "opened" it for the developer yet + if ($this->connections->contains($conn)) { + $this->_decorating->onClose($this->connections[$conn]); + $this->connections->detach($conn); + } } /** * {@inheritdoc} - * @todo Shouldn't I be using prepareCommand() on the return? look into this */ public function onError(ConnectionInterface $conn, \Exception $e) { - return $this->_decorating->onError($conn, $e); - } - - /** - * Checks if a return Command from your application is a message, if so encode it/them - * @param Ratchet\Resource\Command\CommandInterface|NULL - * @return Ratchet\Resource\Command\CommandInterface|NULL - */ - protected function prepareCommand(CommandInterface $command = null) { - $cache = array(); - return $this->mungCommand($command, $cache); - } - - /** - * Does the actual work of prepareCommand - * Separated to pass the cache array by reference, so we're not framing the same stirng over and over - * @param Ratchet\Resource\Command\CommandInterface|NULL - * @param array - * @return Ratchet\Resource\Command\CommandInterface|NULL - */ - protected function mungCommand(CommandInterface $command = null, &$cache) { - if ($command instanceof SendMessage) { - if (!isset($command->getConnection()->WebSocket->version)) { // Client could close connection before handshake complete or invalid handshake - return $command; - } - - $version = $command->getConnection()->WebSocket->version; - $hash = md5($command->getMessage()) . '-' . spl_object_hash($version); - - if (!isset($cache[$hash])) { - $cache[$hash] = $version->frame($command->getMessage(), $this->_mask_payload); - } - - return $command->setMessage($cache[$hash]); + if ($this->connections->contains($conn)) { + $this->_decorating->onError($this->connections[$conn], $e); + } else { + $conn->close(); } - - if ($command instanceof \Traversable) { - foreach ($command as $cmd) { - $cmd = $this->mungCommand($cmd, $cache); - } - } - - return $command; } /** diff --git a/src/Ratchet/Component/WebSocket/WsConnection.php b/src/Ratchet/Component/WebSocket/WsConnection.php new file mode 100644 index 0000000..a4f9b6c --- /dev/null +++ b/src/Ratchet/Component/WebSocket/WsConnection.php @@ -0,0 +1,33 @@ +WebSocket->version->frame($data, false); + + $this->getConnection()->send($data); + } + + public function close() { + // send close frame + + // ??? + + // profit + + $this->getConnection()->close(); // temporary + } + + public function ping() { + } + + public function pong() { + } +} \ No newline at end of file diff --git a/src/Ratchet/Resource/Connection.php b/src/Ratchet/Resource/Connection.php deleted file mode 100644 index def516b..0000000 --- a/src/Ratchet/Resource/Connection.php +++ /dev/null @@ -1,49 +0,0 @@ -_socket = $socket; - } - - /** - * {@inheritdoc} - */ - public function write($data) { - return $this->_socket->deliver($data); - } - - /** - * {@inheritdoc} - */ - public function end() { - try { - $this->_socket->shutdown(); - } catch (BSDSocketException $e) { - } - - $this->_socket->close(); - } - - /** - * This is here because I couldn't figure out a better/easier way to tie a connection and socket together for the server and commands - * Anyway, if you're here, it's not recommended you use this/directly interact with the socket in your App... - * The command pattern (which is fully flexible, see Runtime) is the safest, desired way to interact with the socket(s). - * @return Ratchet\SocketInterface - * @todo Figure out a better way to match Socket/Connection in Application and Commands - */ - public function getSocket() { - return $this->_socket; - } -} \ No newline at end of file diff --git a/src/Ratchet/Resource/ConnectionInterface.php b/src/Ratchet/Resource/ConnectionInterface.php index f53df88..49030f2 100644 --- a/src/Ratchet/Resource/ConnectionInterface.php +++ b/src/Ratchet/Resource/ConnectionInterface.php @@ -8,10 +8,10 @@ interface ConnectionInterface { * Send data to the connection * @param string */ - function write($data); + function send($data); /** - * End the connection + * Close the connection */ - function end(); + function close(); } \ No newline at end of file diff --git a/src/Ratchet/Resource/Socket/BSDSocket.php b/src/Ratchet/Resource/Socket/BSDSocket.php deleted file mode 100644 index d66c371..0000000 --- a/src/Ratchet/Resource/Socket/BSDSocket.php +++ /dev/null @@ -1,245 +0,0 @@ - - * @link http://ca2.php.net/manual/en/book.sockets.php - */ -class BSDSocket implements SocketInterface { - /** - * @type resource - */ - protected $_resource; - - public static $_defaults = array( - 'domain' => AF_INET - , 'type' => SOCK_STREAM - , 'protocol' => SOL_TCP - ); - - /** - * @param int Specifies the protocol family to be used by the socket. - * @param int The type of communication to be used by the socket - * @param int Sets the specific protocol within the specified domain to be used when communicating on the returned socket - * @throws BSDSocketException - */ - public function __construct($domain = null, $type = null, $protocol = null) { - list($domain, $type, $protocol) = static::getConfig($domain, $type, $protocol); - - $this->_resource = @socket_create($domain, $type, $protocol); - - if (!is_resource($this->_resource)) { - throw new BSDSocketException($this); - } - } - - public function __destruct() { - @socket_close($this->_resource); - } - - public function __toString() { - $id = (string)$this->getResource(); - return (string)substr($id, strrpos($id, '#') + 1); - } - - /** - * @return resource (Socket) - */ - public function getResource() { - return $this->_resource; - } - - public function __clone() { - $this->_resource = @socket_accept($this->_resource); - - if (false === $this->_resource) { - throw new BSDSocketException($this); - } - } - - public function deliver($message) { - $len = strlen($message); - - do { - $sent = $this->write($message, $len); - $len -= $sent; - $message = substr($message, $sent); - } while ($len > 0); - } - - public function bind($address, $port = 0) { - if (false === @socket_bind($this->getResource(), $address, $port)) { - throw new BSDSocketException($this); - } - - return $this; - } - - public function close() { - @socket_close($this->getResource()); - unset($this->_resource); - } - - public function connect($address, $port = 0) { - if (false === @socket_connect($this->getResource(), $address, $port)) { - throw new BSDSocketException($this); - } - - return $this; - } - - public function getRemoteAddress() { - $address = $port = ''; - if (false === @socket_getpeername($this->getResource(), $address, $port)) { - throw new BSDSocketException($this); - } - - return $address; - } - - public function get_option($level, $optname) { - if (false === ($res = @socket_get_option($this->getResource(), $level, $optname))) { - throw new BSDSocketException($this); - } - - return $res; - } - - public function listen($backlog = 0) { - if (false === @socket_listen($this->getResource(), $backlog)) { - throw new BSDSocketException($this); - } - - return $this; - } - - public function read($length, $type = PHP_BINARY_READ) { - if (false === ($res = @socket_read($this->getResource(), $length, $type))) { - throw new BSDSocketException($this); - } - - return $res; - } - - /** - * @see http://ca3.php.net/manual/en/function.socket-recv.php - * @param string Variable to write data to - * @param int Number of bytes to read - * @param int - * @return int Number of bytes received - * @throws BSDSocketException - */ - public function recv(&$buf, $len, $flags) { - if (false === ($bytes = @socket_recv($this->_resource, $buf, $len, $flags))) { - throw new BSDSocketException($this); - } - - return $bytes; - } - - /** - * Since PHP is retarded and their golden hammer, the array, doesn't implement any interfaces I have to hackishly overload socket_select - * @see http://ca3.php.net/manual/en/function.socket-select.php - * @param Iterator|array|NULL The sockets listed in the read array will be watched to see if characters become available for reading (more precisely, to see if a read will not block - in particular, a socket resource is also ready on end-of-file, in which case a socket_read() will return a zero length string). - * @param Iterator|array|NULL The sockets listed in the write array will be watched to see if a write will not block. - * @param Iterator|array|NULL The sockets listed in the except array will be watched for exceptions. - * @param int The tv_sec and tv_usec together form the timeout parameter. The timeout is an upper bound on the amount of time elapsed before socket_select() return. tv_sec may be zero , causing socket_select() to return immediately. This is useful for polling. If tv_sec is NULL (no timeout), socket_select() can block indefinitely. - * @param int - * @throws \InvalidArgumentException - * @throws BSDSocketException - */ - public function select(&$read, &$write, &$except, $tv_sec, $tv_usec = 0) { - $read = static::mungForSelect($read); - $write = static::mungForSelect($write); - $except = static::mungForSelect($except); - - $num = socket_select($read, $write, $except, $tv_sec, $tv_usec); - - if (false === $num) { - throw new BSDSocketException($this); - } - - return $num; - } - - public function set_block() { - if (false === @socket_set_block($this->getResource())) { - throw new BSDSocketException($this); - } - - return $this; - } - - public function set_nonblock() { - if (false === @socket_set_nonblock($this->getResource())) { - throw new BSDSocketException($this); - } - - return $this; - } - - public function set_option($level, $optname, $optval) { - if (false === @socket_set_option($this->getResource(), $level, $optname, $optval)) { - throw new BSDSocketException($this); - } - - return $this; - } - - public function shutdown($how = 2) { - if (false === @socket_shutdown($this->getResource(), $how)) { - throw new BSDSocketException($this); - } - - return $this; - } - - public function write($buffer, $length = 0) { - if (false === ($res = @socket_write($this->getResource(), $buffer, $length))) { - throw new BSDSocketException($this); - } - - return $res; - } - - /** - * @internal - * @param int Specifies the protocol family to be used by the socket. - * @param int The type of communication to be used by the socket - * @param int Sets the specific protocol within the specified domain to be used when communicating on the returned socket - * @return array - */ - protected static function getConfig($domain = null, $type = null, $protocol = null) { - foreach (static::$_defaults as $key => $val) { - if (null === $$key) { - $$key = $val; - } - } - - return array($domain, $type, $protocol); - } - - /** - * @internal - * @param Iterator|array|NULL - * @return array|NULL - * @throws \InvalidArgumentException - */ - protected static function mungForSelect($collection) { - if (null === $collection || is_array($collection)) { - return $collection; - } - - if (!($collection instanceof \Traversable)) { - throw new \InvalidArgumentException('Object pass is not traversable'); - } - - $return = array(); - foreach ($collection as $key => $socket) { - $return[$key] = ($socket instanceof $this ? $socket->getResource() : $socket); - } - - return $return; - } -} \ No newline at end of file diff --git a/src/Ratchet/Resource/Socket/BSDSocketException.php b/src/Ratchet/Resource/Socket/BSDSocketException.php deleted file mode 100644 index b3ef30e..0000000 --- a/src/Ratchet/Resource/Socket/BSDSocketException.php +++ /dev/null @@ -1,26 +0,0 @@ -_socket = $socket; - //@socket_clear_error($socket->getResource()); - - parent::__construct($msg, $int); - } - - public function getSocket() { - return $this->_socket; - } -} \ No newline at end of file diff --git a/src/Ratchet/Resource/Socket/SocketInterface.php b/src/Ratchet/Resource/Socket/SocketInterface.php deleted file mode 100644 index a01a5b8..0000000 --- a/src/Ratchet/Resource/Socket/SocketInterface.php +++ /dev/null @@ -1,151 +0,0 @@ -_catalyst = new Socket; - $this->_decorated = new TestApp; - $this->_server = new IOServerComponent($this->_decorated); - - $ref = new \ReflectionClass('\\Ratchet\\Component\\Server\\IOServerComponent'); - $prop = $ref->getProperty('_run'); - $prop->setAccessible(true); - $prop->setValue($this->_server, false); - } - - protected function getPrivateProperty($class, $name) { - $reflectedClass = new \ReflectionClass($class); - $property = $reflectedClass->getProperty($name); - $property->setAccessible(true); - - return $property->getValue($class); - } - - protected function getMasterConnection() { - $connections = $this->getPrivateProperty($this->_server, '_connections'); - return array_pop($connections); - } - - public function testOnOpenPassesClonedSocket() { - $this->_server->run(1025, '127.0.0.1', $this->_catalyst); - $master = $this->getMasterConnection(); - - $this->_server->onOpen($master); - $clone = $this->_decorated->last['onOpen'][0]; - - $this->assertEquals($master->resourceId + 1, $clone->resourceId); - } - - public function testOnMessageSendsToApp() { - $this->_server->run(1025, '127.0.0.1', $this->_catalyst); - $master = $this->getMasterConnection(); - - // todo, make FakeSocket better, set data in select, recv to pass data when called, then do this check - // that way can mimic the TCP fragmentation/buffer situation - - $this->_server->onOpen($master); - $clone = $this->_decorated->last['onOpen'][0]; - - // $this->_server->run($this->_catalyst); - $msg = 'Hello World!'; - $this->_server->onMessage($clone, $msg); - - $this->assertEquals($msg, $this->_decorated->last['onMessage'][1]); - } -} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Component/Server/IpBlackListComponentTest.php b/tests/Ratchet/Tests/Component/Server/IpBlackListComponentTest.php index c164803..bd0d5e2 100644 --- a/tests/Ratchet/Tests/Component/Server/IpBlackListComponentTest.php +++ b/tests/Ratchet/Tests/Component/Server/IpBlackListComponentTest.php @@ -21,9 +21,9 @@ class IpBlackListComponentTest extends \PHPUnit_Framework_TestCase { $this->_comp->blockAddress($conn->remoteAddress); - $ret = $this->_comp->onOpen($conn); + $ret = $this->_comp->onOpen($conn); - $this->assertInstanceOf('\\Ratchet\\Resource\\Command\\Action\\CloseConnection', $ret); + $this->assertTrue($conn->last['close']); } public function testAddAndRemoveWithFluentInterfaces() { diff --git a/tests/Ratchet/Tests/Component/WAMP/WAMPServerComponentTest.php b/tests/Ratchet/Tests/Component/WAMP/WAMPServerComponentTest.php index b4f3875..c4dd680 100644 --- a/tests/Ratchet/Tests/Component/WAMP/WAMPServerComponentTest.php +++ b/tests/Ratchet/Tests/Component/WAMP/WAMPServerComponentTest.php @@ -1,8 +1,7 @@ _comp->onOpen($conn); $action = $return->pop(); @@ -155,10 +154,7 @@ class WAMPServerComponentTest extends \PHPUnit_Framework_TestCase { public function testOnErrorPropagation() { $conn = $this->newConn(); - try { - throw new \Exception('Nope'); - } catch (\Exception $e) { - } + $e = new \Exception('Nope'); $this->_comp->onError($conn, $e); diff --git a/tests/Ratchet/Tests/Mock/Connection.php b/tests/Ratchet/Tests/Mock/Connection.php index 47f4da1..03acfb1 100644 --- a/tests/Ratchet/Tests/Mock/Connection.php +++ b/tests/Ratchet/Tests/Mock/Connection.php @@ -4,17 +4,17 @@ use Ratchet\Resource\ConnectionInterface; class Connection implements ConnectionInterface { public $last = array( - 'write' => '' - , 'end' => false + 'send' => '' + , 'close' => false ); public $remoteAddress = '127.0.0.1'; - public function write($data) { + public function send($data) { $this->last[__FUNCTION__] = $data; } - public function end() { + public function close() { $this->last[__FUNCTION__] = true; } } \ No newline at end of file diff --git a/tests/Ratchet/Tests/Mock/ConnectionDecorator.php b/tests/Ratchet/Tests/Mock/ConnectionDecorator.php index 60e0862..f876e67 100644 --- a/tests/Ratchet/Tests/Mock/ConnectionDecorator.php +++ b/tests/Ratchet/Tests/Mock/ConnectionDecorator.php @@ -8,15 +8,15 @@ class ConnectionDecorator extends AbstractConnectionDecorator { , 'end' => false ); - public function write($data) { + public function send($data) { $this->last[__FUNCTION__] = $data; - $this->getConnection()->write($data); + $this->getConnection()->send($data); } - public function end() { + public function close() { $this->last[__FUNCTION__] = true; - $this->getConnection()->end(); + $this->getConnection()->close(); } } \ No newline at end of file diff --git a/tests/Ratchet/Tests/Mock/FakeSocket.php b/tests/Ratchet/Tests/Mock/FakeSocket.php deleted file mode 100644 index 1ef7e63..0000000 --- a/tests/Ratchet/Tests/Mock/FakeSocket.php +++ /dev/null @@ -1,100 +0,0 @@ -_id}"; - } - - public function __toString() { - return (string)$this->_id; - } - - public function __construct($domain = null, $type = null, $protocol = null) { - list($this->_arguments['domain'], $this->_arguments['type'], $this->_arguments['protocol']) = array(1, 1, 1); - } - - public function __clone() { - $this->_id++; - } - - public function deliver($message) { - $this->write($message, strlen($message)); - } - - public function bind($address, $port = 0) { - $this->_last['bind'] = array($address, $port); - return $this; - } - - public function close() { - } - - public function connect($address, $port = 0) { - $this->_last['connect'] = array($address, $port = 0); - return $this; - } - - public function getRemoteAddress() { - return '127.0.0.1'; - } - - public function get_option($level, $optname) { - return $this->_options[$level][$optname]; - } - - public function listen($backlog = 0) { - $this->_last['listen'] = array($backlog); - return $this; - } - - public function read($length, $type = PHP_BINARY_READ) { - $this->_last['read'] = array($length, $type); - return 0; - } - - public function recv(&$buf, $len, $flags) { - $this->_last['recv'] = array($buf, $len, $flags); - return 0; - } - - public function select(&$read, &$write, &$except, $tv_sec, $tv_usec = 0) { - $this->_last['select'] = array($read, $write, $except, $tv_sec, $tv_usec); - return 0; - } - - public function set_block() { - return $this; - } - - public function set_nonblock() { - return $this; - } - - public function set_option($level, $optname, $optval) { - if (!isset($this->_options[$level])) { - $this->_options[$level] = array(); - } - - $this->_options[$level][$optname] = $optval; - } - - public function shutdown($how = 2) { - $this->_last['shutdown'] = array($how); - return $this; - } - - public function write($buffer, $length = 0) { - $this->_last['write'] = array($buffer, $length); - return $this; - } -} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Resource/Command/CompositeTest.php b/tests/Ratchet/Tests/Resource/Command/CompositeTest.php index 1febbd8..9f0e278 100644 --- a/tests/Ratchet/Tests/Resource/Command/CompositeTest.php +++ b/tests/Ratchet/Tests/Resource/Command/CompositeTest.php @@ -1,8 +1,7 @@ _fs = new FakeSocket; - $this->_c = new Connection($this->_fs); - } - - public static function keyAndValProvider() { - return array( - array('hello', 'world') - , array('herp', 'derp') - , array('depth', array('hell', 'yes')) - , array('moar', array('hellz' => 'yes')) - ); - } - - public function testGetSocketReturnsWhatIsSetInConstruct() { - $this->assertSame($this->_fs, $this->_c->getSocket()); - } - - /** - * @dataProvider keyAndValProvider - */ - public function testCanGetWhatIsSet($key, $val) { - $this->_c->{$key} = $val; - $this->assertEquals($val, $this->_c->{$key}); - } - - /** - * @dataProvider keyAndValProvider - */ - public function testIssetWorksOnOverloadedVariables($key, $val) { - $this->_c->{$key} = $val; - $this->assertTrue(isset($this->_c->{$key})); - } - - /** - * @dataProvider keyAndValProvider - */ - public function testUnsetMakesIssetReturnFalse($key, $val) { - $this->_c->{$key} = $val; - unset($this->_c->{$key}); - $this->assertFalse(isset($this->_c->{$key})); - } -} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Resource/Socket/BSDSocketTest.php b/tests/Ratchet/Tests/Resource/Socket/BSDSocketTest.php deleted file mode 100644 index a7ac510..0000000 --- a/tests/Ratchet/Tests/Resource/Socket/BSDSocketTest.php +++ /dev/null @@ -1,68 +0,0 @@ -getMethod($name); - $method->setAccessible(true); - - return $method; - } - - public function setUp() { - $this->_socket = new Socket(); - } - - /* (1): I may or may not re-enable this test (need to add code back to FakeSocket), not sure if I'll keep this feature at all - public function testGetDefaultConfigForConstruct() { - $ref_conf = static::getMethod('getConfig'); - $config = $ref_conf->invokeArgs($this->_socket, array()); - - $this->assertEquals(array_values(Socket::$_defaults), $config); - } - /**/ - - public function testInvalidConstructorArguments() { - $this->setExpectedException('\\Ratchet\\Resource\\Socket\\BSDSocketException'); - $socket = new RealSocket('invalid', 'param', 'derp'); - } - - public function testConstructAndCallByOpenAndClose() { - $socket = new RealSocket(); - $socket->close(); - } - - public function asArrayProvider() { - return array( - array(array('hello' => 'world'), array('hello' => 'world')) - , array(null, null) - , array(array('hello' => 'world'), new \ArrayObject(array('hello' => 'world'))) - ); - } - - /** - * (1) - * @dataProvider asArrayProvider - * / - public function testMethodMungforselectReturnsExpectedValues($output, $input) { - $method = static::getMethod('mungForSelect'); - $return = $method->invokeArgs($this->_socket, array($input)); - - $this->assertEquals($return, $output); - } - - public function NOPEtestMethodMungforselectRejectsNonTraversable() { - $this->setExpectedException('\\InvalidArgumentException'); - $method = static::getMethod('mungForSelect'); - $method->invokeArgs($this->_socket, array('I am upset with PHP ATM')); - } - */ -} \ No newline at end of file From f5005d1a4e77bc0662f5037998437008bd2f4a21 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Mon, 7 May 2012 19:20:19 -0400 Subject: [PATCH 06/22] Composer correction --- README.md | 4 ++-- composer.json | 2 +- composer.lock | 9 +++++---- src/Ratchet/Component/WebSocket/WsConnection.php | 1 - 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 752cbaa..739e443 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,8 @@ class Chat implements MessageInterface { } // Run the server application through the WebSocket protocol - $server = new IoServer(new WsServer(new Chat)); - $server->run(8000); + $server = IoServer::factory(new WsServer(new Chat)); + $server->run(); ``` # php chat.php \ No newline at end of file diff --git a/composer.json b/composer.json index 3088f92..bd40aa3 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ } } , "source": { - "url": "git@github.com:cboden/SocketServer.git" + "url": "https://github.com/cboden/Ratchet.git" , "type": "git" , "reference": "ratchet" } diff --git a/composer.lock b/composer.lock index 4e5ff35..0e8b37a 100644 --- a/composer.lock +++ b/composer.lock @@ -1,5 +1,5 @@ { - "hash": "ae2788962867b06b14a9e473cdd71ebd", + "hash": "9baa15e7791631e31de9c91ca4acf4b7", "packages": [ { "package": "cboden/react", @@ -8,8 +8,8 @@ }, { "package": "doctrine/common", - "version": "dev-master", - "source-reference": "717ea940ff8fa0854e84a2249edadfb998f91406" + "version": "2.2.x-dev", + "source-reference": "1e0aa60d109c630d19543d999f12e2852ef8f932" }, { "package": "evenement/evenement", @@ -33,7 +33,8 @@ }, { "package": "symfony/validator", - "version": "v2.0.10" + "version": "dev-master", + "source-reference": "dac248b43b62d30023dd9b73ad7e5b7bc1128e5e" } ], "packages-dev": null, diff --git a/src/Ratchet/Component/WebSocket/WsConnection.php b/src/Ratchet/Component/WebSocket/WsConnection.php index a4f9b6c..7bf20ed 100644 --- a/src/Ratchet/Component/WebSocket/WsConnection.php +++ b/src/Ratchet/Component/WebSocket/WsConnection.php @@ -1,7 +1,6 @@ Date: Mon, 7 May 2012 19:27:39 -0400 Subject: [PATCH 07/22] Autoload fix --- composer.json | 8 ++------ composer.lock | 2 +- src/Ratchet/Component/Server/IOServerComponent.php | 7 ++++--- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index bd40aa3..60c709a 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ "psr-0": { "Ratchet\\Tests": "tests" , "Ratchet": "src" + , "React": "vendor/cboden/react/src" } } , "require": { @@ -32,13 +33,8 @@ , "package": { "name": "cboden/react" , "version": "dev-master" - , "autoload": { - "psr-0": { - "React": "src" - } - } , "source": { - "url": "https://github.com/cboden/Ratchet.git" + "url": "git://github.com/cboden/Ratchet.git" , "type": "git" , "reference": "ratchet" } diff --git a/composer.lock b/composer.lock index 0e8b37a..1238ba3 100644 --- a/composer.lock +++ b/composer.lock @@ -1,5 +1,5 @@ { - "hash": "9baa15e7791631e31de9c91ca4acf4b7", + "hash": "3933102e03b75b0fdf6cd460e9d3a808", "packages": [ { "package": "cboden/react", diff --git a/src/Ratchet/Component/Server/IOServerComponent.php b/src/Ratchet/Component/Server/IOServerComponent.php index 2ba7109..04d50ca 100644 --- a/src/Ratchet/Component/Server/IOServerComponent.php +++ b/src/Ratchet/Component/Server/IOServerComponent.php @@ -11,9 +11,10 @@ use React\Socket\Server as Reactor; * Creates an open-ended socket to listen on a port for incomming connections. Events are delegated through this to attached applications */ class IOServerComponent { - protected $loop; - - protected $connections; + /** + * @var React\EventLoop\LoopInterface + */ + public $loop; public function __construct(MessageComponentInterface $app, ServerInterface $socket, LoopInterface $loop) { $this->loop = $loop; From bbea3e8e0555ba6c494991785e98bad0bee96dc5 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Mon, 7 May 2012 19:37:55 -0400 Subject: [PATCH 08/22] CI fix (last time :-|) --- composer.json | 2 +- composer.lock | 9 ++--- .../Component/WAMP/Resource/Connection.php | 28 -------------- src/Ratchet/Component/WAMP/WampConnection.php | 37 +++++++++++++++++++ 4 files changed, 42 insertions(+), 34 deletions(-) delete mode 100644 src/Ratchet/Component/WAMP/Resource/Connection.php create mode 100644 src/Ratchet/Component/WAMP/WampConnection.php diff --git a/composer.json b/composer.json index 60c709a..fed04e5 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "name": "cboden/react" , "version": "dev-master" , "source": { - "url": "git://github.com/cboden/Ratchet.git" + "url": "git://github.com/cboden/SocketServer.git" , "type": "git" , "reference": "ratchet" } diff --git a/composer.lock b/composer.lock index 1238ba3..2726ed5 100644 --- a/composer.lock +++ b/composer.lock @@ -1,5 +1,5 @@ { - "hash": "3933102e03b75b0fdf6cd460e9d3a808", + "hash": "bd02fb0517b1805dc483bbb064341ced", "packages": [ { "package": "cboden/react", @@ -8,8 +8,8 @@ }, { "package": "doctrine/common", - "version": "2.2.x-dev", - "source-reference": "1e0aa60d109c630d19543d999f12e2852ef8f932" + "version": "dev-master", + "source-reference": "717ea940ff8fa0854e84a2249edadfb998f91406" }, { "package": "evenement/evenement", @@ -33,8 +33,7 @@ }, { "package": "symfony/validator", - "version": "dev-master", - "source-reference": "dac248b43b62d30023dd9b73ad7e5b7bc1128e5e" + "version": "v2.0.10" } ], "packages-dev": null, diff --git a/src/Ratchet/Component/WAMP/Resource/Connection.php b/src/Ratchet/Component/WAMP/Resource/Connection.php deleted file mode 100644 index 4bff525..0000000 --- a/src/Ratchet/Component/WAMP/Resource/Connection.php +++ /dev/null @@ -1,28 +0,0 @@ -WAMP = new \StdClass; + $this->WAMP->sessionId = uniqid(); + $this->WAMP->prefixes = array(); + + $this->getConnection()->send(json_encode(array(WAMP::MSG_WELCOME, $this->WAMP->sessionId, 1, \Ratchet\Resource\VERSION))); + } + + public function callResponse() { + } + + public function callError() { + } + + public function event() { + } + + public function addPrefix($curie, $uri) { + } + + public function send($data) { + $this->getConnection()->send($data); + } + + public function close() { + $this->getConnection()->close(); + } +} \ No newline at end of file From d9bc1af385bc44a28404b7f652ea5c999ae78cf2 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Mon, 7 May 2012 20:59:47 -0400 Subject: [PATCH 09/22] [WAMP] Cleanup Removed all Command classes (WAMP and global) We-wrote WAMP unit tests to match refs #22 --- .../Component/Server/IpBlackListComponent.php | 10 +- .../Component/WAMP/WAMPServerComponent.php | 111 ++++-------------- src/Ratchet/Component/WAMP/WampConnection.php | 63 ++++++++-- .../WebSocket/WebSocketComponent.php | 4 +- .../Command/Action/ActionInterface.php | 20 ---- .../Command/Action/ActionTemplate.php | 18 --- .../Command/Action/CloseConnection.php | 31 ----- src/Ratchet/Resource/Command/Action/Null.php | 11 -- .../Resource/Command/Action/Runtime.php | 31 ----- .../Resource/Command/Action/SendMessage.php | 43 ------- .../Resource/Command/CommandInterface.php | 16 --- src/Ratchet/Resource/Command/Composite.php | 47 -------- src/Ratchet/Resource/Command/Factory.php | 82 ------------- .../WAMP/Command/Action/CallErrorTest.php | 72 ------------ .../WAMP/Command/Action/CallResultTest.php | 46 -------- .../WAMP/Command/Action/EventTest.php | 0 .../WAMP/WAMPServerComponentTest.php | 96 ++++++++------- .../Component/WAMP/WampConnectionTest.php | 67 +++++++++++ .../Command/Action/SendMessageTest.php | 22 ---- .../Tests/Resource/Command/CompositeTest.php | 63 ---------- 20 files changed, 208 insertions(+), 645 deletions(-) delete mode 100644 src/Ratchet/Resource/Command/Action/ActionInterface.php delete mode 100644 src/Ratchet/Resource/Command/Action/ActionTemplate.php delete mode 100644 src/Ratchet/Resource/Command/Action/CloseConnection.php delete mode 100644 src/Ratchet/Resource/Command/Action/Null.php delete mode 100644 src/Ratchet/Resource/Command/Action/Runtime.php delete mode 100644 src/Ratchet/Resource/Command/Action/SendMessage.php delete mode 100644 src/Ratchet/Resource/Command/CommandInterface.php delete mode 100644 src/Ratchet/Resource/Command/Composite.php delete mode 100644 src/Ratchet/Resource/Command/Factory.php delete mode 100644 tests/Ratchet/Tests/Component/WAMP/Command/Action/CallErrorTest.php delete mode 100644 tests/Ratchet/Tests/Component/WAMP/Command/Action/CallResultTest.php delete mode 100644 tests/Ratchet/Tests/Component/WAMP/Command/Action/EventTest.php create mode 100644 tests/Ratchet/Tests/Component/WAMP/WampConnectionTest.php delete mode 100644 tests/Ratchet/Tests/Resource/Command/Action/SendMessageTest.php delete mode 100644 tests/Ratchet/Tests/Resource/Command/CompositeTest.php diff --git a/src/Ratchet/Component/Server/IpBlackListComponent.php b/src/Ratchet/Component/Server/IpBlackListComponent.php index ad2e38d..f78f9ad 100644 --- a/src/Ratchet/Component/Server/IpBlackListComponent.php +++ b/src/Ratchet/Component/Server/IpBlackListComponent.php @@ -90,17 +90,17 @@ class IpBlackListComponent implements MessageComponentInterface { * {@inheritdoc} */ function onClose(ConnectionInterface $conn) { - if ($this->isBlocked($conn->remoteAddress)) { - return null; + if (!$this->isBlocked($conn->remoteAddress)) { + $this->_decorating->onClose($conn); } - - return $this->_decorating->onClose($conn); } /** * {@inheritdoc} */ function onError(ConnectionInterface $conn, \Exception $e) { - return $this->_decorating->onError($conn, $e); + if (!$this->isBlocked($conn->remoteAddress)) { + $this->_decorating->onError($conn, $e); + } } } \ No newline at end of file diff --git a/src/Ratchet/Component/WAMP/WAMPServerComponent.php b/src/Ratchet/Component/WAMP/WAMPServerComponent.php index 6e3e353..06e5099 100644 --- a/src/Ratchet/Component/WAMP/WAMPServerComponent.php +++ b/src/Ratchet/Component/WAMP/WAMPServerComponent.php @@ -2,11 +2,6 @@ namespace Ratchet\Component\WAMP; use Ratchet\Component\WebSocket\WebSocketComponentInterface; use Ratchet\Resource\ConnectionInterface; -use Ratchet\Resource\Command\Composite; -use Ratchet\Resource\Command\CommandInterface; -use Ratchet\Resource\Command\Factory as CmdFactory; -use Ratchet\Component\WAMP\Command\Action\Prefix; -use Ratchet\Component\WAMP\Command\Action\Welcome; /** * WebSocket Application Messaging Protocol @@ -45,11 +40,17 @@ class WAMPServerComponent implements WebSocketComponentInterface { protected $_decorating; /** - * Any server to client prefixes are stored here - * They're taxied along with the next outgoing message - * @var Ratchet\Resource\Command\Composite + * @var SplObjectStorage */ - protected $_msg_buffer = null; + protected $connections; + + /** + * @param WAMPServerComponentInterface An class to propagate calls through + */ + public function __construct(WAMPServerComponentInterface $server_component) { + $this->_decorating = $server_component; + $this->connections = new \SplObjectStorage; + } /** * {@inheritdoc} @@ -58,43 +59,14 @@ class WAMPServerComponent implements WebSocketComponentInterface { return 'wamp'; } - /** - * @todo WAMP spec does not say what to do when there is an error with PREFIX... - */ - public function addPrefix(ConnectionInterface $conn, $curie, $uri, $from_server = false) { - // validate uri - // validate curie - - // make sure the curie is shorter than the uri - - $conn->WAMP->prefixes[$curie] = $uri; - - if ($from_server) { - $prefix = new Prefix($conn); - $prefix->setPrefix($curie, $uri); - - $this->_msg_buffer->enqueue($prefix); - } - } - /** * {@inheritdoc} */ public function onOpen(ConnectionInterface $conn) { - $conn->WAMP = new \StdClass; - $conn->WAMP->sessionId = uniqid(); - $conn->WAMP->prefixes = array(); + $decor = new WampConnection($conn); + $this->connections->attach($conn, $decor); - $wamp = $this; - $conn->WAMP->addPrefix = function($curie, $uri) use ($wamp, $conn) { - $wamp->addPrefix($conn, $curie, $uri, true); - }; - - $welcome = new Welcome($conn); - $welcome->setWelcome($conn->WAMP->sessionId, \Ratchet\Resource\VERSION); - $this->_msg_buffer->enqueue($welcome); - - return $this->attachStack($this->_decorating->onOpen($conn)); + $this->_decorating->onOpen($decor); } /** @@ -103,13 +75,16 @@ class WAMPServerComponent implements WebSocketComponentInterface { * @throws JSONException */ public function onMessage(ConnectionInterface $from, $msg) { + $from = $this->connections[$from]; + if (null === ($json = @json_decode($msg, true))) { throw new JSONException; } switch ($json[0]) { case static::MSG_PREFIX: - $ret = $this->addPrefix($from, $json[1], $json[2]); + $from->WAMP->prefixes[$json[1]] = $json[2]; +// $from->WAMP->prefixes($json[1], $json[2]); break; case static::MSG_CALL: @@ -121,74 +96,40 @@ class WAMPServerComponent implements WebSocketComponentInterface { $json = $json[0]; } - $ret = $this->_decorating->onCall($from, $callID, $procURI, $json); + $this->_decorating->onCall($from, $callID, $procURI, $json); break; case static::MSG_SUBSCRIBE: - $ret = $this->_decorating->onSubscribe($from, $this->getUri($from, $json[1])); + $this->_decorating->onSubscribe($from, $from->getUri($json[1])); break; case static::MSG_UNSUBSCRIBE: - $ret = $this->_decorating->onUnSubscribe($from, $this->getUri($from, $json[1])); + $this->_decorating->onUnSubscribe($from, $from->getUri($json[1])); break; case static::MSG_PUBLISH: - $ret = $this->_decorating->onPublish($from, $this->getUri($from, $json[1]), $json[2]); + $this->_decorating->onPublish($from, $from->getUri($json[1]), $json[2]); break; default: throw new Exception('Invalid message type'); } - - return $this->attachStack($ret); - } - - /** - * Get the full request URI from the connection object if a prefix has been established for it - * @param Ratchet\Resource\Connection - * @param ... - * @return string - */ - protected function getUri(ConnectionInterface $conn, $uri) { - return (isset($conn->WAMP->prefixes[$uri]) ? $conn->WAMP->prefixes[$uri] : $uri); - } - - /** - * If the developer's application as set some server-to-client prefixes to be set, - * this method ensures those are taxied to the next outgoing message - * @param Ratchet\Resource\Command\CommandInterface|NULL - * @return Ratchet\Resource\Command\Composite - */ - protected function attachStack(CommandInterface $command = null) { - $stack = $this->_msg_buffer; - $stack->enqueue($command); - - $this->_msg_buffer = new Composite; - - return $stack; - } - - /** - * @param WAMPServerComponentInterface An class to propagate calls through - */ - public function __construct(WAMPServerComponentInterface $server_component) { - CmdFactory::registerActionPath(__NAMESPACE__ . '\\Command\\Action'); - - $this->_decorating = $server_component; - $this->_msg_buffer = new Composite; } /** * {@inheritdoc} */ public function onClose(ConnectionInterface $conn) { - return $this->_decorating->onClose($conn); + $decor = $this->connections[$conn]; + $this->connections->detach($conn); + + $this->_decorating->onClose($decor); } /** * {@inheritdoc} */ public function onError(ConnectionInterface $conn, \Exception $e) { - return $this->_decorating->onError($conn, $e); + return $this->_decorating->onError($this->connections[$conn], $e); } } \ No newline at end of file diff --git a/src/Ratchet/Component/WAMP/WampConnection.php b/src/Ratchet/Component/WAMP/WampConnection.php index fa6f921..e8edc01 100644 --- a/src/Ratchet/Component/WAMP/WampConnection.php +++ b/src/Ratchet/Component/WAMP/WampConnection.php @@ -1,36 +1,83 @@ WAMP = new \StdClass; $this->WAMP->sessionId = uniqid(); $this->WAMP->prefixes = array(); - $this->getConnection()->send(json_encode(array(WAMP::MSG_WELCOME, $this->WAMP->sessionId, 1, \Ratchet\Resource\VERSION))); + $this->send(json_encode(array(WAMP::MSG_WELCOME, $this->WAMP->sessionId, 1, \Ratchet\Resource\VERSION))); } - public function callResponse() { + /** + * @param string The unique ID given by the client to respond to + * @param array An array of data to return to the client + */ + public function callResult($id, array $data = array()) { + $this->send(json_encode(array(WAMP::MSG_CALL_RESULT, $id, $data))); } - public function callError() { + /** + * @param string The unique ID given by the client to respond to + * @param string The URI given by the client ot respond to + * @param string A developer-oriented description of the error + * @param string|null An optional human readable detail message to send back + */ + public function callError($id, $uri, $desc = '', $details = null) { + $data = array(WAMP::MSG_CALL_ERROR, $id, $uri, $desc); + + if (null !== $details) { + $data[] = $details; + } + + $this->send(json_encode($data)); } - public function event() { + /** + * @param string The URI or CURIE to broadcast to + * @param mixed Data to send with the event. Anything that is json'able + */ + public function event($uri, $msg) { + $this->send(json_encode(array(WAMP::MSG_EVENT, $uri, $msg))); } - public function addPrefix($curie, $uri) { + /** + * @param string + * @param string + */ + public function prefix($curie, $uri) { + $this->WAMP->prefixes[$curie] = $uri; + $this->send(json_encode(array(WAMP::MSG_PREFIX, $curie, $uri))); } + /** + * Get the full request URI from the connection object if a prefix has been established for it + * @param string + * @return string + */ + public function getUri($uri) { + return (isset($this->WAMP->prefixes[$uri]) ? $this->WAMP->prefixes[$uri] : $uri); + } + + /** + * @internal + */ public function send($data) { $this->getConnection()->send($data); } + /** + * {@inheritdoc} + */ public function close() { $this->getConnection()->close(); } diff --git a/src/Ratchet/Component/WebSocket/WebSocketComponent.php b/src/Ratchet/Component/WebSocket/WebSocketComponent.php index 1cdbdd6..03a5ab1 100644 --- a/src/Ratchet/Component/WebSocket/WebSocketComponent.php +++ b/src/Ratchet/Component/WebSocket/WebSocketComponent.php @@ -138,8 +138,10 @@ class WebSocketComponent implements MessageComponentInterface { // WS::onOpen is not called when the socket connects, it's call when the handshake is done // The socket could close before WS calls onOpen, so we need to check if we've "opened" it for the developer yet if ($this->connections->contains($conn)) { - $this->_decorating->onClose($this->connections[$conn]); + $decor = $this->connections[$conn]; $this->connections->detach($conn); + + $this->_decorating->onClose($decor); } } diff --git a/src/Ratchet/Resource/Command/Action/ActionInterface.php b/src/Ratchet/Resource/Command/Action/ActionInterface.php deleted file mode 100644 index c5d982e..0000000 --- a/src/Ratchet/Resource/Command/Action/ActionInterface.php +++ /dev/null @@ -1,20 +0,0 @@ -_conn = $conn; - } - - public function getConnection() { - return $this->_conn; - } -} \ No newline at end of file diff --git a/src/Ratchet/Resource/Command/Action/CloseConnection.php b/src/Ratchet/Resource/Command/Action/CloseConnection.php deleted file mode 100644 index 6966a89..0000000 --- a/src/Ratchet/Resource/Command/Action/CloseConnection.php +++ /dev/null @@ -1,31 +0,0 @@ -onClose($this->getConnection()); - - if ($ret instanceof CommandInterface) { - $comp = new Composite; - $comp->enqueue($ret); - - $rt = new Runtime($this->getConnection()); - $rt->setCommand(function(ConnectionInterface $conn, ComponentInterface $scope) { - $conn->getSocket()->close(); - }); - $comp->enqueue($rt); - - return $comp; - } - - $this->getConnection()->getSocket()->close(); - } -} \ No newline at end of file diff --git a/src/Ratchet/Resource/Command/Action/Null.php b/src/Ratchet/Resource/Command/Action/Null.php deleted file mode 100644 index 0b8df4e..0000000 --- a/src/Ratchet/Resource/Command/Action/Null.php +++ /dev/null @@ -1,11 +0,0 @@ -_command = $callback; - } - - /** - * {@inheritdoc} - */ - public function execute(ComponentInterface $scope = null) { - $cmd = $this->_command; - - return $cmd($this->getConnection(), $scope); - } -} \ No newline at end of file diff --git a/src/Ratchet/Resource/Command/Action/SendMessage.php b/src/Ratchet/Resource/Command/Action/SendMessage.php deleted file mode 100644 index 3eca5fe..0000000 --- a/src/Ratchet/Resource/Command/Action/SendMessage.php +++ /dev/null @@ -1,43 +0,0 @@ -_message = (string)$msg; - return $this; - } - - /** - * Get the message from setMessage() - * @return string - */ - public function getMessage() { - return $this->_message; - } - - /** - * {@inheritdoc} - * @throws \UnexpectedValueException if a message was not set with setMessage() - */ - public function execute(ComponentInterface $scope = null) { - if (empty($this->_message)) { - throw new \UnexpectedValueException("Message is empty"); - } - - $this->getConnection()->getSocket()->deliver($this->_message); - } -} \ No newline at end of file diff --git a/src/Ratchet/Resource/Command/CommandInterface.php b/src/Ratchet/Resource/Command/CommandInterface.php deleted file mode 100644 index 5ea31c6..0000000 --- a/src/Ratchet/Resource/Command/CommandInterface.php +++ /dev/null @@ -1,16 +0,0 @@ -enqueue($cmd); - } - - return; - } - - parent::enqueue($command); - } - - /** - * {@inheritdoc} - */ - public function execute(ComponentInterface $scope = null) { - $this->setIteratorMode(static::IT_MODE_DELETE); - - $recursive = new self; - - foreach ($this as $command) { - $recursive->enqueue($command->execute($scope)); - } - - if (count($recursive) > 0) { - return $recursive; - } - } -} \ No newline at end of file diff --git a/src/Ratchet/Resource/Command/Factory.php b/src/Ratchet/Resource/Command/Factory.php deleted file mode 100644 index ebd2cc8..0000000 --- a/src/Ratchet/Resource/Command/Factory.php +++ /dev/null @@ -1,82 +0,0 @@ -addActionPath(__NAMESPACE__ . '\\Action'); - $this->_ignoreGlobals = (boolean)$ignoreGlobals; - } - - /** - * Add a new namespace of which CommandInterfaces reside under to autoload with $this->newCommand() - * @param string - */ - public function addActionPath($namespace) { - $this->_paths[] = $this->slashIt($namespace); - } - - public static function registerActionPath($namespace) { - static::$globalPaths[$namespace] = 1; - } - - /** - * @return Composite - */ - public function newComposite() { - return new Composite; - } - - /** - * @param string - * @return CommandInterface - * @throws UnexpectedValueException - */ - public function newCommand($name, ConnectionInterface $conn) { - if (isset($this->_mapped_commands[$name])) { - $cmd = $this->_mapped_commands[$name]; - return new $cmd($conn); - } - - foreach ($this->_paths as $path) { - if (class_exists($path . $name)) { - $this->_mapped_commands[$name] = $path . $name; - return $this->newCommand($name, $conn); - } - } - - if (false === $this->_ignoreGlobals) { - foreach (static::$globalPaths as $path => $one) { - $path = $this->slashIt($path); - if (class_exists($path . $name)) { - $this->_mapped_commands[$name] = $path . $name; - return $this->newCommand($name, $conn); - } - } - } - - throw new \UnexepctedValueException("Command {$name} not found"); - } - - /** - * @param string - * @return string - */ - protected function slashIt($ns) { - return (substr($ns, -1) == '\\' ? $ns : $ns . '\\'); - } -} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Component/WAMP/Command/Action/CallErrorTest.php b/tests/Ratchet/Tests/Component/WAMP/Command/Action/CallErrorTest.php deleted file mode 100644 index 5d93349..0000000 --- a/tests/Ratchet/Tests/Component/WAMP/Command/Action/CallErrorTest.php +++ /dev/null @@ -1,72 +0,0 @@ -setError($callId, $uri); - $resultString = $error->getMessage(); - - $this->assertEquals(array(4, $callId, $uri, ''), json_decode($resultString, true)); - } - - public function testDetailedCallError() { - $error = new CallError(new Connection); - - $callId = uniqid(); - $uri = 'http://example.com/end/point'; - $desc = 'beep boop beep'; - $detail = 'Error: Too much awesome'; - - $error->setError($callId, $uri, $desc, $detail); - $resultString = $error->getMessage(); - - $this->assertEquals(array(4, $callId, $uri, $desc, $detail), json_decode($resultString, true)); - } - - public function testGetId() { - $id = uniqid(); - - $error = new CallError(new Connection); - $error->setError($id, 'http://example.com'); - - $this->assertEquals($id, $error->getId()); - } - - public function testGetUri() { - $uri = 'http://example.com/end/point'; - - $error = new CallError(new Connection); - $error->setError(uniqid(), $uri); - - $this->assertEquals($uri, $error->getUri()); - } - - public function testGetDescription() { - $desc = uniqid(); - - $error = new CallError(new Connection); - $error->setError(uniqid(), 'curie', $desc); - - $this->assertEquals($desc, $error->getDescription()); - } - - public function testGetDetails() { - $detail = uniqid(); - - $error = new CallError(new Connection); - $this->assertNull($error->getDetails()); - $error->setError(uniqid(), 'http://socketo.me', 'desc', $detail); - - $this->assertEquals($detail, $error->getDetails()); - } -} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Component/WAMP/Command/Action/CallResultTest.php b/tests/Ratchet/Tests/Component/WAMP/Command/Action/CallResultTest.php deleted file mode 100644 index a931d4b..0000000 --- a/tests/Ratchet/Tests/Component/WAMP/Command/Action/CallResultTest.php +++ /dev/null @@ -1,46 +0,0 @@ - 'world', 'herp' => 'derp'); - - $result->setResult($callId, $data); - $resultString = $result->getMessage(); - - $this->assertEquals(array(3, $callId, $data), json_decode($resultString, true)); - } - - public function testGetId() { - $id = uniqid(); - - $result = new CallResult(new Connection); - $result->setResult($id, array()); - - $this->assertEquals($id, $result->getId()); - } - - public function testGetData() { - $data = array( - 'hello' => 'world' - , 'recursive' => array( - 'the' => 'quick' - , 'brown' => 'fox' - ) - , 'jumps' - ); - - $result = new CallResult(new Connection); - $result->setResult(uniqid(), $data); - - $this->assertEquals($data, $result->getData()); - } -} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Component/WAMP/Command/Action/EventTest.php b/tests/Ratchet/Tests/Component/WAMP/Command/Action/EventTest.php deleted file mode 100644 index e69de29..0000000 diff --git a/tests/Ratchet/Tests/Component/WAMP/WAMPServerComponentTest.php b/tests/Ratchet/Tests/Component/WAMP/WAMPServerComponentTest.php index c4dd680..ae2f01d 100644 --- a/tests/Ratchet/Tests/Component/WAMP/WAMPServerComponentTest.php +++ b/tests/Ratchet/Tests/Component/WAMP/WAMPServerComponentTest.php @@ -1,15 +1,14 @@ setExpectedException('\\Ratchet\\Component\\WAMP\\Exception'); - $this->_comp->onMessage($this->newConn(), json_encode(array($type))); + $conn = $this->newConn(); + $this->_comp->onOpen($conn); + $this->_comp->onMessage($conn, json_encode(array($type))); } - /** - * @covers Ratchet\Component\WAMP\Command\Action\Welcome - */ public function testWelcomeMessage() { - $conn = new Connection(); + $conn = $this->newConn(); - $return = $this->_comp->onOpen($conn); - $action = $return->pop(); - $message = $action->getMessage(); + $this->_comp->onOpen($conn); + + $message = $conn->last['send']; $json = json_decode($message); $this->assertEquals(4, count($json)); @@ -65,7 +63,10 @@ class WAMPServerComponentTest extends \PHPUnit_Framework_TestCase { $uri = 'http://example.com'; $clientMessage = array(5, $uri); - $this->_comp->onMessage($this->newConn(), json_encode($clientMessage)); + $conn = $this->newConn(); + + $this->_comp->onOpen($conn); + $this->_comp->onMessage($conn, json_encode($clientMessage)); $this->assertEquals($uri, $this->_app->last['onSubscribe'][1]); } @@ -74,7 +75,10 @@ class WAMPServerComponentTest extends \PHPUnit_Framework_TestCase { $uri = 'http://example.com/endpoint'; $clientMessage = array(6, $uri); - $this->_comp->onMessage($this->newConn(), json_encode($clientMessage)); + $conn = $this->newConn(); + + $this->_comp->onOpen($conn); + $this->_comp->onMessage($conn, json_encode($clientMessage)); $this->assertEquals($uri, $this->_app->last['onUnSubscribe'][1]); } @@ -103,7 +107,10 @@ class WAMPServerComponentTest extends \PHPUnit_Framework_TestCase { $id = uniqid(); $clientMessage = array_merge(array(2, $id, $uri), $args); - $this->_comp->onMessage($this->newConn(), json_encode($clientMessage)); + $conn = $this->newConn(); + + $this->_comp->onOpen($conn); + $this->_comp->onMessage($conn, json_encode($clientMessage)); $this->assertEquals($id, $this->_app->last['onCall'][1]); $this->assertEquals($uri, $this->_app->last['onCall'][2]); @@ -132,67 +139,68 @@ class WAMPServerComponentTest extends \PHPUnit_Framework_TestCase { /** * @dataProvider eventProvider - * @covers Ratchet\Component\WAMP\Command\Action\Event */ public function testEvent($topic, $payload) { - $event = new Event($this->newConn()); - $event->setEvent($topic, $payload); + $conn = new WampConnection($this->newConn()); + $conn->event($topic, $payload); - $eventString = $event->getMessage(); + $eventString = $conn->last['send']; $this->assertSame(array(8, $topic, $payload), json_decode($eventString, true)); } public function testOnClosePropagation() { - $conn = $this->newConn(); + $conn = new Connection; + $this->_comp->onOpen($conn); $this->_comp->onClose($conn); - $this->assertSame($conn, $this->_app->last['onClose'][0]); + $class = new \ReflectionClass('\\Ratchet\\Component\\WAMP\\WampConnection'); + $method = $class->getMethod('getConnection'); + $method->setAccessible(true); + + $check = $method->invokeArgs($this->_app->last['onClose'][0], array()); + + $this->assertSame($conn, $check); } public function testOnErrorPropagation() { - $conn = $this->newConn(); + $conn = new Connection; $e = new \Exception('Nope'); + $this->_comp->onOpen($conn); $this->_comp->onError($conn, $e); - $this->assertSame($conn, $this->_app->last['onError'][0]); + $class = new \ReflectionClass('\\Ratchet\\Component\\WAMP\\WampConnection'); + $method = $class->getMethod('getConnection'); + $method->setAccessible(true); + + $check = $method->invokeArgs($this->_app->last['onError'][0], array()); + + $this->assertSame($conn, $check); $this->assertSame($e, $this->_app->last['onError'][1]); } - /** - * @covers Ratchet\Component\WAMP\Command\Action\Prefix - */ public function testPrefix() { - $conn = $this->newConn(); + $conn = new WampConnection($this->newConn()); $this->_comp->onOpen($conn); - $shortOut = 'outgoing'; - $longOut = 'http://example.com/outoing'; + $shortIn = 'incoming'; + $longIn = 'http://example.com/incoming/'; - $shortIn = 'incoming'; - $shortIn = 'http://example.com/incoming/'; + $this->_comp->onMessage($conn, json_encode(array(1, $shortIn, $longIn))); - $this->assertTrue(is_callable($conn->WAMP->addPrefix)); - - $cb = $conn->WAMP->addPrefix; - $cb($shortOut, $longOut); - - $return = $this->_comp->onMessage($conn, json_encode(array(1, $shortIn, $shortOut))); - $command = $return->pop(); - - $this->assertInstanceOf('Ratchet\\Component\\WAMP\\Command\\Action\\Prefix', $command); - $this->assertEquals($shortOut, $command->getCurie()); - $this->assertEquals($longOut, $command->getUri()); - - $this->assertEquals(array(1, $shortOut, $longOut), json_decode($command->getMessage())); + $this->assertEquals($longIn, $conn->WAMP->prefixes[$shortIn]); + $this->assertEquals($longIn, $conn->getUri($shortIn)); } public function testMessageMustBeJson() { $this->setExpectedException('\\Ratchet\\Component\\WAMP\\JsonException'); - $this->_comp->onMessage($this->newConn(), 'Hello World!'); + $conn = new Connection; + + $this->_comp->onOpen($conn); + $this->_comp->onMessage($conn, 'Hello World!'); } } \ No newline at end of file diff --git a/tests/Ratchet/Tests/Component/WAMP/WampConnectionTest.php b/tests/Ratchet/Tests/Component/WAMP/WampConnectionTest.php new file mode 100644 index 0000000..b77cfe5 --- /dev/null +++ b/tests/Ratchet/Tests/Component/WAMP/WampConnectionTest.php @@ -0,0 +1,67 @@ + 'world', 'herp' => 'derp'); + + + $decor->callResult($callId, $data); + $resultString = $conn->last['send']; + + $this->assertEquals(array(3, $callId, $data), json_decode($resultString, true)); + } + + public function testCallError() { + $conn = new Connection; + $decor = new WampConnection($conn); + + $callId = uniqid(); + $uri = 'http://example.com/end/point'; + + $decor->callError($callId, $uri); + $resultString = $conn->last['send']; + + $this->assertEquals(array(4, $callId, $uri, ''), json_decode($resultString, true)); + } + + public function testDetailedCallError() { + $conn = new Connection; + $decor = new WampConnection($conn); + + $callId = uniqid(); + $uri = 'http://example.com/end/point'; + $desc = 'beep boop beep'; + $detail = 'Error: Too much awesome'; + + $decor->callError($callId, $uri, $desc, $detail); + $resultString = $conn->last['send']; + + $this->assertEquals(array(4, $callId, $uri, $desc, $detail), json_decode($resultString, true)); + } + + public function testPrefix() { + $conn = new WampConnection(new Connection); + + $shortOut = 'outgoing'; + $longOut = 'http://example.com/outoing'; + + $conn->prefix($shortOut, $longOut); + } + + public function testGetUriWhenNoCurieGiven() { + $conn = new WampConnection(new Connection); + $uri = 'http://example.com/noshort'; + + $this->assertEquals($uri, $conn->getUri($uri)); + } +} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Resource/Command/Action/SendMessageTest.php b/tests/Ratchet/Tests/Resource/Command/Action/SendMessageTest.php deleted file mode 100644 index fca0055..0000000 --- a/tests/Ratchet/Tests/Resource/Command/Action/SendMessageTest.php +++ /dev/null @@ -1,22 +0,0 @@ -assertInstanceOf('\\Ratchet\\Resource\\Command\\Action\\SendMessage', $cmd->setMessage('Hello World!')); - } - - public function testGetMessageMatchesSet() { - $msg = 'The quick brown fox jumps over the lazy dog.'; - $cmd = new SendMessage(new Connection); - $cmd->setMessage($msg); - - $this->assertEquals($msg, $cmd->getMessage()); - } -} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Resource/Command/CompositeTest.php b/tests/Ratchet/Tests/Resource/Command/CompositeTest.php deleted file mode 100644 index 9f0e278..0000000 --- a/tests/Ratchet/Tests/Resource/Command/CompositeTest.php +++ /dev/null @@ -1,63 +0,0 @@ -_comp = new Composite; - } - - protected function newNull() { - return new NullAction(new Connection); - } - - public function testCanEnqueueNull() { - $count = $this->_comp->count(); - - $this->_comp->enqueue(null); - - $this->assertEquals($count, $this->_comp->count()); - } - - public function testEnqueueCommand() { - $count = $this->_comp->count(); - - $this->_comp->enqueue($this->newNull()); - - $this->assertEquals($count + 1, $this->_comp->count()); - } - - public function badEnqueueProviders() { - return array( - array(array()) - , array('string') - ); - } - - /** - * @dataProvider badEnqueueProviders - */ - public function testCanNotPassOtherThings($object) { - $this->setExpectedException('InvalidArgumentException'); - - $this->_comp->enqueue($object); - } - - public function testCompositeComposite() { - $compTwo = new Composite; - $compTwo->enqueue($this->newNull()); - $compTwo->enqueue($this->newNull()); - - $this->_comp->enqueue($this->newNull()); - $this->_comp->enqueue($compTwo); - - $this->assertEquals(3, $this->_comp->count()); - } -} \ No newline at end of file From b537d8c98dde85245b9a61b88e9dec8ea683db27 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Mon, 7 May 2012 21:06:51 -0400 Subject: [PATCH 10/22] [Flash] Removed Command object calls --- src/Ratchet/Component/Server/FlashPolicyComponent.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Ratchet/Component/Server/FlashPolicyComponent.php b/src/Ratchet/Component/Server/FlashPolicyComponent.php index 8510fac..e7031a2 100644 --- a/src/Ratchet/Component/Server/FlashPolicyComponent.php +++ b/src/Ratchet/Component/Server/FlashPolicyComponent.php @@ -2,10 +2,6 @@ namespace Ratchet\Component\Server; use Ratchet\Component\MessageComponentInterface; use Ratchet\Resource\ConnectionInterface; -use Ratchet\Resource\Connection; -use Ratchet\Resource\Command\CommandInterface; -use Ratchet\Resource\Command\Action\SendMessage; -use Ratchet\Resource\Command\Action\CloseConnection; /** * An app to go on a server stack to pass a policy file to a Flash socket @@ -109,10 +105,7 @@ class FlashPolicyComponent implements MessageComponentInterface { $this->_cacheValid = true; } - $cmd = new SendMessage($from); - $cmd->setMessage($this->_cache . "\0"); - - return $cmd; + $from->send($this->_cache . "\0"); } /** @@ -125,7 +118,7 @@ class FlashPolicyComponent implements MessageComponentInterface { * {@inheritdoc} */ public function onError(ConnectionInterface $conn, \Exception $e) { - return new CloseConnection($conn); + $conn->close(); } /** From 13009cf6733cc694ca7846eb9900a0fe0e649880 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 8 May 2012 09:13:47 -0400 Subject: [PATCH 11/22] Guzzle 2.5 --- composer.json | 2 +- composer.lock | 13 ++----------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index fed04e5..61bdc0c 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ } , "require": { "php": ">=5.3.2" - , "guzzle/guzzle": "2.4.*" + , "guzzle/guzzle": "2.5.*" , "symfony/http-foundation": "2.1.*" , "evenement/evenement": "dev-master" , "cboden/react": "dev-master" diff --git a/composer.lock b/composer.lock index 2726ed5..eeb5df7 100644 --- a/composer.lock +++ b/composer.lock @@ -1,16 +1,11 @@ { - "hash": "bd02fb0517b1805dc483bbb064341ced", + "hash": "ce8ef8ec0b9f8fb32084fda8290120f7", "packages": [ { "package": "cboden/react", "version": "dev-master", "source-reference": "ratchet" }, - { - "package": "doctrine/common", - "version": "dev-master", - "source-reference": "717ea940ff8fa0854e84a2249edadfb998f91406" - }, { "package": "evenement/evenement", "version": "dev-master", @@ -18,7 +13,7 @@ }, { "package": "guzzle/guzzle", - "version": "v2.4.1" + "version": "v2.5.0" }, { "package": "symfony/event-dispatcher", @@ -30,10 +25,6 @@ "version": "dev-master", "source-reference": "54c22f4bf8625303503a117dcc68544d3f8ac876", "alias": "2.1.9999999.9999999-dev" - }, - { - "package": "symfony/validator", - "version": "v2.0.10" } ], "packages-dev": null, From ef6e777f31e5ea135cfae401e220b78a55f89adc Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 8 May 2012 12:46:21 -0400 Subject: [PATCH 12/22] Guzzle changes Taking advantage of RequestFactory LSB New tests to make sure Guzzle returns what's expected --- phpunit.xml.dist | 2 +- .../Guzzle/Http/Message/RequestFactory.php | 219 +----------------- .../Http/Message/RequestFactoryTest.php | 67 ++++++ .../WebSocket/Version/RFC6455Test.php | 8 + tests/bootstrap.php | 5 - 5 files changed, 83 insertions(+), 218 deletions(-) create mode 100644 tests/Ratchet/Tests/Component/WebSocket/Guzzle/Http/Message/RequestFactoryTest.php delete mode 100644 tests/bootstrap.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e093f23..78b3128 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -2,7 +2,7 @@ [A-Za-z]+)\s+(?P/.*)\s+(?P\w+)/(?P\d\.\d)\s*$#i', $line, $matches)) { - $method = strtoupper($matches['method']); - $protocol = strtoupper($matches['protocol']); - $path = $matches['path']; - $version = $matches['version']; - $scheme = 'http'; - } else if (strpos($line, ':')) { - list($key, $value) = explode(':', $line, 2); - $key = trim($key); - // Normalize standard HTTP headers - if (in_array(strtolower($key), self::$requestHeaders)) { - $key = str_replace(' ', '-', ucwords(str_replace('-', ' ', $key))); - } - // Headers are case insensitive - $headers->add($key, trim($value)); - } - } - - // Check for the Host header - if (isset($headers['Host'])) { - $host = $headers['Host']; - } - - if (strpos($host, ':')) { - list($host, $port) = array_map('trim', explode(':', $host)); - if ($port == 443) { - $scheme = 'https'; - } - } else { - $port = ''; - } - - // Check for basic authorization - $auth = isset($headers['Authorization']) ? $headers['Authorization'] : ''; - - if ($auth) { - list($type, $data) = explode(' ', $auth); - if (strtolower($type) == 'basic') { - $data = base64_decode($data); - list($user, $pass) = explode(':', $data); - } - } - - // Check if a query is present - $qpos = strpos($path, '?'); - if ($qpos) { - $query = substr($path, $qpos); - $path = substr($path, 0, $qpos); - } - - return array( - 'method' => $method, - 'protocol' => $protocol, - 'protocol_version' => $version, - 'parts' => array( - 'scheme' => $scheme, - 'host' => $host, - 'port' => $port, - 'user' => $user, - 'pass' => $pass, - 'path' => $path, - 'query' => $query - ), - 'headers' => $headers->getAll(), - 'body' => $body - ); - } - - /** - * {@inheritdoc} - */ - public function fromMessage($message) - { - $parsed = $this->parseMessage($message); - - if (!$parsed) { - return false; - } - - $request = $this->fromParts($parsed['method'], $parsed['parts'], - $parsed['headers'], $parsed['body'], $parsed['protocol'], - $parsed['protocol_version']); - - // EntityEnclosingRequest adds an "Expect: 100-Continue" header when - // using a raw request body for PUT or POST requests. This factory - // method should accurately reflect the message, so here we are - // removing the Expect header if one was not supplied in the message. - if (!isset($parsed['headers']['Expect'])) { - $request->removeHeader('Expect'); - } - - return $request; - } - - /** - * {@inheritdoc} - */ - public function fromParts($method, array $parts, $headers = null, $body = null, $protocol = 'HTTP', $protocolVersion = '1.1') - { - return $this->create($method, Url::buildUrl($parts, true), $headers, $body) - ->setProtocolVersion($protocolVersion); - } - - /** - * {@inheritdoc} - */ - public function create($method, $url, $headers = null, $body = null) - { - if ($method != 'POST' && $method != 'PUT' && $method != 'PATCH') { - $c = $this->requestClass; - $request = new $c($method, $url, $headers); - if ($body) { - $request->setBody(EntityBody::factory($body)); - } - } else { - $c = $this->entityEnclosingRequestClass; - $request = new $c($method, $url, $headers); - - if ($body) { - if ($method == 'POST' && (is_array($body) || $body instanceof Collection)) { - $request->addPostFields($body); - } else if (is_resource($body) || $body instanceof EntityBody) { - $request->setBody($body, (string) $request->getHeader('Content-Type')); - } else { - $request->setBody((string) $body, (string) $request->getHeader('Content-Type')); - } - } - - // Fix chunked transfers based on the passed headers - if (isset($headers['Transfer-Encoding']) && $headers['Transfer-Encoding'] == 'chunked') { - $request->removeHeader('Content-Length') - ->setHeader('Transfer-Encoding', 'chunked'); - } + public function create($method, $url, $headers = null, $body = null) { + $c = $this->entityEnclosingRequestClass; + $request = new $c($method, $url, $headers); + if ($body) { + $request->setBody(EntityBody::factory($body)); } return $request; diff --git a/tests/Ratchet/Tests/Component/WebSocket/Guzzle/Http/Message/RequestFactoryTest.php b/tests/Ratchet/Tests/Component/WebSocket/Guzzle/Http/Message/RequestFactoryTest.php new file mode 100644 index 0000000..1bf54e9 --- /dev/null +++ b/tests/Ratchet/Tests/Component/WebSocket/Guzzle/Http/Message/RequestFactoryTest.php @@ -0,0 +1,67 @@ +factory = RequestFactory::getInstance(); + } + + public function testMessageProvider() { + return array( + 'status' => 'GET / HTTP/1.1' + , 'headers' => array( + 'Upgrade' => 'WebSocket' + , 'Connection' => 'Upgrade' + , 'Host' => 'localhost:8000' + , 'Sec-WebSocket-Key1' => '> b3lU Z0 fh f 3+83394 6 (zG4' + , 'Sec-WebSocket-Key2' => ',3Z0X0677 dV-d [159 Z*4' + ) + , 'body' => "123456\r\n\r\n" + ); + } + + public function combineMessage($status, array $headers, $body = '') { + $message = $status . "\r\n"; + + foreach ($headers as $key => $val) { + $message .= "{$key}: {$val}\r\n"; + } + + $message .= "\r\n{$body}"; + + return $message; + } + + public function testExpectedDataFromGuzzleHeaders() { + $parts = $this->testMessageProvider(); + $message = $this->combineMessage($parts['status'], $parts['headers'], $parts['body']); + $object = $this->factory->fromMessage($message); + + foreach ($parts['headers'] as $key => $val) { + $this->assertEquals($val, $object->getHeader($key, true)); + } + } + + public function testExpectedDataFromNonGuzzleHeaders() { + $parts = $this->testMessageProvider(); + $message = $this->combineMessage($parts['status'], $parts['headers'], $parts['body']); + $object = $this->factory->fromMessage($message); + + $this->assertNull($object->getHeader('Nope', true)); + $this->assertNull($object->getHeader('Nope')); + } + + public function testExpectedDataFromNonGuzzleBody() { + $parts = $this->testMessageProvider(); + $message = $this->combineMessage($parts['status'], $parts['headers'], $parts['body']); + $object = $this->factory->fromMessage($message); + + $this->assertEquals($parts['body'], (string)$object->getBody()); + } +} \ No newline at end of file diff --git a/tests/Ratchet/Tests/Component/WebSocket/Version/RFC6455Test.php b/tests/Ratchet/Tests/Component/WebSocket/Version/RFC6455Test.php index 3b22481..b33b9e8 100644 --- a/tests/Ratchet/Tests/Component/WebSocket/Version/RFC6455Test.php +++ b/tests/Ratchet/Tests/Component/WebSocket/Version/RFC6455Test.php @@ -125,4 +125,12 @@ class RFC6455Test extends \PHPUnit_Framework_TestCase { $this->_version->handshake($request); } } + + public function testNewMessage() { + $this->assertInstanceOf('\\Ratchet\\Component\\WebSocket\\Version\\RFC6455\\Message', $this->_version->newMessage()); + } + + public function testNewFrame() { + $this->assertInstanceOf('\\Ratchet\\Component\\WebSocket\\Version\\RFC6455\\Frame', $this->_version->newFrame()); + } } \ No newline at end of file diff --git a/tests/bootstrap.php b/tests/bootstrap.php deleted file mode 100644 index 9c15fdc..0000000 --- a/tests/bootstrap.php +++ /dev/null @@ -1,5 +0,0 @@ - Date: Tue, 8 May 2012 16:33:58 -0400 Subject: [PATCH 13/22] Factory LSB --- src/Ratchet/Component/Server/IOServerComponent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ratchet/Component/Server/IOServerComponent.php b/src/Ratchet/Component/Server/IOServerComponent.php index 04d50ca..234fed5 100644 --- a/src/Ratchet/Component/Server/IOServerComponent.php +++ b/src/Ratchet/Component/Server/IOServerComponent.php @@ -47,7 +47,7 @@ class IOServerComponent { $loop = LoopFactory::create(); $socket = new Reactor($loop); $socket->listen($port, $address); - $server = new self($component, $socket, $loop); + $server = new static($component, $socket, $loop); return $server; } From 4735218aa0fe616dba1daa55fbd800c7b398f962 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 8 May 2012 23:14:28 -0400 Subject: [PATCH 14/22] [BCB] Namespace changes Removed the `Component` namespace Removed the `Resource` namespace Renamed components: `IOServerComponent` => `IoServer` `WebSocketComponent` => `WsServer` `SessionComponent` => `SessionProvider` `WAMPServerComponent` => `WampServer` `IpBlackListComponent` => `IpBlackList` `FlashPolicyComponent` => `FlashPolicy` --- .../AbstractConnectionDecorator.php | 2 +- .../WAMP/Command/Action/CallError.php | 79 ------------------- .../WAMP/Command/Action/CallResult.php | 45 ----------- .../Component/WAMP/Command/Action/Event.php | 19 ----- .../Component/WAMP/Command/Action/Prefix.php | 40 ---------- .../Component/WAMP/Command/Action/Welcome.php | 18 ----- .../{Component => }/ComponentInterface.php | 13 ++- .../{Resource => }/ConnectionInterface.php | 2 +- .../MessageComponentInterface.php | 7 +- .../FlashPolicy.php} | 12 +-- .../{Component => }/Server/IoConnection.php | 8 +- .../IoServer.php} | 8 +- .../IpBlackList.php} | 10 +-- .../Session/Serialize/HandlerInterface.php | 2 +- .../Session/Serialize/PhpBinaryHandler.php | 2 +- .../Session/Serialize/PhpHandler.php | 2 +- .../SessionProvider.php} | 20 ++--- .../Session/Storage/Proxy/VirtualProxy.php | 2 +- .../Session/Storage/VirtualSessionStorage.php | 10 +-- .../{Component/WAMP => Wamp}/Exception.php | 2 +- .../WAMP => Wamp}/JSONException.php | 2 +- .../WAMP => Wamp}/WampConnection.php | 10 +-- .../WampServer.php} | 14 ++-- .../WampServerInterface.php} | 22 +++--- .../Guzzle/Http/Message/RequestFactory.php | 2 +- .../WebSocket/Version/FrameInterface.php | 2 +- .../WebSocket/Version/Hixie76.php | 2 +- .../WebSocket/Version/Hixie76/Frame.php | 4 +- .../WebSocket/Version/Hixie76/Message.php | 8 +- .../WebSocket/Version/HyBi10.php | 2 +- .../WebSocket/Version/MessageInterface.php | 2 +- .../WebSocket/Version/RFC6455.php | 4 +- .../WebSocket/Version/RFC6455/Frame.php | 4 +- .../Version/RFC6455/HandshakeVerifier.php | 2 +- .../WebSocket/Version/RFC6455/Message.php | 6 +- .../WebSocket/Version/VersionInterface.php | 2 +- .../WebSocket/WsConnection.php | 4 +- .../WsServer.php} | 14 ++-- .../WsServerInterface.php} | 6 +- .../AbstractConnectionDecoratorTest.php | 8 +- tests/Ratchet/Tests/Mock/Component.php | 4 +- tests/Ratchet/Tests/Mock/Connection.php | 2 +- .../Tests/Mock/ConnectionDecorator.php | 2 +- tests/Ratchet/Tests/Mock/WAMPComponent.php | 6 +- .../Server/FlashPolicyComponentTest.php | 8 +- .../Server/IpBlackListComponentTest.php | 12 +-- .../Session/Serialize/PhpHandlerTest.php | 6 +- .../Session/SessionComponentTest.php | 20 ++--- .../WAMP => Wamp}/WampConnectionTest.php | 6 +- .../WampServerTest.php} | 26 +++--- .../Http/Message/RequestFactoryTest.php | 6 +- .../WebSocket/Version/Hixie76Test.php | 8 +- .../WebSocket/Version/HyBi10Test.php | 10 +-- .../WebSocket/Version/RFC6455/FrameTest.php | 6 +- .../Version/RFC6455/HandshakeVerifierTest.php | 8 +- .../WebSocket/Version/RFC6455Test.php | 14 ++-- 56 files changed, 179 insertions(+), 388 deletions(-) rename src/Ratchet/{Resource => }/AbstractConnectionDecorator.php (96%) delete mode 100644 src/Ratchet/Component/WAMP/Command/Action/CallError.php delete mode 100644 src/Ratchet/Component/WAMP/Command/Action/CallResult.php delete mode 100644 src/Ratchet/Component/WAMP/Command/Action/Event.php delete mode 100644 src/Ratchet/Component/WAMP/Command/Action/Prefix.php delete mode 100644 src/Ratchet/Component/WAMP/Command/Action/Welcome.php rename src/Ratchet/{Component => }/ComponentInterface.php (66%) rename src/Ratchet/{Resource => }/ConnectionInterface.php (89%) rename src/Ratchet/{Component => }/MessageComponentInterface.php (52%) rename src/Ratchet/{Component/Server/FlashPolicyComponent.php => Server/FlashPolicy.php} (95%) rename src/Ratchet/{Component => }/Server/IoConnection.php (77%) rename src/Ratchet/{Component/Server/IOServerComponent.php => Server/IoServer.php} (91%) rename src/Ratchet/{Component/Server/IpBlackListComponent.php => Server/IpBlackList.php} (90%) rename src/Ratchet/{Component => }/Session/Serialize/HandlerInterface.php (82%) rename src/Ratchet/{Component => }/Session/Serialize/PhpBinaryHandler.php (94%) rename src/Ratchet/{Component => }/Session/Serialize/PhpHandler.php (96%) rename src/Ratchet/{Component/Session/SessionComponent.php => Session/SessionProvider.php} (88%) rename src/Ratchet/{Component => }/Session/Storage/Proxy/VirtualProxy.php (95%) rename src/Ratchet/{Component => }/Session/Storage/VirtualSessionStorage.php (87%) rename src/Ratchet/{Component/WAMP => Wamp}/Exception.php (55%) rename src/Ratchet/{Component/WAMP => Wamp}/JSONException.php (96%) rename src/Ratchet/{Component/WAMP => Wamp}/WampConnection.php (90%) rename src/Ratchet/{Component/WAMP/WAMPServerComponent.php => Wamp/WampServer.php} (89%) rename src/Ratchet/{Component/WAMP/WAMPServerComponentInterface.php => Wamp/WampServerInterface.php} (58%) rename src/Ratchet/{Component => }/WebSocket/Guzzle/Http/Message/RequestFactory.php (89%) rename src/Ratchet/{Component => }/WebSocket/Version/FrameInterface.php (95%) rename src/Ratchet/{Component => }/WebSocket/Version/Hixie76.php (98%) rename src/Ratchet/{Component => }/WebSocket/Version/Hixie76/Frame.php (93%) rename src/Ratchet/{Component => }/WebSocket/Version/Hixie76/Message.php (84%) rename src/Ratchet/{Component => }/WebSocket/Version/HyBi10.php (91%) rename src/Ratchet/{Component => }/WebSocket/Version/MessageInterface.php (92%) rename src/Ratchet/{Component => }/WebSocket/Version/RFC6455.php (97%) rename src/Ratchet/{Component => }/WebSocket/Version/RFC6455/Frame.php (98%) rename src/Ratchet/{Component => }/WebSocket/Version/RFC6455/HandshakeVerifier.php (98%) rename src/Ratchet/{Component => }/WebSocket/Version/RFC6455/Message.php (92%) rename src/Ratchet/{Component => }/WebSocket/Version/VersionInterface.php (97%) rename src/Ratchet/{Component => }/WebSocket/WsConnection.php (85%) rename src/Ratchet/{Component/WebSocket/WebSocketComponent.php => WebSocket/WsServer.php} (95%) rename src/Ratchet/{Component/WebSocket/WebSocketComponentInterface.php => WebSocket/WsServerInterface.php} (62%) rename tests/Ratchet/Tests/{Resource => }/AbstractConnectionDecoratorTest.php (93%) rename tests/Ratchet/Tests/{Component => }/Server/FlashPolicyComponentTest.php (93%) rename tests/Ratchet/Tests/{Component => }/Server/IpBlackListComponentTest.php (85%) rename tests/Ratchet/Tests/{Component => }/Session/Serialize/PhpHandlerTest.php (83%) rename tests/Ratchet/Tests/{Component => }/Session/SessionComponentTest.php (83%) rename tests/Ratchet/Tests/{Component/WAMP => Wamp}/WampConnectionTest.php (93%) rename tests/Ratchet/Tests/{Component/WAMP/WAMPServerComponentTest.php => Wamp/WampServerTest.php} (86%) rename tests/Ratchet/Tests/{Component => }/WebSocket/Guzzle/Http/Message/RequestFactoryTest.php (90%) rename tests/Ratchet/Tests/{Component => }/WebSocket/Version/Hixie76Test.php (82%) rename tests/Ratchet/Tests/{Component => }/WebSocket/Version/HyBi10Test.php (87%) rename tests/Ratchet/Tests/{Component => }/WebSocket/Version/RFC6455/FrameTest.php (98%) rename tests/Ratchet/Tests/{Component => }/WebSocket/Version/RFC6455/HandshakeVerifierTest.php (94%) rename tests/Ratchet/Tests/{Component => }/WebSocket/Version/RFC6455Test.php (88%) diff --git a/src/Ratchet/Resource/AbstractConnectionDecorator.php b/src/Ratchet/AbstractConnectionDecorator.php similarity index 96% rename from src/Ratchet/Resource/AbstractConnectionDecorator.php rename to src/Ratchet/AbstractConnectionDecorator.php index c4ea479..c683fa3 100644 --- a/src/Ratchet/Resource/AbstractConnectionDecorator.php +++ b/src/Ratchet/AbstractConnectionDecorator.php @@ -1,5 +1,5 @@ _id = $callId; - $this->_uri = $uri; - $this->_desc = $desc; - - $data = array(WAMP::MSG_CALL_ERROR, $callId, $uri, $desc); - - if (null !== $details) { - $data[] = $details; - $this->_details = $details; - } - - return $this->setMessage(json_encode($data)); - } - - /** - * @return string|null - */ - public function getId() { - return $this->_id; - } - - /** - * @return string|null - */ - public function getUri() { - return $this->_uri; - } - - /** - * @return string - */ - public function getDescription() { - return $this->_desc; - } - - /** - * @return string|null - */ - public function getDetails() { - return $this->_details; - } -} \ No newline at end of file diff --git a/src/Ratchet/Component/WAMP/Command/Action/CallResult.php b/src/Ratchet/Component/WAMP/Command/Action/CallResult.php deleted file mode 100644 index b65d062..0000000 --- a/src/Ratchet/Component/WAMP/Command/Action/CallResult.php +++ /dev/null @@ -1,45 +0,0 @@ -_id = $callId; - $this->_data = $data; - - return $this->setMessage(json_encode(array(WAMP::MSG_CALL_RESULT, $callId, $data))); - } - - /** - * @return string|null - */ - public function getId() { - return $this->_id; - } - - /** - * @return array|null - */ - public function getData() { - return $this->_data; - } -} \ No newline at end of file diff --git a/src/Ratchet/Component/WAMP/Command/Action/Event.php b/src/Ratchet/Component/WAMP/Command/Action/Event.php deleted file mode 100644 index a26a18d..0000000 --- a/src/Ratchet/Component/WAMP/Command/Action/Event.php +++ /dev/null @@ -1,19 +0,0 @@ -setMessage(json_encode(array(WAMP::MSG_EVENT, $uri, $msg))); - } -} \ No newline at end of file diff --git a/src/Ratchet/Component/WAMP/Command/Action/Prefix.php b/src/Ratchet/Component/WAMP/Command/Action/Prefix.php deleted file mode 100644 index 047c1ea..0000000 --- a/src/Ratchet/Component/WAMP/Command/Action/Prefix.php +++ /dev/null @@ -1,40 +0,0 @@ -_curie = $curie; - $this->_uri = $uri; - - return $this->setMessage(json_encode(array(WAMP::MSG_PREFIX, $curie, $uri))); - } - - /** - * @return string - */ - public function getCurie() { - return $this->_curie; - } - - /** - * @return string - */ - public function getUri() { - return $this->_uri; - } -} diff --git a/src/Ratchet/Component/WAMP/Command/Action/Welcome.php b/src/Ratchet/Component/WAMP/Command/Action/Welcome.php deleted file mode 100644 index c9c8974..0000000 --- a/src/Ratchet/Component/WAMP/Command/Action/Welcome.php +++ /dev/null @@ -1,18 +0,0 @@ -setMessage(json_encode(array(WAMP::MSG_WELCOME, $sessionId, 1, $serverIdent))); - } -} \ No newline at end of file diff --git a/src/Ratchet/Component/ComponentInterface.php b/src/Ratchet/ComponentInterface.php similarity index 66% rename from src/Ratchet/Component/ComponentInterface.php rename to src/Ratchet/ComponentInterface.php index 63ed81c..abebe3f 100644 --- a/src/Ratchet/Component/ComponentInterface.php +++ b/src/Ratchet/ComponentInterface.php @@ -1,6 +1,6 @@ validateDomain($domain)) { @@ -77,7 +77,7 @@ class FlashPolicyComponent implements MessageComponentInterface { * crossdomain.xml. * * @param string - * @return FlashPolicyComponent + * @return FlashPolicy */ public function setSiteControl($permittedCrossDomainPolicies = 'all') { if (!$this->validateSiteControl($permittedCrossDomainPolicies)) { diff --git a/src/Ratchet/Component/Server/IoConnection.php b/src/Ratchet/Server/IoConnection.php similarity index 77% rename from src/Ratchet/Component/Server/IoConnection.php rename to src/Ratchet/Server/IoConnection.php index c14303e..5338435 100644 --- a/src/Ratchet/Component/Server/IoConnection.php +++ b/src/Ratchet/Server/IoConnection.php @@ -1,6 +1,6 @@ conn = $conn; $this->server = $server; } diff --git a/src/Ratchet/Component/Server/IOServerComponent.php b/src/Ratchet/Server/IoServer.php similarity index 91% rename from src/Ratchet/Component/Server/IOServerComponent.php rename to src/Ratchet/Server/IoServer.php index 234fed5..d6dfc80 100644 --- a/src/Ratchet/Component/Server/IOServerComponent.php +++ b/src/Ratchet/Server/IoServer.php @@ -1,7 +1,7 @@ setSaveHandler($handler); diff --git a/src/Ratchet/Component/WAMP/Exception.php b/src/Ratchet/Wamp/Exception.php similarity index 55% rename from src/Ratchet/Component/WAMP/Exception.php rename to src/Ratchet/Wamp/Exception.php index f66097e..9b0ca24 100644 --- a/src/Ratchet/Component/WAMP/Exception.php +++ b/src/Ratchet/Wamp/Exception.php @@ -1,5 +1,5 @@ WAMP->sessionId = uniqid(); $this->WAMP->prefixes = array(); - $this->send(json_encode(array(WAMP::MSG_WELCOME, $this->WAMP->sessionId, 1, \Ratchet\Resource\VERSION))); + $this->send(json_encode(array(WAMP::MSG_WELCOME, $this->WAMP->sessionId, 1, \Ratchet\VERSION))); } /** diff --git a/src/Ratchet/Component/WAMP/WAMPServerComponent.php b/src/Ratchet/Wamp/WampServer.php similarity index 89% rename from src/Ratchet/Component/WAMP/WAMPServerComponent.php rename to src/Ratchet/Wamp/WampServer.php index 06e5099..b80f239 100644 --- a/src/Ratchet/Component/WAMP/WAMPServerComponent.php +++ b/src/Ratchet/Wamp/WampServer.php @@ -1,7 +1,7 @@ _decorating = $server_component; $this->connections = new \SplObjectStorage; } diff --git a/src/Ratchet/Component/WAMP/WAMPServerComponentInterface.php b/src/Ratchet/Wamp/WampServerInterface.php similarity index 58% rename from src/Ratchet/Component/WAMP/WAMPServerComponentInterface.php rename to src/Ratchet/Wamp/WampServerInterface.php index 180ad2a..144fabe 100644 --- a/src/Ratchet/Component/WAMP/WAMPServerComponentInterface.php +++ b/src/Ratchet/Wamp/WampServerInterface.php @@ -1,46 +1,42 @@ 0) { $response->setHeader('Sec-WebSocket-Protocol', implode(',', $agreed_protocols)); } - $response->setHeader('X-Powered-By', \Ratchet\Resource\VERSION); + $response->setHeader('X-Powered-By', \Ratchet\VERSION); $header = (string)$response; $from->send($header); diff --git a/src/Ratchet/Component/WebSocket/WebSocketComponentInterface.php b/src/Ratchet/WebSocket/WsServerInterface.php similarity index 62% rename from src/Ratchet/Component/WebSocket/WebSocketComponentInterface.php rename to src/Ratchet/WebSocket/WsServerInterface.php index 14f70d5..30b9ba4 100644 --- a/src/Ratchet/Component/WebSocket/WebSocketComponentInterface.php +++ b/src/Ratchet/WebSocket/WsServerInterface.php @@ -1,8 +1,8 @@ getMethod('getConnection'); $method->setAccessible(true); @@ -94,7 +94,7 @@ class AbstractConnectionDecoratorTest extends \PHPUnit_Framework_TestCase { } public function testGetConnectionLevel2() { - $class = new \ReflectionClass('\\Ratchet\\Resource\\AbstractConnectionDecorator'); + $class = new \ReflectionClass('\\Ratchet\\AbstractConnectionDecorator'); $method = $class->getMethod('getConnection'); $method->setAccessible(true); diff --git a/tests/Ratchet/Tests/Mock/Component.php b/tests/Ratchet/Tests/Mock/Component.php index bcf0fbb..d0064d0 100644 --- a/tests/Ratchet/Tests/Mock/Component.php +++ b/tests/Ratchet/Tests/Mock/Component.php @@ -1,8 +1,8 @@ _policy = new FlashPolicyComponent(); + $this->_policy = new FlashPolicy(); } public function testPolicyRender() { diff --git a/tests/Ratchet/Tests/Component/Server/IpBlackListComponentTest.php b/tests/Ratchet/Tests/Server/IpBlackListComponentTest.php similarity index 85% rename from tests/Ratchet/Tests/Component/Server/IpBlackListComponentTest.php rename to tests/Ratchet/Tests/Server/IpBlackListComponentTest.php index bd0d5e2..2d1f662 100644 --- a/tests/Ratchet/Tests/Component/Server/IpBlackListComponentTest.php +++ b/tests/Ratchet/Tests/Server/IpBlackListComponentTest.php @@ -1,19 +1,19 @@ _mock = new MockComponent; - $this->_comp = new IpBlackListComponent($this->_mock); + $this->_comp = new IpBlackList($this->_mock); } public function testBlockAndCloseOnOpen() { @@ -86,6 +86,6 @@ class IpBlackListComponentTest extends \PHPUnit_Framework_TestCase { } public function testUnblockingSilentlyFails() { - $this->assertInstanceOf('\\Ratchet\\Component\\Server\\IpBlackListComponent', $this->_comp->unblockAddress('localhost')); + $this->assertInstanceOf('\\Ratchet\\Server\\IpBlackList', $this->_comp->unblockAddress('localhost')); } } \ No newline at end of file diff --git a/tests/Ratchet/Tests/Component/Session/Serialize/PhpHandlerTest.php b/tests/Ratchet/Tests/Session/Serialize/PhpHandlerTest.php similarity index 83% rename from tests/Ratchet/Tests/Component/Session/Serialize/PhpHandlerTest.php rename to tests/Ratchet/Tests/Session/Serialize/PhpHandlerTest.php index 0528817..c8bf0dc 100644 --- a/tests/Ratchet/Tests/Component/Session/Serialize/PhpHandlerTest.php +++ b/tests/Ratchet/Tests/Session/Serialize/PhpHandlerTest.php @@ -1,9 +1,9 @@ markTestSkipped('Dependency of Symfony HttpFoundation failed'); @@ -31,11 +31,11 @@ class SessionComponentTest extends \PHPUnit_Framework_TestCase { * @dataProvider classCaseProvider */ public function testToClassCase($in, $out) { - $ref = new \ReflectionClass('\\Ratchet\\Component\\Session\\SessionComponent'); + $ref = new \ReflectionClass('\\Ratchet\\Session\\SessionProvider'); $method = $ref->getMethod('toClassCase'); $method->setAccessible(true); - $component = new SessionComponent(new MockComponent, new MemorySessionHandler); + $component = new SessionProvider(new MockComponent, new MemorySessionHandler); $this->assertEquals($out, $method->invokeArgs($component, array($in))); } @@ -56,7 +56,7 @@ class SessionComponentTest extends \PHPUnit_Framework_TestCase { $pdo->exec(vsprintf("CREATE TABLE %s (%s VARCHAR(255) PRIMARY KEY, %s TEXT, %s INTEGER)", $dbOptions)); $pdo->prepare(vsprintf("INSERT INTO %s (%s, %s, %s) VALUES (?, ?, ?)", $dbOptions))->execute(array($sessionId, base64_encode('_sf2_attributes|a:2:{s:5:"hello";s:5:"world";s:4:"last";i:1332872102;}_sf2_flashes|a:0:{}'), time())); - $component = new SessionComponent(new MockComponent, new PdoSessionHandler($pdo, $dbOptions), array('auto_start' => 1)); + $component = new SessionProvider(new MockComponent, new PdoSessionHandler($pdo, $dbOptions), array('auto_start' => 1)); $connection = new Connection(); $headers = $this->getMock('Guzzle\\Http\\Message\\Request', array('getCookie'), array('POST', '/', array())); @@ -83,7 +83,7 @@ class SessionComponentTest extends \PHPUnit_Framework_TestCase { } $mock = new MockComponent; - $comp = new SessionComponent($mock, new NullSessionHandler); + $comp = new SessionProvider($mock, new NullSessionHandler); $comp->onOpen($conns[1]); $comp->onOpen($conns[3]); diff --git a/tests/Ratchet/Tests/Component/WAMP/WampConnectionTest.php b/tests/Ratchet/Tests/Wamp/WampConnectionTest.php similarity index 93% rename from tests/Ratchet/Tests/Component/WAMP/WampConnectionTest.php rename to tests/Ratchet/Tests/Wamp/WampConnectionTest.php index b77cfe5..43a1127 100644 --- a/tests/Ratchet/Tests/Component/WAMP/WampConnectionTest.php +++ b/tests/Ratchet/Tests/Wamp/WampConnectionTest.php @@ -1,10 +1,10 @@ _app = new TestComponent; - $this->_comp = new WAMPServerComponent($this->_app); + $this->_comp = new WampServer($this->_app); } protected function newConn() { @@ -38,7 +38,7 @@ class WAMPServerComponentTest extends \PHPUnit_Framework_TestCase { * @dataProvider invalidMessageProvider */ public function testInvalidMessages($type) { - $this->setExpectedException('\\Ratchet\\Component\\WAMP\\Exception'); + $this->setExpectedException('\\Ratchet\\WAMP\\Exception'); $conn = $this->newConn(); $this->_comp->onOpen($conn); @@ -155,7 +155,7 @@ class WAMPServerComponentTest extends \PHPUnit_Framework_TestCase { $this->_comp->onOpen($conn); $this->_comp->onClose($conn); - $class = new \ReflectionClass('\\Ratchet\\Component\\WAMP\\WampConnection'); + $class = new \ReflectionClass('\\Ratchet\\WAMP\\WampConnection'); $method = $class->getMethod('getConnection'); $method->setAccessible(true); @@ -172,7 +172,7 @@ class WAMPServerComponentTest extends \PHPUnit_Framework_TestCase { $this->_comp->onOpen($conn); $this->_comp->onError($conn, $e); - $class = new \ReflectionClass('\\Ratchet\\Component\\WAMP\\WampConnection'); + $class = new \ReflectionClass('\\Ratchet\\WAMP\\WampConnection'); $method = $class->getMethod('getConnection'); $method->setAccessible(true); @@ -196,7 +196,7 @@ class WAMPServerComponentTest extends \PHPUnit_Framework_TestCase { } public function testMessageMustBeJson() { - $this->setExpectedException('\\Ratchet\\Component\\WAMP\\JsonException'); + $this->setExpectedException('\\Ratchet\\WAMP\\JsonException'); $conn = new Connection; diff --git a/tests/Ratchet/Tests/Component/WebSocket/Guzzle/Http/Message/RequestFactoryTest.php b/tests/Ratchet/Tests/WebSocket/Guzzle/Http/Message/RequestFactoryTest.php similarity index 90% rename from tests/Ratchet/Tests/Component/WebSocket/Guzzle/Http/Message/RequestFactoryTest.php rename to tests/Ratchet/Tests/WebSocket/Guzzle/Http/Message/RequestFactoryTest.php index 1bf54e9..01d5df0 100644 --- a/tests/Ratchet/Tests/Component/WebSocket/Guzzle/Http/Message/RequestFactoryTest.php +++ b/tests/Ratchet/Tests/WebSocket/Guzzle/Http/Message/RequestFactoryTest.php @@ -1,9 +1,9 @@ isInstanceOf('\\Ratchet\\Component\\WebSocket\\Version\\VersionInterface'); + $constraint = $this->isInstanceOf('\\Ratchet\\WebSocket\\Version\\VersionInterface'); $this->assertThat($this->_version, $constraint); } diff --git a/tests/Ratchet/Tests/Component/WebSocket/Version/HyBi10Test.php b/tests/Ratchet/Tests/WebSocket/Version/HyBi10Test.php similarity index 87% rename from tests/Ratchet/Tests/Component/WebSocket/Version/HyBi10Test.php rename to tests/Ratchet/Tests/WebSocket/Version/HyBi10Test.php index cac5280..c8ded8b 100644 --- a/tests/Ratchet/Tests/Component/WebSocket/Version/HyBi10Test.php +++ b/tests/Ratchet/Tests/WebSocket/Version/HyBi10Test.php @@ -1,10 +1,10 @@ isInstanceOf('\\Ratchet\\Component\\WebSocket\\Version\\VersionInterface'); + $constraint = $this->isInstanceOf('\\Ratchet\\WebSocket\\Version\\VersionInterface'); $this->assertThat($this->_version, $constraint); } diff --git a/tests/Ratchet/Tests/Component/WebSocket/Version/RFC6455/FrameTest.php b/tests/Ratchet/Tests/WebSocket/Version/RFC6455/FrameTest.php similarity index 98% rename from tests/Ratchet/Tests/Component/WebSocket/Version/RFC6455/FrameTest.php rename to tests/Ratchet/Tests/WebSocket/Version/RFC6455/FrameTest.php index 820bf6c..84352fb 100644 --- a/tests/Ratchet/Tests/Component/WebSocket/Version/RFC6455/FrameTest.php +++ b/tests/Ratchet/Tests/WebSocket/Version/RFC6455/FrameTest.php @@ -1,9 +1,9 @@ isInstanceOf('\\Ratchet\\Component\\WebSocket\\Version\\VersionInterface'); + $constraint = $this->isInstanceOf('\\Ratchet\\WebSocket\\Version\\VersionInterface'); $this->assertThat($this->_version, $constraint); } @@ -127,10 +127,10 @@ class RFC6455Test extends \PHPUnit_Framework_TestCase { } public function testNewMessage() { - $this->assertInstanceOf('\\Ratchet\\Component\\WebSocket\\Version\\RFC6455\\Message', $this->_version->newMessage()); + $this->assertInstanceOf('\\Ratchet\\WebSocket\\Version\\RFC6455\\Message', $this->_version->newMessage()); } public function testNewFrame() { - $this->assertInstanceOf('\\Ratchet\\Component\\WebSocket\\Version\\RFC6455\\Frame', $this->_version->newFrame()); + $this->assertInstanceOf('\\Ratchet\\WebSocket\\Version\\RFC6455\\Frame', $this->_version->newFrame()); } } \ No newline at end of file From 0d592ae875f49ad204ad74f0c5b27ba3819a5ff6 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 8 May 2012 23:19:28 -0400 Subject: [PATCH 15/22] Case sensitiviy fixes --- tests/Ratchet/Tests/Mock/WAMPComponent.php | 2 +- tests/Ratchet/Tests/Wamp/WampServerTest.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Ratchet/Tests/Mock/WAMPComponent.php b/tests/Ratchet/Tests/Mock/WAMPComponent.php index 1b59f30..5e4bdc3 100644 --- a/tests/Ratchet/Tests/Mock/WAMPComponent.php +++ b/tests/Ratchet/Tests/Mock/WAMPComponent.php @@ -3,7 +3,7 @@ namespace Ratchet\Tests\Mock; use Ratchet\Wamp\WampServerInterface; use Ratchet\ConnectionInterface; -class WAMPComponent implements WampServerInterface { +class WampComponent implements WampServerInterface { public $last = array(); public function onCall(ConnectionInterface $conn, $id, $procURI, array $params) { diff --git a/tests/Ratchet/Tests/Wamp/WampServerTest.php b/tests/Ratchet/Tests/Wamp/WampServerTest.php index fb68862..f829859 100644 --- a/tests/Ratchet/Tests/Wamp/WampServerTest.php +++ b/tests/Ratchet/Tests/Wamp/WampServerTest.php @@ -38,7 +38,7 @@ class WampServerTest extends \PHPUnit_Framework_TestCase { * @dataProvider invalidMessageProvider */ public function testInvalidMessages($type) { - $this->setExpectedException('\\Ratchet\\WAMP\\Exception'); + $this->setExpectedException('\\Ratchet\\Wamp\\Exception'); $conn = $this->newConn(); $this->_comp->onOpen($conn); @@ -155,7 +155,7 @@ class WampServerTest extends \PHPUnit_Framework_TestCase { $this->_comp->onOpen($conn); $this->_comp->onClose($conn); - $class = new \ReflectionClass('\\Ratchet\\WAMP\\WampConnection'); + $class = new \ReflectionClass('\\Ratchet\\Wamp\\WampConnection'); $method = $class->getMethod('getConnection'); $method->setAccessible(true); @@ -172,7 +172,7 @@ class WampServerTest extends \PHPUnit_Framework_TestCase { $this->_comp->onOpen($conn); $this->_comp->onError($conn, $e); - $class = new \ReflectionClass('\\Ratchet\\WAMP\\WampConnection'); + $class = new \ReflectionClass('\\Ratchet\\Wamp\\WampConnection'); $method = $class->getMethod('getConnection'); $method->setAccessible(true); @@ -196,7 +196,7 @@ class WampServerTest extends \PHPUnit_Framework_TestCase { } public function testMessageMustBeJson() { - $this->setExpectedException('\\Ratchet\\WAMP\\JsonException'); + $this->setExpectedException('\\Ratchet\\Wamp\\JsonException'); $conn = new Connection; From ce12a977bf6b098de07c88ef485767e98c66fb2e Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Tue, 8 May 2012 23:22:17 -0400 Subject: [PATCH 16/22] Filename case fix --- tests/Ratchet/Tests/Mock/{WAMPComponent.php => WampComponent.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/Ratchet/Tests/Mock/{WAMPComponent.php => WampComponent.php} (100%) diff --git a/tests/Ratchet/Tests/Mock/WAMPComponent.php b/tests/Ratchet/Tests/Mock/WampComponent.php similarity index 100% rename from tests/Ratchet/Tests/Mock/WAMPComponent.php rename to tests/Ratchet/Tests/Mock/WampComponent.php From 01b0ec07636b8b647163425f1d1fb2a00a56ef8b Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Wed, 9 May 2012 12:31:34 -0400 Subject: [PATCH 17/22] [Info] Updated docs and licence --- LICENSE | 20 ++++++++++++++++---- README.md | 9 ++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/LICENSE b/LICENSE index 0423176..36193c8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,19 @@ -Copyright (c) 2011 Chris Boden +Copyright (c) 2011-2012 Chris Boden -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index 739e443..8412356 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,7 @@ #Ratchet A PHP 5.3 (PSR-0) component library for serving sockets and building socket based applications. -Build up your application through simple interfaces using the decorator and command patterns. -Re-use your application without changing any of its code just by combining different components. +Build up your application through simple interfaces and re-use your application without changing any of its code just by combining different components. ##WebSockets @@ -18,7 +17,7 @@ To avoid proxy/firewall blockage it's recommended WebSockets are run on port 80, Note that you can not run two applications (Apache and Ratchet) on the same port, thus the requirement for a separate machine (for now). Cookies from your domain will be passed to the socket server, allowing you to identify users. -Accessing your website's session data in Ratchet requires you to use [Symfony2 HttpFoundation Sessions](http://symfony.com/doc/master/components/http_foundation/sessions.html) on your website. +Accessing your website's session data in Ratchet requires you to use [Symfony2 Sessions](http://symfony.com/doc/master/components/http_foundation/sessions.html) on your website. ### Documentation @@ -69,8 +68,8 @@ class Chat implements MessageInterface { } } - // Run the server application through the WebSocket protocol - $server = IoServer::factory(new WsServer(new Chat)); + // Run the server application through the WebSocket protocol on port 8000 + $server = IoServer::factory(new WsServer(new Chat), 8000); $server->run(); ``` From 3a1ee0313fc7f885b3ed700fa7484c1219cf8fab Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Thu, 10 May 2012 20:06:09 -0400 Subject: [PATCH 18/22] React Packagist deps --- composer.json | 18 ++---------------- composer.lock | 32 +++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/composer.json b/composer.json index 61bdc0c..1ad9eed 100644 --- a/composer.json +++ b/composer.json @@ -24,21 +24,7 @@ "php": ">=5.3.2" , "guzzle/guzzle": "2.5.*" , "symfony/http-foundation": "2.1.*" - , "evenement/evenement": "dev-master" - , "cboden/react": "dev-master" + , "react/event-loop": "dev-master" + , "react/socket": "dev-master" } - , "repositories": [ - { - "type": "package" - , "package": { - "name": "cboden/react" - , "version": "dev-master" - , "source": { - "url": "git://github.com/cboden/SocketServer.git" - , "type": "git" - , "reference": "ratchet" - } - } - } - ] } \ No newline at end of file diff --git a/composer.lock b/composer.lock index eeb5df7..8846011 100644 --- a/composer.lock +++ b/composer.lock @@ -1,11 +1,6 @@ { - "hash": "ce8ef8ec0b9f8fb32084fda8290120f7", + "hash": "b7d2ee4e3fd11f2e9c862b6b2ca2372f", "packages": [ - { - "package": "cboden/react", - "version": "dev-master", - "source-reference": "ratchet" - }, { "package": "evenement/evenement", "version": "dev-master", @@ -15,6 +10,23 @@ "package": "guzzle/guzzle", "version": "v2.5.0" }, + { + "package": "react/event-loop", + "version": "dev-master", + "source-reference": "e9850fe37b04a34cb4d6b59861d3a6c680fb1aa1" + }, + { + "package": "react/socket", + "version": "dev-master", + "source-reference": "a2b7d74eef48f9fec44bf727d19b0385101b62a2" + }, + { + "package": "symfony/event-dispatcher", + "version": "dev-master", + "source-reference": "0c1ae4898196f5e96b79028d8d2f35de4b584659", + "alias-pretty-version": "2.1.x-dev", + "alias-version": "2.1.9999999.9999999-dev" + }, { "package": "symfony/event-dispatcher", "version": "dev-master", @@ -24,7 +36,13 @@ "package": "symfony/http-foundation", "version": "dev-master", "source-reference": "54c22f4bf8625303503a117dcc68544d3f8ac876", - "alias": "2.1.9999999.9999999-dev" + "alias-pretty-version": "2.1.x-dev", + "alias-version": "2.1.9999999.9999999-dev" + }, + { + "package": "symfony/http-foundation", + "version": "dev-master", + "source-reference": "54c22f4bf8625303503a117dcc68544d3f8ac876" } ], "packages-dev": null, From 55e11bac7eb2ea8ee67402fe6c56de2f18d3146f Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Thu, 10 May 2012 22:24:47 -0400 Subject: [PATCH 19/22] [Server] Methods over closures, StreamSelectLoop --- src/Ratchet/Server/IoServer.php | 74 +++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/src/Ratchet/Server/IoServer.php b/src/Ratchet/Server/IoServer.php index d6dfc80..7c80f18 100644 --- a/src/Ratchet/Server/IoServer.php +++ b/src/Ratchet/Server/IoServer.php @@ -6,6 +6,7 @@ use React\EventLoop\LoopInterface; use React\Socket\ServerInterface; use React\EventLoop\Factory as LoopFactory; use React\Socket\Server as Reactor; +use React\EventLoop\StreamSelectLoop; /** * Creates an open-ended socket to listen on a port for incomming connections. Events are delegated through this to attached applications @@ -16,35 +17,39 @@ class IoServer { */ public $loop; + /** + * @var Ratchet\MessageComponentInterface + */ + public $app; + + /** + * Array of React event handlers + * @var array + */ + protected $handlers = array(); + + /** + * @param Ratchet\MessageComponentInterface The Ratchet application stack to host + * @param React\Socket\ServerInterface The React socket server to run the Ratchet application off of + * @param React\EventLoop\LoopInterface The React looper to run the Ratchet application off of + */ public function __construct(MessageComponentInterface $app, ServerInterface $socket, LoopInterface $loop) { $this->loop = $loop; + $this->app = $app; - $that = $this; + $socket->on('connect', array($this, 'handleConnect')); - $socket->on('connect', function($conn) use ($app, $that) { - $decor = new IoConnection($conn, $that); - - $decor->resourceId = (int)$conn->socket; - $decor->remoteAddress = '127.0.0.1'; // todo - - $app->onOpen($decor); - - $conn->on('data', function($data) use ($decor, $app) { - $app->onMessage($decor, $data); - }); - - $conn->on('error', function($e) use ($decor, $app) { - $app->onError($decor, $e); - }); - - $conn->on('end', function() use ($decor, $app) { - $app->onClose($decor); - }); - }); + $this->handlers['data'] = array($this, 'handleData'); + $this->handlers['end'] = array($this, 'handleEnd'); + $this->handlers['error'] = array($this, 'handleError'); } public static function factory(MessageComponentInterface $component, $port = 80, $address = '0.0.0.0') { - $loop = LoopFactory::create(); + // Enable this after we fix a bug with libevent + // $loop = LoopFactory::create(); + + $loop = new StreamSelectLoop; + $socket = new Reactor($loop); $socket->listen($port, $address); $server = new static($component, $socket, $loop); @@ -55,4 +60,29 @@ class IoServer { public function run() { $this->loop->run(); } + + public function handleConnect($conn) { + $conn->decor = new IoConnection($conn, $this); + + $conn->decor->resourceId = (int)$conn->socket; + $conn->decor->remoteAddress = '127.0.0.1'; // todo + + $this->app->onOpen($conn->decor); + + $conn->on('data', $this->handlers['data']); + $conn->on('end', $this->handlers['end']); + $conn->on('error', $this->handlers['error']); + } + + public function handleData($data, $conn) { + $this->app->onMessage($conn->decor, $data); + } + + public function handleEnd($conn) { + $this->app->onClose($conn->decor); + } + + public function handleError(\Exception $e, $conn) { + $this->app->onError($conn->decor, $e); + } } \ No newline at end of file From 710ec2535f5df1ed81d2dcf3b216190a4cb2f3c1 Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Thu, 10 May 2012 23:14:59 -0400 Subject: [PATCH 20/22] [WAMP][BCB] Subscribe protocol compliance --- README.md | 10 +++++----- src/Ratchet/Wamp/WampServer.php | 6 ++++-- src/Ratchet/Wamp/WampServerInterface.php | 2 +- tests/Ratchet/Tests/Mock/WampComponent.php | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8412356..7998e62 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ #Ratchet -A PHP 5.3 (PSR-0) component library for serving sockets and building socket based applications. +A PHP 5.3 (PSR-0) library for serving WebSockets and building socket based applications. Build up your application through simple interfaces and re-use your application without changing any of its code just by combining different components. ##WebSockets -* Supports the RFC6455, HyBi-10, and Hixie76 protocol versions (at the same time) -* Tested on Chrome 18 - 16, Firefox 6 - 8, Safari 5, iOS 4.2, iOS 5 +* Supports the RFC6455, HyBi-10+, and Hixie76 protocol versions (at the same time) +* Tested on Chrome 18 - 16, Firefox 6 - 9, Safari 5, iOS 4.2, iOS 5 ##Requirements @@ -31,7 +31,7 @@ See https://github.com/cboden/Ratchet-examples for some out-of-the-box working d ```php WAMP->prefixes[$json[1]] = $json[2]; -// $from->WAMP->prefixes($json[1], $json[2]); break; case static::MSG_CALL: @@ -108,7 +107,10 @@ class WampServer implements WsServerInterface { break; case static::MSG_PUBLISH: - $this->_decorating->onPublish($from, $from->getUri($json[1]), $json[2]); + $exclude = (array_key_exists(3, $json) ? $json[3] : null); + $eligible = (array_key_exists(4, $json) ? $json[4] : null); + + $this->_decorating->onPublish($from, $from->getUri($json[1]), $json[2], $exclude, $eligible); break; default: diff --git a/src/Ratchet/Wamp/WampServerInterface.php b/src/Ratchet/Wamp/WampServerInterface.php index 144fabe..528d627 100644 --- a/src/Ratchet/Wamp/WampServerInterface.php +++ b/src/Ratchet/Wamp/WampServerInterface.php @@ -38,5 +38,5 @@ interface WampServerInterface extends ComponentInterface { * @param ... * @param string */ - function onPublish(ConnectionInterface $conn, $uri, $event); + function onPublish(ConnectionInterface $conn, $uri, $event, $exclude, $eligible); } \ No newline at end of file diff --git a/tests/Ratchet/Tests/Mock/WampComponent.php b/tests/Ratchet/Tests/Mock/WampComponent.php index 5e4bdc3..8d1460d 100644 --- a/tests/Ratchet/Tests/Mock/WampComponent.php +++ b/tests/Ratchet/Tests/Mock/WampComponent.php @@ -18,7 +18,7 @@ class WampComponent implements WampServerInterface { $this->last[__FUNCTION__] = func_get_args(); } - public function onPublish(ConnectionInterface $conn, $uri, $event) { + public function onPublish(ConnectionInterface $conn, $uri, $event, $exclude, $eligible) { $this->last[__FUNCTION__] = func_get_args(); } From 5f80c291b7dc9690e66d6b8dec1b94af8f51255b Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Fri, 11 May 2012 00:51:11 -0400 Subject: [PATCH 21/22] CS and API docs --- src/Ratchet/AbstractConnectionDecorator.php | 4 ++++ src/Ratchet/ConnectionInterface.php | 4 ++++ src/Ratchet/Server/IoConnection.php | 3 +-- src/Ratchet/Wamp/{JSONException.php => JsonException.php} | 2 +- src/Ratchet/Wamp/WampConnection.php | 2 ++ src/Ratchet/Wamp/WampServer.php | 4 ++-- src/Ratchet/WebSocket/WsConnection.php | 1 + 7 files changed, 15 insertions(+), 5 deletions(-) rename src/Ratchet/Wamp/{JSONException.php => JsonException.php} (95%) diff --git a/src/Ratchet/AbstractConnectionDecorator.php b/src/Ratchet/AbstractConnectionDecorator.php index c683fa3..c85fa32 100644 --- a/src/Ratchet/AbstractConnectionDecorator.php +++ b/src/Ratchet/AbstractConnectionDecorator.php @@ -1,6 +1,10 @@ connections[$from]; if (null === ($json = @json_decode($msg, true))) { - throw new JSONException; + throw new JsonException; } switch ($json[0]) { diff --git a/src/Ratchet/WebSocket/WsConnection.php b/src/Ratchet/WebSocket/WsConnection.php index ce769bc..c0f127b 100644 --- a/src/Ratchet/WebSocket/WsConnection.php +++ b/src/Ratchet/WebSocket/WsConnection.php @@ -3,6 +3,7 @@ namespace Ratchet\WebSocket; use Ratchet\AbstractConnectionDecorator; /** + * {@inheritdoc} * @property stdClass $WebSocket */ class WsConnection extends AbstractConnectionDecorator { From d05cac8b6c4bfa0751722b41d4fc97a88f116bcf Mon Sep 17 00:00:00 2001 From: Chris Boden Date: Fri, 11 May 2012 11:59:18 -0400 Subject: [PATCH 22/22] [Io] Handle Application Exceptions --- src/Ratchet/Server/IoServer.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Ratchet/Server/IoServer.php b/src/Ratchet/Server/IoServer.php index 7c80f18..daf9b12 100644 --- a/src/Ratchet/Server/IoServer.php +++ b/src/Ratchet/Server/IoServer.php @@ -75,11 +75,19 @@ class IoServer { } public function handleData($data, $conn) { - $this->app->onMessage($conn->decor, $data); + try { + $this->app->onMessage($conn->decor, $data); + } catch (\Exception $e) { + $this->handleError($e, $conn); + } } public function handleEnd($conn) { - $this->app->onClose($conn->decor); + try { + $this->app->onClose($conn->decor); + } catch (\Exception $e) { + $this->handleError($e, $conn); + } } public function handleError(\Exception $e, $conn) {