Skip to content

Commit

Permalink
Merge pull request #264 from clue-labs/connector-signature
Browse files Browse the repository at this point in the history
Update `Connector` signature to take `$context` as first argument
  • Loading branch information
WyriHaximus authored Jul 28, 2021
2 parents 22d3b31 + 1941c6c commit c85158a
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 97 deletions.
44 changes: 28 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -948,12 +948,6 @@ also shares all of their features and implementation details.
If you want to typehint in your higher-level protocol implementation, you SHOULD
use the generic [`ConnectorInterface`](#connectorinterface) instead.

This class takes an optional `LoopInterface|null $loop` parameter that can be used to
pass the event loop instance to use for this object. You can use a `null` value
here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
This value SHOULD NOT be given unless you're sure you want to explicitly use a
given event loop instance.

As of `v1.4.0`, the `Connector` class defaults to using the
[happy eyeballs algorithm](https://en.wikipedia.org/wiki/Happy_Eyeballs) to
automatically connect over IPv4 or IPv6 when a hostname is given.
Expand All @@ -964,7 +958,7 @@ If you want to revert to the old behavior of only doing an IPv4 lookup and
only attempt a single IPv4 connection, you can set up the `Connector` like this:

```php
$connector = new React\Socket\Connector(null, array(
$connector = new React\Socket\Connector(array(
'happy_eyeballs' => false
));
```
Expand All @@ -978,7 +972,7 @@ If you explicitly want to use a custom DNS server (such as a local DNS relay or
a company wide DNS server), you can set up the `Connector` like this:

```php
$connector = new React\Socket\Connector(null, array(
$connector = new React\Socket\Connector(array(
'dns' => '127.0.1.1'
));

Expand All @@ -992,7 +986,7 @@ If you do not want to use a DNS resolver at all and want to connect to IP
addresses only, you can also set up your `Connector` like this:

```php
$connector = new React\Socket\Connector(null, array(
$connector = new React\Socket\Connector(array(
'dns' => false
));

Expand All @@ -1009,7 +1003,7 @@ can also set up your `Connector` like this:
$dnsResolverFactory = new React\Dns\Resolver\Factory();
$resolver = $dnsResolverFactory->createCached('127.0.1.1');

$connector = new React\Socket\Connector(null, array(
$connector = new React\Socket\Connector(array(
'dns' => $resolver
));

Expand All @@ -1024,7 +1018,7 @@ respects your `default_socket_timeout` ini setting (which defaults to 60s).
If you want a custom timeout value, you can simply pass this like this:

```php
$connector = new React\Socket\Connector(null, array(
$connector = new React\Socket\Connector(array(
'timeout' => 10.0
));
```
Expand All @@ -1033,7 +1027,7 @@ Similarly, if you do not want to apply a timeout at all and let the operating
system handle this, you can pass a boolean flag like this:

```php
$connector = new React\Socket\Connector(null, array(
$connector = new React\Socket\Connector(array(
'timeout' => false
));
```
Expand All @@ -1044,7 +1038,7 @@ pass boolean flags like this:

```php
// only allow secure TLS connections
$connector = new React\Socket\Connector(null, array(
$connector = new React\Socket\Connector(array(
'tcp' => false,
'tls' => true,
'unix' => false,
Expand All @@ -1063,7 +1057,7 @@ pass arrays of context options like this:

```php
// allow insecure TLS connections
$connector = new React\Socket\Connector(null, array(
$connector = new React\Socket\Connector(array(
'tcp' => array(
'bindto' => '192.168.0.1:0'
),
Expand All @@ -1084,7 +1078,7 @@ SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you
want to negotiate with the remote side:

```php
$connector = new React\Socket\Connector(null, array(
$connector = new React\Socket\Connector(array(
'tls' => array(
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
)
Expand All @@ -1110,7 +1104,7 @@ $tls = new React\Socket\SecureConnector($tcp);

$unix = new React\Socket\UnixConnector();

$connector = new React\Socket\Connector(null, array(
$connector = new React\Socket\Connector(array(
'tcp' => $tcp,
'tls' => $tls,
'unix' => $unix,
Expand All @@ -1137,6 +1131,24 @@ $connector->connect('google.com:80')->then(function (React\Socket\ConnectionInte
Internally, the `tcp://` and `tls://` connectors will always be wrapped by
`TimeoutConnector`, unless you disable timeouts like in the above example.

This class takes an optional `LoopInterface|null $loop` parameter that can be used to
pass the event loop instance to use for this object. You can use a `null` value
here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
This value SHOULD NOT be given unless you're sure you want to explicitly use a
given event loop instance.

> Changelog v1.9.0: The constructur signature has been updated to take the
> optional `$context` as the first parameter and the optional `$loop` as a second
> argument. The previous signature has been deprecated and should not be used anymore.
>
> ```php
> // constructor signature as of v1.9.0
> $connector = new React\Socket\Connector(array $context = [], ?LoopInterface $loop = null);
>
> // legacy constructor signature before v1.9.0
> $connector = new React\Socket\Connector(?LoopInterface $loop = null, array $context = []);
> ```
### Advanced client usage
#### TcpConnector
Expand Down
109 changes: 72 additions & 37 deletions src/Connector.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use React\Dns\Config\Config as DnsConfig;
use React\Dns\Resolver\Factory as DnsFactory;
use React\Dns\Resolver\ResolverInterface;
use React\EventLoop\Loop;
use React\EventLoop\LoopInterface;

/**
Expand All @@ -16,7 +15,7 @@
* as plaintext TCP/IP, secure TLS or local Unix connection streams.
*
* Under the hood, the `Connector` is implemented as a *higher-level facade*
* or the lower-level connectors implemented in this package. This means it
* for the lower-level connectors implemented in this package. This means it
* also shares all of their features and implementation details.
* If you want to typehint in your higher-level protocol implementation, you SHOULD
* use the generic [`ConnectorInterface`](#connectorinterface) instead.
Expand All @@ -27,11 +26,48 @@ final class Connector implements ConnectorInterface
{
private $connectors = array();

public function __construct(LoopInterface $loop = null, array $options = array())
/**
* Instantiate new `Connector`
*
* ```php
* $connector = new React\Socket\Connector();
* ```
*
* This class takes two optional arguments for more advanced usage:
*
* ```php
* // constructor signature as of v1.9.0
* $connector = new React\Socket\Connector(array $context = [], ?LoopInterface $loop = null);
*
* // legacy constructor signature before v1.9.0
* $connector = new React\Socket\Connector(?LoopInterface $loop = null, array $context = []);
* ```
*
* This class takes an optional `LoopInterface|null $loop` parameter that can be used to
* pass the event loop instance to use for this object. You can use a `null` value
* here in order to use the [default loop](https://github.com/reactphp/event-loop#loop).
* This value SHOULD NOT be given unless you're sure you want to explicitly use a
* given event loop instance.
*
* @param array|LoopInterface|null $context
* @param null|LoopInterface|array $loop
* @throws \InvalidArgumentException for invalid arguments
*/
public function __construct($context = array(), $loop = null)
{
$loop = $loop ?: Loop::get();
// swap arguments for legacy constructor signature
if (($context instanceof LoopInterface || $context === null) && (\func_num_args() <= 1 || \is_array($loop))) {
$swap = $loop === null ? array(): $loop;
$loop = $context;
$context = $swap;
}

if (!\is_array($context) || ($loop !== null && !$loop instanceof LoopInterface)) {
throw new \InvalidArgumentException('Expected "array $context" and "?LoopInterface $loop" arguments');
}

// apply default options if not explicitly given
$options += array(
$context += array(
'tcp' => true,
'tls' => true,
'unix' => true,
Expand All @@ -41,25 +77,25 @@ public function __construct(LoopInterface $loop = null, array $options = array()
'happy_eyeballs' => true,
);

if ($options['timeout'] === true) {
$options['timeout'] = (float)\ini_get("default_socket_timeout");
if ($context['timeout'] === true) {
$context['timeout'] = (float)\ini_get("default_socket_timeout");
}

if ($options['tcp'] instanceof ConnectorInterface) {
$tcp = $options['tcp'];
if ($context['tcp'] instanceof ConnectorInterface) {
$tcp = $context['tcp'];
} else {
$tcp = new TcpConnector(
$loop,
\is_array($options['tcp']) ? $options['tcp'] : array()
\is_array($context['tcp']) ? $context['tcp'] : array()
);
}

if ($options['dns'] !== false) {
if ($options['dns'] instanceof ResolverInterface) {
$resolver = $options['dns'];
if ($context['dns'] !== false) {
if ($context['dns'] instanceof ResolverInterface) {
$resolver = $context['dns'];
} else {
if ($options['dns'] !== true) {
$config = $options['dns'];
if ($context['dns'] !== true) {
$config = $context['dns'];
} else {
// try to load nameservers from system config or default to Google's public DNS
$config = DnsConfig::loadSystemConfigBlocking();
Expand All @@ -75,52 +111,52 @@ public function __construct(LoopInterface $loop = null, array $options = array()
);
}

if ($options['happy_eyeballs'] === true) {
if ($context['happy_eyeballs'] === true) {
$tcp = new HappyEyeBallsConnector($loop, $tcp, $resolver);
} else {
$tcp = new DnsConnector($tcp, $resolver);
}
}

if ($options['tcp'] !== false) {
$options['tcp'] = $tcp;
if ($context['tcp'] !== false) {
$context['tcp'] = $tcp;

if ($options['timeout'] !== false) {
$options['tcp'] = new TimeoutConnector(
$options['tcp'],
$options['timeout'],
if ($context['timeout'] !== false) {
$context['tcp'] = new TimeoutConnector(
$context['tcp'],
$context['timeout'],
$loop
);
}

$this->connectors['tcp'] = $options['tcp'];
$this->connectors['tcp'] = $context['tcp'];
}

if ($options['tls'] !== false) {
if (!$options['tls'] instanceof ConnectorInterface) {
$options['tls'] = new SecureConnector(
if ($context['tls'] !== false) {
if (!$context['tls'] instanceof ConnectorInterface) {
$context['tls'] = new SecureConnector(
$tcp,
$loop,
\is_array($options['tls']) ? $options['tls'] : array()
\is_array($context['tls']) ? $context['tls'] : array()
);
}

if ($options['timeout'] !== false) {
$options['tls'] = new TimeoutConnector(
$options['tls'],
$options['timeout'],
if ($context['timeout'] !== false) {
$context['tls'] = new TimeoutConnector(
$context['tls'],
$context['timeout'],
$loop
);
}

$this->connectors['tls'] = $options['tls'];
$this->connectors['tls'] = $context['tls'];
}

if ($options['unix'] !== false) {
if (!$options['unix'] instanceof ConnectorInterface) {
$options['unix'] = new UnixConnector($loop);
if ($context['unix'] !== false) {
if (!$context['unix'] instanceof ConnectorInterface) {
$context['unix'] = new UnixConnector($loop);
}
$this->connectors['unix'] = $options['unix'];
$this->connectors['unix'] = $context['unix'];
}
}

Expand All @@ -140,4 +176,3 @@ public function connect($uri)
return $this->connectors[$scheme]->connect($uri);
}
}

Loading

0 comments on commit c85158a

Please sign in to comment.