Skip to content

Commit

Permalink
Merge pull request #129 from clue-labs/default-loop
Browse files Browse the repository at this point in the history
Simplify usage by supporting new default loop and new Socket API
  • Loading branch information
mbonneau authored Nov 4, 2021
2 parents 2946751 + 1f9f4d1 commit d32c497
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 74 deletions.
71 changes: 34 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,23 @@ An asynchronous WebSocket client in PHP

#### Usage
Pawl as a standalone app: Connect to an echo server, send a message, display output, close connection:

```php
<?php

require __DIR__ . '/vendor/autoload.php';

\Ratchet\Client\connect('wss://echo.websocket.org:443')->then(function($conn) {
$conn->on('message', function($msg) use ($conn) {
echo "Received: {$msg}\n";
$conn->close();
});
require __DIR__ . '/vendor/autoload.php';

$conn->send('Hello World!');
}, function ($e) {
echo "Could not connect: {$e->getMessage()}\n";
\Ratchet\Client\connect('wss://echo.websocket.org:443')->then(function($conn) {
$conn->on('message', function($msg) use ($conn) {
echo "Received: {$msg}\n";
$conn->close();
});
```

---
$conn->send('Hello World!');
}, function ($e) {
echo "Could not connect: {$e->getMessage()}\n";
});
```

#### Classes

Expand Down Expand Up @@ -57,31 +56,29 @@ A more in-depth example using explicit interfaces: Requesting sub-protocols, and
```php
<?php

require __DIR__ . '/vendor/autoload.php';

$loop = \React\EventLoop\Factory::create();
$reactConnector = new \React\Socket\Connector($loop, [
'dns' => '8.8.8.8',
'timeout' => 10
]);
$connector = new \Ratchet\Client\Connector($loop, $reactConnector);

