Skip to content

Commit

Permalink
Add TimeoutConnector decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
clue committed Nov 19, 2015
1 parent 5e3c4c6 commit d5b9fd5
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 1 deletion.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,20 @@ $secureConnector->create('www.google.com', 443)->then(function (React\Stream\Str
$loop->run();
```

### Connection timeouts

The `TimeoutConnector` class decorates any given `Connector` instance.
It provides the same `create()` method, but will automatically reject the
underlying connection attempt if it takes too long.

```php
$timeoutConnector = new React\SocketClient\TimeoutConnector($connector, 3.0, $loop);

$timeoutConnector->create('google.com', 80)->then(function (React\Stream\Stream $stream) {
// connection succeeded within 3.0 seconds
});
```

### Unix domain sockets

Similarly, the `UnixConnector` class can be used to connect to Unix domain socket (UDS)
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"react/dns": "0.4.*",
"react/event-loop": "0.4.*",
"react/stream": "0.4.*",
"react/promise": "~2.0"
"react/promise": "~2.0",
"react/promise-timer": "~1.0"
},
"autoload": {
"psr-4": {
Expand Down
26 changes: 26 additions & 0 deletions src/TimeoutConnector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace React\SocketClient;

use React\SocketClient\ConnectorInterface;
use React\EventLoop\LoopInterface;
use React\Promise\Timer;

class TimeoutConnector implements ConnectorInterface
{
private $connector;
private $timeout;
private $loop;

public function __construct(ConnectorInterface $connector, $timeout, LoopInterface $loop)
{
$this->connector = $connector;
$this->timeout = $timeout;
$this->loop = $loop;
}

public function create($host, $port)
{
return Timer\timeout($this->connector->create($host, $port), $this->timeout, $this->loop);
}
}
86 changes: 86 additions & 0 deletions tests/TimeoutConnectorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace React\Tests\SocketClient;

use React\SocketClient\TimeoutConnector;
use React\Promise;
use React\EventLoop\Factory;

class TimeoutConnectorTest extends TestCase
{
public function testRejectsOnTimeout()
{
$promise = new Promise\Promise(function () { });

$connector = $this->getMock('React\SocketClient\ConnectorInterface');
$connector->expects($this->once())->method('create')->with('google.com', 80)->will($this->returnValue($promise));

$loop = Factory::create();

$timeout = new TimeoutConnector($connector, 0.01, $loop);

$timeout->create('google.com', 80)->then(
$this->expectCallableNever(),
$this->expectCallableOnce()
);

$loop->run();
}

public function testRejectsWhenConnectorRejects()
{
$promise = Promise\reject();

$connector = $this->getMock('React\SocketClient\ConnectorInterface');
$connector->expects($this->once())->method('create')->with('google.com', 80)->will($this->returnValue($promise));

$loop = Factory::create();

$timeout = new TimeoutConnector($connector, 5.0, $loop);

$timeout->create('google.com', 80)->then(
$this->expectCallableNever(),
$this->expectCallableOnce()
);

$loop->run();
}

public function testResolvesWhenConnectorResolves()
{
$promise = Promise\resolve();

$connector = $this->getMock('React\SocketClient\ConnectorInterface');
$connector->expects($this->once())->method('create')->with('google.com', 80)->will($this->returnValue($promise));

$loop = Factory::create();

$timeout = new TimeoutConnector($connector, 5.0, $loop);

$timeout->create('google.com', 80)->then(
$this->expectCallableOnce(),
$this->expectCallableNever()
);

$loop->run();
}

public function testRejectsAndCancelsPendingPromiseOnTimeout()
{
$promise = new Promise\Promise(function () { }, $this->expectCallableOnce());

$connector = $this->getMock('React\SocketClient\ConnectorInterface');
$connector->expects($this->once())->method('create')->with('google.com', 80)->will($this->returnValue($promise));

$loop = Factory::create();

$timeout = new TimeoutConnector($connector, 0.01, $loop);

$timeout->create('google.com', 80)->then(
$this->expectCallableNever(),
$this->expectCallableOnce()
);

$loop->run();
}
}

0 comments on commit d5b9fd5

Please sign in to comment.