Minor Refactoring

This commit is contained in:
Chris Boden 2011-11-15 08:22:01 -05:00
parent ec607090d6
commit 08db1e6fac
5 changed files with 132 additions and 62 deletions

View File

@ -49,8 +49,6 @@ class App implements ApplicationInterface {
$this->_connections[$host->getResource()] = new Connection($host); $this->_connections[$host->getResource()] = new Connection($host);
$this->_resources[] = $host->getResource(); $this->_resources[] = $host->getResource();
$recv_bytes = 1024;
set_time_limit(0); set_time_limit(0);
ob_implicit_flush(); ob_implicit_flush();
@ -61,64 +59,69 @@ class App implements ApplicationInterface {
$host->listen(); $host->listen();
do { do {
$changed = $this->_resources; $this->loop($host);
try {
$num_changed = $host->select($changed, $write = null, $except = null, null);
} catch (Exception $e) {
// master had a problem?...what to do?
continue;
}
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, $recv_bytes, 0);
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->onRecv($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;
}
}
} while (true); } while (true);
} }
protected function loop(SocketInterface $host, $recv_bytes = 1024) {
$changed = $this->_resources;
try {
$num_changed = $host->select($changed, $write = null, $except = null, 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, $recv_bytes, 0);
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->onRecv($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;
}
}
}
public function onOpen(Connection $conn) { public function onOpen(Connection $conn) {
$new_socket = clone $conn->getSocket(); $new_socket = clone $conn->getSocket();
$new_connection = new Connection($new_socket); $new_connection = new Connection($new_socket);

View File

@ -5,6 +5,9 @@ namespace Ratchet;
* Uses internal php methods to fill an Exception class (no parameters required) * Uses internal php methods to fill an Exception class (no parameters required)
*/ */
class Exception extends \Exception { class Exception extends \Exception {
/**
* @var SocketInterface
*/
protected $_socket; protected $_socket;
public function __construct(SocketInterface $socket) { public function __construct(SocketInterface $socket) {

View File

@ -50,7 +50,7 @@ class Connection {
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public function &__get($name) { public function &__get($name) {
if (!isset($this->_data[$name])) { if (!$this->__isset($name)) {
throw new \InvalidArgumentException("Attribute '{$name}' not found in Connection {$this->getID()}"); throw new \InvalidArgumentException("Attribute '{$name}' not found in Connection {$this->getID()}");
} }
@ -60,4 +60,19 @@ class Connection {
return $this->_data[$name]; return $this->_data[$name];
} }
} }
/**
* @param mixed
* @return bool
*/
public function __isset($name) {
return isset($this->_data[$name]);
}
/**
* @param mixed
*/
public function __unset($name) {
unset($this->_data[$name]);
}
} }

View File

@ -5,18 +5,38 @@ use Ratchet\Tests\Mock\Socket as MockSocket;
use Ratchet\Resource\Connection; use Ratchet\Resource\Connection;
class Application implements ApplicationInterface { class Application implements ApplicationInterface {
public $_app;
public $_conn_open;
public $_conn_recv;
public $_msg_recv;
public $_conn_close;
public $_conn_error;
public $_excep_error;
public function __construct(ApplicationInterface $app = null) { public function __construct(ApplicationInterface $app = null) {
// probably should make this null app
$this->_app = $app;
} }
public function onOpen(Connection $conn) { public function onOpen(Connection $conn) {
$this->_conn_open = $conn;
} }
public function onRecv(Connection $from, $msg) { public function onRecv(Connection $from, $msg) {
$this->_conn_recv = $from;
$this->_msg_recv = $msg;
} }
public function onClose(Connection $conn) { public function onClose(Connection $conn) {
$this->_conn_close = $conn;
} }
public function onError(Connection $conn, \Exception $e) { public function onError(Connection $conn, \Exception $e) {
$this->_conn_error = $conn;
$this->_excep_error = $e;
} }
} }

View File

@ -7,16 +7,28 @@ use Ratchet\Tests\Mock\FakeSocket;
* @covers Ratchet\Resource\Connection * @covers Ratchet\Resource\Connection
*/ */
class ConnectionTest extends \PHPUnit_Framework_TestCase { class ConnectionTest extends \PHPUnit_Framework_TestCase {
protected $_fs;
protected $_c; protected $_c;
public function setUp() { public function setUp() {
$this->_c = new Connection(new FakeSocket); $this->_fs = new FakeSocket;
$this->_c = new Connection($this->_fs);
} }
public function testCanGetWhatIsSet() { public static function keyAndValProvider() {
$key = 'hello'; return array(
$val = 'world'; array('hello', 'world')
);
}
public function testGetSocketReturnsWhatIsSetInConstruct() {
$this->assertSame($this->_fs, $this->_c->getSocket());
}
/**
* @dataProvider keyAndValProvider
*/
public function testCanGetWhatIsSet($key, $val) {
$this->_c->{$key} = $val; $this->_c->{$key} = $val;
$this->assertEquals($val, $this->_c->{$key}); $this->assertEquals($val, $this->_c->{$key});
} }
@ -29,4 +41,21 @@ class ConnectionTest extends \PHPUnit_Framework_TestCase {
public function testLambdaReturnValueOnGet() { public function testLambdaReturnValueOnGet() {
$this->markTestIncomplete(); $this->markTestIncomplete();
} }
/**
* @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}));
}
} }