Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API documentation for ExecutorInterface #137

Merged
merged 2 commits into from
Jul 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,9 @@ The following example looks up the `IPv6` address for `igor.io`.

```php
$loop = Factory::create();
$executor = new UdpTransportExecutor($loop);
$executor = new UdpTransportExecutor('8.8.8.8:53', $loop);

$executor->query(
'8.8.8.8:53',
new Query($name, Message::TYPE_AAAA, Message::CLASS_IN)
)->then(function (Message $message) {
foreach ($message->answers as $answer) {
Expand All @@ -229,7 +228,7 @@ want to use this in combination with a `TimeoutExecutor` like this:

```php
$executor = new TimeoutExecutor(
new UdpTransportExecutor($loop),
new UdpTransportExecutor($nameserver, $loop),
3.0,
$loop
);
Expand All @@ -242,7 +241,7 @@ combination with a `RetryExecutor` like this:
```php
$executor = new RetryExecutor(
new TimeoutExecutor(
new UdpTransportExecutor($loop),
new UdpTransportExecutor($nameserver, $loop),
3.0,
$loop
)
Expand All @@ -261,7 +260,7 @@ a `CoopExecutor` like this:
$executor = new CoopExecutor(
new RetryExecutor(
new TimeoutExecutor(
new UdpTransportExecutor($loop),
new UdpTransportExecutor($nameserver, $loop),
3.0,
$loop
)
Expand All @@ -284,11 +283,10 @@ use this code:
```php
$hosts = \React\Dns\Config\HostsFile::loadFromPathBlocking();

$executor = new UdpTransportExecutor($loop);
$executor = new UdpTransportExecutor('8.8.8.8:53', $loop);
$executor = new HostsFileExecutor($hosts, $executor);