$connector('ws://127.0.0.1:9000', ['protocol1', 'subprotocol2'], ['Origin' => 'http://localhost'])
->then(function(\Ratchet\Client\WebSocket $conn) {
$conn->on('message', function(\Ratchet\RFC6455\Messaging\MessageInterface $msg) use ($conn) {
echo "Received: {$msg}\n";
$conn->close();
});

$conn->on('close', function($code = null, $reason = null) {
echo "Connection closed ({$code} - {$reason})\n";
});

$conn->send('Hello World!');
}, function(\Exception $e) use ($loop) {
echo "Could not connect: {$e->getMessage()}\n";
$loop->stop();
require __DIR__ . '/vendor/autoload.php';

$reactConnector = new \React\Socket\Connector([
'dns' => '8.8.8.8',
'timeout' => 10
]);
$loop = \React\EventLoop\Loop::get();
$connector = new \Ratchet\Client\Connector($loop, $reactConnector);

$connector('ws://127.0.0.1:9000', ['protocol1', 'subprotocol2'], ['Origin' => 'http://localhost'])
->then(function(\Ratchet\Client\WebSocket $conn) {
$conn->on('message', function(\Ratchet\RFC6455\Messaging\MessageInterface $msg) use ($conn) {
echo "Received: {$msg}\n";
$conn->close();
});

$conn->on('close', function($code = null, $reason = null) {
echo "Connection closed ({$code} - {$reason})\n";
});

$loop->run();
$conn->send('Hello World!');
}, function(\Exception $e) use ($loop) {
echo "Could not connect: {$e->getMessage()}\n";
$loop->stop();
});
```
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
}
, "require": {
"php": ">=5.4"
, "react/socket": "^1.0 || ^0.8 || ^0.7"
, "evenement/evenement": "^3.0 || ^2.0"
, "ratchet/rfc6455": "^0.3"
, "react/socket": "^1.9"
}
, "require-dev": {
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8"
Expand Down
10 changes: 6 additions & 4 deletions src/Connector.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace Ratchet\Client;
use Ratchet\RFC6455\Handshake\ClientNegotiator;
use React\EventLoop\Loop;
use React\EventLoop\LoopInterface;
use React\Socket\ConnectionInterface;
use React\Socket\ConnectorInterface;
Expand All @@ -15,14 +16,15 @@ class Connector {
protected $_secureConnector;
protected $_negotiator;

public function __construct(LoopInterface $loop, ConnectorInterface $connector = null) {
public function __construct(LoopInterface $loop = null, ConnectorInterface $connector = null) {
$this->_loop = $loop ?: Loop::get();

if (null === $connector) {
$connector = new \React\Socket\Connector($loop, [
$connector = new \React\Socket\Connector([
'timeout' => 20
]);
], $this->_loop);
}

$this->_loop = $loop;
$this->_connector = $connector;
$this->_negotiator = new ClientNegotiator;
}
Expand Down
16 changes: 0 additions & 16 deletions src/functions.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<?php
namespace Ratchet\Client;
use React\EventLoop\LoopInterface;
use React\EventLoop\Factory as ReactFactory;
use React\EventLoop\Timer\Timer;

/**
* @param string $url
Expand All @@ -12,22 +10,8 @@
* @return \React\Promise\PromiseInterface<\Ratchet\Client\WebSocket>
*/
function connect($url, array $subProtocols = [], $headers = [], LoopInterface $loop = null) {
$loop = $loop ?: ReactFactory::create();

$connector = new Connector($loop);
$connection = $connector($url, $subProtocols, $headers);

$runHasBeenCalled = false;

$loop->addTimer(Timer::MIN_INTERVAL, function () use (&$runHasBeenCalled) {
$runHasBeenCalled = true;
});

register_shutdown_function(function() use ($loop, &$runHasBeenCalled) {
if (!$runHasBeenCalled) {
$loop->run();
}
});

return $connection;
}
20 changes: 9 additions & 11 deletions tests/autobahn/runner.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@

define('AGENT', 'Pawl/0.3');

$loop = React\EventLoop\Factory::create();

$connFactory = function() use ($loop) {
$connector = new Ratchet\Client\Connector($loop);
$connFactory = function() {
$connector = new Ratchet\Client\Connector();

return function($url) use ($connector) {
return $connector('ws://127.0.0.1:9001' . $url);
Expand All @@ -29,14 +27,14 @@
return $futureNum->promise();
}, function($e) {
echo "Could not connect to test server: {$e->getMessage()}\n";
})->then(function($numOfCases) use ($connector, $loop) {
})->then(function($numOfCases) use ($connector) {
echo "Running {$numOfCases} test cases\n\n";

$allCases = new Deferred;

$i = 0;

$runNextCase = function() use (&$runNextCase, &$i, $numOfCases, $allCases, $connector, $loop) {
$runNextCase = function() use (&$runNextCase, &$i, $numOfCases, $allCases, $connector) {
$i++;

if ($i > (int)$numOfCases->getPayload()) {
Expand All @@ -59,11 +57,11 @@
$runNextCase();

return $allCases->promise();
})->then(function() use ($connector, $loop) {
$connector('/updateReports?agent=' . AGENT)->then(function(WebSocket $conn) use ($loop) {
})->then(function() use ($connector) {
$connector('/updateReports?agent=' . AGENT)->then(function(WebSocket $conn) {
echo "\nDone!\n";
$conn->on('close', [$loop, 'stop']);
$conn->on('close', function () {
\React\EventLoop\Loop::stop();
});
});
});

$loop->run();
15 changes: 13 additions & 2 deletions tests/unit/ConnectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,23 @@

use PHPUnit\Framework\TestCase;
use Ratchet\Client\Connector;
use React\EventLoop\Factory;
use React\EventLoop\Loop;
use React\Promise\RejectedPromise;
use React\Promise\Promise;

class ConnectorTest extends TestCase
{
public function testConstructWithoutLoopAssignsLoopAutomatically()
{
$factory = new Connector();

$ref = new \ReflectionProperty($factory, '_loop');
$ref->setAccessible(true);
$loop = $ref->getValue($factory);

$this->assertInstanceOf('React\EventLoop\LoopInterface', $loop);
}

public function uriDataProvider() {
return [
['ws://127.0.0.1', 'tcp://127.0.0.1:80'],
Expand All @@ -21,7 +32,7 @@ public function uriDataProvider() {
* @dataProvider uriDataProvider
*/
public function testSecureConnectionUsesTlsScheme($uri, $expectedConnectorUri) {
$loop = Factory::create();
$loop = Loop::get();

$connector = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock();

Expand Down
4 changes: 1 addition & 3 deletions tests/unit/RequestUriTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ function uriDataProvider() {
* @dataProvider uriDataProvider
*/
function testGeneratedRequestUri($uri, $expectedRequestUri) {
$loop = Factory::create();

$connector = new Connector($loop);
$connector = new Connector();

$generateRequest = self::getPrivateClassMethod('\Ratchet\Client\Connector', 'generateRequest');
$request = $generateRequest->invokeArgs($connector, [$uri, [], []]);
Expand Down

0 comments on commit d32c497

Please sign in to comment.