Skip to content

Commit

Permalink
Forward compatibility with react/promise 3
Browse files Browse the repository at this point in the history
  • Loading branch information
WyriHaximus committed Jun 13, 2022
1 parent dd3c325 commit 11b168e
Show file tree
Hide file tree
Showing 14 changed files with 168 additions and 140 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
name: PHPUnit (PHP ${{ matrix.php }} on ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-20.04
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
"react/dns": "^1.8",
"react/event-loop": "^1.2",
"react/promise": "^2.6.0 || ^1.2.1",
"react/promise-timer": "^1.8",
"react/promise": "3.x-dev as 2.999.9999",
"react/promise-timer": "1.x-dev as 1.999.999",
"react/stream": "^1.2"
},
"require-dev": {
Expand Down
2 changes: 1 addition & 1 deletion src/DnsConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ function ($_, $reject) use (&$promise, &$resolved, $uri) {
}

// (try to) cancel pending DNS lookup / connection attempt
if ($promise instanceof CancellablePromiseInterface) {
if ($promise instanceof CancellablePromiseInterface || (!\interface_exists('React\Promise\CancellablePromiseInterface') && \method_exists($promise, 'cancel'))) {
// overwrite callback arguments for PHP7+ only, so they do not show
// up in the Exception trace and do not cause a possible cyclic reference.
$_ = $reject = null;
Expand Down
12 changes: 8 additions & 4 deletions src/HappyEyeBallsConnectionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ public function connect()
};
};

$that->resolverPromises[Message::TYPE_AAAA] = $that->resolve(Message::TYPE_AAAA, $reject)->then($lookupResolve(Message::TYPE_AAAA));
$lookupResolveError = function ($type) {
return function ($error) { };
};

$that->resolverPromises[Message::TYPE_AAAA] = $that->resolve(Message::TYPE_AAAA, $reject)->then($lookupResolve(Message::TYPE_AAAA), $lookupResolveError(Message::TYPE_AAAA));
$that->resolverPromises[Message::TYPE_A] = $that->resolve(Message::TYPE_A, $reject)->then(function (array $ips) use ($that, &$timer) {
// happy path: IPv6 has resolved already (or could not resolve), continue with IPv4 addresses
if ($that->resolved[Message::TYPE_AAAA] === true || !$ips) {
Expand All @@ -101,7 +105,7 @@ public function connect()
});

return $deferred->promise();
})->then($lookupResolve(Message::TYPE_A));
})->then($lookupResolve(Message::TYPE_A), $lookupResolveError(Message::TYPE_A));
}, function ($_, $reject) use ($that, &$timer) {
$reject(new \RuntimeException(
'Connection to ' . $that->uri . ' cancelled' . (!$that->connectionPromises ? ' during DNS lookup' : '') . ' (ECONNABORTED)',
Expand Down Expand Up @@ -248,13 +252,13 @@ public function cleanUp()
$this->connectQueue = array();

foreach ($this->connectionPromises as $connectionPromise) {
if ($connectionPromise instanceof CancellablePromiseInterface) {
if ($connectionPromise instanceof CancellablePromiseInterface || (!\interface_exists('React\Promise\CancellablePromiseInterface') && \method_exists($connectionPromise, 'cancel'))) {
$connectionPromise->cancel();
}
}

foreach ($this->resolverPromises as $resolverPromise) {
if ($resolverPromise instanceof CancellablePromiseInterface) {
if ($resolverPromise instanceof CancellablePromiseInterface || (!\interface_exists('React\Promise\CancellablePromiseInterface') && \method_exists($resolverPromise, 'cancel'))) {
$resolverPromise->cancel();
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/SecureConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ public function connect($uri)
)->then(function (ConnectionInterface $connection) use ($context, $encryption, $uri, &$promise, &$connected) {
// (unencrypted) TCP/IP connection succeeded
$connected = true;

if (!$connection instanceof Connection) {
$connection->close();
throw new \UnexpectedValueException('Base connector does not use internal Connection class exposing stream resource');
Expand All @@ -61,7 +60,7 @@ public function connect($uri)
}

// try to enable encryption
return $promise = $encryption->enable($connection)->then(null, function ($error) use ($connection, $uri) {
return $encryption->enable($connection)->then(null, function ($error) use ($connection, $uri) {
// establishing encryption failed => close invalid connection and return error
$connection->close();

Expand Down
2 changes: 1 addition & 1 deletion src/StreamEncryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public function toggleCrypto($socket, Deferred $deferred, $toggle, $method)
\restore_error_handler();

if (true === $result) {
$deferred->resolve();
$deferred->resolve(null);
} else if (false === $result) {
// overwrite callback arguments for PHP7+ only, so they do not show
// up in the Exception trace and do not cause a possible cyclic reference.
Expand Down
38 changes: 19 additions & 19 deletions tests/DnsConnectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,49 +26,49 @@ public function setUpMocks()
public function testPassByResolverIfGivenIp()
{
$this->resolver->expects($this->never())->method('resolve');
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('127.0.0.1:80'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('127.0.0.1:80'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('127.0.0.1:80');
$this->connector->connect('127.0.0.1:80')->then(null, function () {});
}

public function testPassThroughResolverIfGivenHost()
{
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('1.2.3.4')));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=google.com'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=google.com'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('google.com:80');
$this->connector->connect('google.com:80')->then(null, function () {});
}

public function testPassThroughResolverIfGivenHostWhichResolvesToIpv6()
{
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('::1')));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('[::1]:80?hostname=google.com'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('[::1]:80?hostname=google.com'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('google.com:80');
$this->connector->connect('google.com:80')->then(null, function () {});
}

public function testPassByResolverIfGivenCompleteUri()
{
$this->resolver->expects($this->never())->method('resolve');
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://127.0.0.1:80/path?query#fragment'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://127.0.0.1:80/path?query#fragment'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('scheme://127.0.0.1:80/path?query#fragment');
$this->connector->connect('scheme://127.0.0.1:80/path?query#fragment')->then(null, function () {});
}

public function testPassThroughResolverIfGivenCompleteUri()
{
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('1.2.3.4')));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://1.2.3.4:80/path?query&hostname=google.com#fragment'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://1.2.3.4:80/path?query&hostname=google.com#fragment'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('scheme://google.com:80/path?query#fragment');
$this->connector->connect('scheme://google.com:80/path?query#fragment')->then(null, function () {});
}

public function testPassThroughResolverIfGivenExplicitHost()
{
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('1.2.3.4')));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://1.2.3.4:80/?hostname=google.de'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://1.2.3.4:80/?hostname=google.de'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('scheme://google.com:80/?hostname=google.de');
$this->connector->connect('scheme://google.com:80/?hostname=google.de')->then(null, function () {});
}

public function testRejectsImmediatelyIfUriIsInvalid()
Expand Down Expand Up @@ -205,7 +205,7 @@ public function testRejectionExceptionUsesPreviousExceptionIfDnsFails()

public function testCancelDuringDnsCancelsDnsAndDoesNotStartTcpConnection()
{
$pending = new Promise\Promise(function () { }, $this->expectCallableOnce());
$pending = new Promise\Promise(function () { }, function () { });
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('example.com'))->will($this->returnValue($pending));
$this->tcp->expects($this->never())->method('connect');

Expand Down Expand Up @@ -237,7 +237,7 @@ public function testCancelDuringTcpConnectionCancelsTcpConnectionIfGivenIp()

public function testCancelDuringTcpConnectionCancelsTcpConnectionAfterDnsIsResolved()
{
$pending = new Promise\Promise(function () { }, $this->expectCallableOnce());
$pending = new Promise\Promise(function () { }, function () { });
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('example.com'))->willReturn(Promise\resolve('1.2.3.4'));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=example.com'))->willReturn($pending);

Expand Down Expand Up @@ -288,7 +288,7 @@ public function testRejectionDuringDnsLookupShouldNotCreateAnyGarbageReferences(
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('example.com'))->willReturn($dns->promise());
$this->tcp->expects($this->never())->method('connect');

$promise = $this->connector->connect('example.com:80');
$promise = $this->connector->connect('example.com:80')->then(null, function () { });
$dns->reject(new \RuntimeException('DNS failed'));
unset($promise, $dns);

Expand All @@ -309,7 +309,7 @@ public function testRejectionAfterDnsLookupShouldNotCreateAnyGarbageReferences()
$tcp = new Deferred();
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=example.com'))->willReturn($tcp->promise());

$promise = $this->connector->connect('example.com:80');
$promise = $this->connector->connect('example.com:80')->then(null, function () { });
$dns->resolve('1.2.3.4');
$tcp->reject(new \RuntimeException('Connection failed'));
unset($promise, $dns, $tcp);
Expand All @@ -334,7 +334,7 @@ public function testRejectionAfterDnsLookupShouldNotCreateAnyGarbageReferencesAg
});
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=example.com'))->willReturn($tcp->promise());

$promise = $this->connector->connect('example.com:80');
$promise = $this->connector->connect('example.com:80')->then(null, function () { });
$dns->resolve('1.2.3.4');

unset($promise, $dns, $tcp);
Expand All @@ -356,7 +356,7 @@ public function testCancelDuringDnsLookupShouldNotCreateAnyGarbageReferences()
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('example.com'))->willReturn($dns->promise());
$this->tcp->expects($this->never())->method('connect');

$promise = $this->connector->connect('example.com:80');
$promise = $this->connector->connect('example.com:80')->then(null, function () { });

$promise->cancel();
unset($promise, $dns);
Expand All @@ -379,7 +379,7 @@ public function testCancelDuringTcpConnectionShouldNotCreateAnyGarbageReferences
});
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=example.com'))->willReturn($tcp);

$promise = $this->connector->connect('example.com:80');
$promise = $this->connector->connect('example.com:80')->then(function () { }, function () { });
$dns->resolve('1.2.3.4');

$promise->cancel();
Expand Down
Loading

0 comments on commit 11b168e

Please sign in to comment.