$executor->query(
'8.8.8.8:53',
new Query('localhost', Message::TYPE_A, Message::CLASS_IN)
);
```
Expand Down
6 changes: 3 additions & 3 deletions examples/91-query-a-and-aaaa.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
require __DIR__ . '/../vendor/autoload.php';

$loop = Factory::create();
$executor = new UdpTransportExecutor($loop);
$executor = new UdpTransportExecutor('8.8.8.8:53', $loop);

$name = isset($argv[1]) ? $argv[1] : 'www.google.com';

$ipv4Query = new Query($name, Message::TYPE_A, Message::CLASS_IN);
$ipv6Query = new Query($name, Message::TYPE_AAAA, Message::CLASS_IN);

$executor->query('8.8.8.8:53', $ipv4Query)->then(function (Message $message) {
$executor->query($ipv4Query)->then(function (Message $message) {
foreach ($message->answers as $answer) {
echo 'IPv4: ' . $answer->data . PHP_EOL;
}
}, 'printf');
$executor->query('8.8.8.8:53', $ipv6Query)->then(function (Message $message) {
$executor->query($ipv6Query)->then(function (Message $message) {
foreach ($message->answers as $answer) {
echo 'IPv6: ' . $answer->data . PHP_EOL;
}
Expand Down
4 changes: 2 additions & 2 deletions examples/92-query-any.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
require __DIR__ . '/../vendor/autoload.php';

$loop = Factory::create();
$executor = new UdpTransportExecutor($loop);
$executor = new UdpTransportExecutor('8.8.8.8:53', $loop);

$name = isset($argv[1]) ? $argv[1] : 'google.com';

$any = new Query($name, Message::TYPE_ANY, Message::CLASS_IN);

$executor->query('8.8.8.8:53', $any)->then(function (Message $message) {
$executor->query($any)->then(function (Message $message) {
foreach ($message->answers as $answer) {
/* @var $answer Record */

Expand Down
8 changes: 4 additions & 4 deletions src/Query/CachingExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,24 @@ public function __construct(ExecutorInterface $executor, CacheInterface $cache)
$this->cache = $cache;
}

public function query($nameserver, Query $query)
public function query(Query $query)
{
$id = $query->name . ':' . $query->type . ':' . $query->class;
$cache = $this->cache;
$that = $this;
$executor = $this->executor;

$pending = $cache->get($id);
return new Promise(function ($resolve, $reject) use ($nameserver, $query, $id, $cache, $executor, &$pending, $that) {
return new Promise(function ($resolve, $reject) use ($query, $id, $cache, $executor, &$pending, $that) {
$pending->then(
function ($message) use ($nameserver, $query, $id, $cache, $executor, &$pending, $that) {
function ($message) use ($query, $id, $cache, $executor, &$pending, $that) {
// return cached response message on cache hit
if ($message !== null) {
return $message;
}

// perform DNS lookup if not already cached
return $pending = $executor->query($nameserver, $query)->then(
return $pending = $executor->query($query)->then(
function (Message $message) use ($cache, $id, $that) {
// DNS response message received => store in cache when not truncated and return
if (!$message->tc) {
Expand Down
6 changes: 3 additions & 3 deletions src/Query/CoopExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
* $executor = new CoopExecutor(
* new RetryExecutor(
* new TimeoutExecutor(
* new UdpTransportExecutor($loop),
* new UdpTransportExecutor($nameserver, $loop),
* 3.0,
* $loop
* )
Expand All @@ -46,7 +46,7 @@ public function __construct(ExecutorInterface $base)
$this->executor = $base;
}

public function query($nameserver, Query $query)
public function query(Query $query)
{
$key = $this->serializeQueryToIdentity($query);
if (isset($this->pending[$key])) {
Expand All @@ -55,7 +55,7 @@ public function query($nameserver, Query $query)
++$this->counts[$key];
} else {
// no such query pending, so start new query and keep reference until it's fulfilled or rejected
$promise = $this->executor->query($nameserver, $query);
$promise = $this->executor->query($query);
$this->pending[$key] = $promise;
$this->counts[$key] = 1;

Expand Down
37 changes: 36 additions & 1 deletion src/Query/ExecutorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,40 @@

interface ExecutorInterface
{
public function query($nameserver, Query $query);
/**
* Executes a query and will return a response message
*
* It returns a Promise which either fulfills with a response
* `React\Dns\Model\Message` on success or rejects with an `Exception` if
* the query is not successful. A response message may indicate an error
* condition in its `rcode`, but this is considered a valid response message.
*
* ```php
* $executor->query($query)->then(
* function (React\Dns\Model\Message $response) {
* // response message successfully received
* var_dump($response->rcode, $response->answers);
* },
* function (Exception $error) {
* // failed to query due to $error
* }
* );
* ```
*
* The returned Promise MUST be implemented in such a way that it can be
* cancelled when it is still pending. Cancelling a pending promise MUST
* reject its value with an Exception. It SHOULD clean up any underlying
* resources and references as applicable.
*
* ```php
* $promise = $executor->query($query);
*
* $promise->cancel();
* ```
*
* @param Query $query
* @return \React\Promise\PromiseInterface<\React\Dns\Model\Message,\Exception>
* resolves with response message on success or rejects with an Exception on error
*/
public function query(Query $query);
}
4 changes: 2 additions & 2 deletions src/Query/HostsFileExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function __construct(HostsFile $hosts, ExecutorInterface $fallback)
$this->fallback = $fallback;
}

public function query($nameserver, Query $query)
public function query(Query $query)
{
if ($query->class === Message::CLASS_IN && ($query->type === Message::TYPE_A || $query->type === Message::TYPE_AAAA)) {
// forward lookup for type A or AAAA
Expand Down Expand Up @@ -61,7 +61,7 @@ public function query($nameserver, Query $query)
}
}

return $this->fallback->query($nameserver, $query);
return $this->fallback->query($query);
}

private function getIpFromHost($host)
Expand Down
12 changes: 6 additions & 6 deletions src/Query/RetryExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ public function __construct(ExecutorInterface $executor, $retries = 2)
$this->retries = $retries;
}

public function query($nameserver, Query $query)
public function query(Query $query)
{
return $this->tryQuery($nameserver, $query, $this->retries);
return $this->tryQuery($query, $this->retries);
}

public function tryQuery($nameserver, Query $query, $retries)
public function tryQuery(Query $query, $retries)
{
$deferred = new Deferred(function () use (&$promise) {
if ($promise instanceof CancellablePromiseInterface) {
Expand All @@ -35,7 +35,7 @@ public function tryQuery($nameserver, Query $query, $retries)
};

$executor = $this->executor;
$errorback = function ($e) use ($deferred, &$promise, $nameserver, $query, $success, &$errorback, &$retries, $executor) {
$errorback = function ($e) use ($deferred, &$promise, $query, $success, &$errorback, &$retries, $executor) {
if (!$e instanceof TimeoutException) {
$errorback = null;
$deferred->reject($e);
Expand All @@ -62,14 +62,14 @@ public function tryQuery($nameserver, Query $query, $retries)
$r->setValue($e, $trace);
} else {
--$retries;
$promise = $executor->query($nameserver, $query)->then(
$promise = $executor->query($query)->then(
$success,
$errorback
);
}
};

$promise = $this->executor->query($nameserver, $query)->then(
$promise = $this->executor->query($query)->then(
$success,
$errorback
);
Expand Down
4 changes: 2 additions & 2 deletions src/Query/TimeoutExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ public function __construct(ExecutorInterface $executor, $timeout, LoopInterface
$this->timeout = $timeout;
}

public function query($nameserver, Query $query)
public function query(Query $query)
{
return Timer\timeout($this->executor->query($nameserver, $query), $this->timeout, $this->loop)->then(null, function ($e) use ($query) {
return Timer\timeout($this->executor->query($query), $this->timeout, $this->loop)->then(null, function ($e) use ($query) {
if ($e instanceof Timer\TimeoutException) {
$e = new TimeoutException(sprintf("DNS query for %s timed out", $query->name), 0, $e);
}
Expand Down
27 changes: 19 additions & 8 deletions src/Query/UdpTransportExecutor.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@
*
* ```php
* $loop = Factory::create();
* $executor = new UdpTransportExecutor($loop);
* $executor = new UdpTransportExecutor('8.8.8.8:53', $loop);
*
* $executor->query(
* '8.8.8.8:53',
* new Query($name, Message::TYPE_AAAA, Message::CLASS_IN)
* )->then(function (Message $message) {
* foreach ($message->answers as $answer) {
Expand All @@ -40,7 +39,7 @@
*
* ```php
* $executor = new TimeoutExecutor(
* new UdpTransportExecutor($loop),
* new UdpTransportExecutor($nameserver, $loop),
* 3.0,
* $loop
* );
Expand All @@ -53,7 +52,7 @@
* ```php
* $executor = new RetryExecutor(
* new TimeoutExecutor(
* new UdpTransportExecutor($loop),
* new UdpTransportExecutor($nameserver, $loop),
* 3.0,
* $loop
* )
Expand All @@ -72,7 +71,7 @@
* $executor = new CoopExecutor(
* new RetryExecutor(
* new TimeoutExecutor(
* new UdpTransportExecutor($loop),
* new UdpTransportExecutor($nameserver, $loop),
* 3.0,
* $loop
* )
Expand All @@ -93,11 +92,12 @@ class UdpTransportExecutor implements ExecutorInterface
private $dumper;

/**
* @param string $nameserver
* @param LoopInterface $loop
* @param null|Parser $parser optional/advanced: DNS protocol parser to use
* @param null|BinaryDumper $dumper optional/advanced: DNS protocol dumper to use
*/
public function __construct(LoopInterface $loop, Parser $parser = null, BinaryDumper $dumper = null)
public function __construct($nameserver, LoopInterface $loop, Parser $parser = null, BinaryDumper $dumper = null)
{
if ($parser === null) {
$parser = new Parser();
Expand All @@ -106,12 +106,23 @@ public function __construct(LoopInterface $loop, Parser $parser = null, BinaryDu
$dumper = new BinaryDumper();
}

if (strpos($nameserver, '[') === false && substr_count($nameserver, ':') >= 2) {
// several colons, but not enclosed in square brackets => enclose IPv6 address in square brackets
$nameserver = '[' . $nameserver . ']';
}

$parts = parse_url('udp://' . $nameserver);
if (!isset($parts['scheme'], $parts['host']) || $parts['scheme'] !== 'udp') {
throw new \InvalidArgumentException('Invalid nameserver address given');
}

$this->nameserver = 'udp://' . $parts['host'] . ':' . (isset($parts['port']) ? $parts['port'] : 53);
$this->loop = $loop;
$this->parser = $parser;
$this->dumper = $dumper;
}

public function query($nameserver, Query $query)
public function query(Query $query)
{
$request = Message::createRequestForQuery($query);

Expand All @@ -123,7 +134,7 @@ public function query($nameserver, Query $query)
}

// UDP connections are instant, so try connection without a loop or timeout
$socket = @\stream_socket_client("udp://$nameserver", $errno, $errstr, 0);
$socket = @\stream_socket_client($this->nameserver, $errno, $errstr, 0);
if ($socket === false) {
return \React\Promise\reject(new \RuntimeException(
'DNS query for ' . $query->name . ' failed: Unable to connect to DNS server (' . $errstr . ')',
Expand Down
Loading