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

Update DNS Factory to accept complete Config object #179

Merged
merged 1 commit into from
Jun 23, 2021
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: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ names, baby!
$loop = React\EventLoop\Factory::create();

$config = React\Dns\Config\Config::loadSystemConfigBlocking();
$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
if (!$config->nameservers) {
$config->nameservers[] = '8.8.8.8';
}

$factory = new React\Dns\Resolver\Factory();
$dns = $factory->create($server, $loop);
$dns = $factory->create($config, $loop);

$dns->resolve('igor.io')->then(function ($ip) {
echo "Host: $ip\n";
Expand Down Expand Up @@ -73,10 +75,12 @@ You can cache results by configuring the resolver to use a `CachedExecutor`:
$loop = React\EventLoop\Factory::create();

$config = React\Dns\Config\Config::loadSystemConfigBlocking();
$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
if (!$config->nameservers) {
$config->nameservers[] = '8.8.8.8';
}

$factory = new React\Dns\Resolver\Factory();
$dns = $factory->createCached($server, $loop);
$dns = $factory->createCached($config, $loop);

$dns->resolve('igor.io')->then(function ($ip) {
echo "Host: $ip\n";
Expand Down
6 changes: 4 additions & 2 deletions examples/01-one.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
$loop = React\EventLoop\Factory::create();

$config = Config::loadSystemConfigBlocking();
$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
if (!$config->nameservers) {
$config->nameservers[] = '8.8.8.8';
}

$factory = new Factory();
$resolver = $factory->create($server, $loop);
$resolver = $factory->create($config, $loop);

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

Expand Down
6 changes: 4 additions & 2 deletions examples/02-concurrent.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
$loop = React\EventLoop\Factory::create();

$config = Config::loadSystemConfigBlocking();
$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
if (!$config->nameservers) {
$config->nameservers[] = '8.8.8.8';
}

$factory = new Factory();
$resolver = $factory->create($server, $loop);
$resolver = $factory->create($config, $loop);

$names = array_slice($argv, 1);
if (!$names) {
Expand Down
6 changes: 4 additions & 2 deletions examples/03-cached.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
$loop = React\EventLoop\Factory::create();

$config = Config::loadSystemConfigBlocking();
$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
if (!$config->nameservers) {
$config->nameservers[] = '8.8.8.8';
}

$factory = new Factory();
$resolver = $factory->createCached($server, $loop);
$resolver = $factory->createCached($config, $loop);

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

Expand Down
6 changes: 4 additions & 2 deletions examples/11-all-ips.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
$loop = React\EventLoop\Factory::create();

$config = Config::loadSystemConfigBlocking();
$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
if (!$config->nameservers) {
$config->nameservers[] = '8.8.8.8';
}

$factory = new Factory();
$resolver = $factory->create($server, $loop);
$resolver = $factory->create($config, $loop);

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

Expand Down
6 changes: 4 additions & 2 deletions examples/12-all-types.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
$loop = React\EventLoop\Factory::create();

$config = Config::loadSystemConfigBlocking();
$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
if (!$config->nameservers) {
$config->nameservers[] = '8.8.8.8';
}

$factory = new Factory();
$resolver = $factory->create($server, $loop);
$resolver = $factory->create($config, $loop);

$name = isset($argv[1]) ? $argv[1] : 'google.com';
$type = constant('React\Dns\Model\Message::TYPE_' . (isset($argv[2]) ? $argv[2] : 'TXT'));
Expand Down
6 changes: 4 additions & 2 deletions examples/13-reverse-dns.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
$loop = React\EventLoop\Factory::create();

$config = Config::loadSystemConfigBlocking();
$server = $config->nameservers ? reset($config->nameservers) : '8.8.8.8';
if (!$config->nameservers) {
$config->nameservers[] = '8.8.8.8';
}

$factory = new Factory();
$resolver = $factory->create($server, $loop);
$resolver = $factory->create($config, $loop);

$ip = isset($argv[1]) ? $argv[1] : '8.8.8.8';

Expand Down
45 changes: 39 additions & 6 deletions src/Resolver/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use React\Cache\ArrayCache;
use React\Cache\CacheInterface;
use React\Dns\Config\Config;
use React\Dns\Config\HostsFile;
use React\Dns\Query\CachingExecutor;
use React\Dns\Query\CoopExecutor;
Expand All @@ -19,31 +20,49 @@
final class Factory
{
/**
* @param string $nameserver
* Creates a DNS resolver instance for the given DNS config
*
* As of v1.7.0 it's recommended to pass a `Config` object instead of a
* single nameserver address. If the given config contains more than one DNS
* nameserver, only the primary will be used at the moment. A future version
* may take advantage of fallback DNS servers.
*
* @param Config|string $config DNS Config object (recommended) or single nameserver address
* @param LoopInterface $loop
* @return \React\Dns\Resolver\ResolverInterface
* @throws \InvalidArgumentException for invalid DNS server address
* @throws \UnderflowException when given DNS Config object has an empty list of nameservers
*/
public function create($nameserver, LoopInterface $loop)
public function create($config, LoopInterface $loop)
{
$executor = $this->decorateHostsFileExecutor($this->createExecutor($nameserver, $loop));
$executor = $this->decorateHostsFileExecutor($this->createExecutor($config, $loop));

return new Resolver($executor);
}

/**
* @param string $nameserver
* Creates a cached DNS resolver instance for the given DNS config and cache
*
* As of v1.7.0 it's recommended to pass a `Config` object instead of a
* single nameserver address. If the given config contains more than one DNS
* nameserver, only the primary will be used at the moment. A future version
* may take advantage of fallback DNS servers.
*
* @param Config|string $config DNS Config object (recommended) or single nameserver address
* @param LoopInterface $loop
* @param ?CacheInterface $cache
* @return \React\Dns\Resolver\ResolverInterface
* @throws \InvalidArgumentException for invalid DNS server address
* @throws \UnderflowException when given DNS Config object has an empty list of nameservers
*/
public function createCached($nameserver, LoopInterface $loop, CacheInterface $cache = null)
public function createCached($config, LoopInterface $loop, CacheInterface $cache = null)
{
// default to keeping maximum of 256 responses in cache unless explicitly given
if (!($cache instanceof CacheInterface)) {
$cache = new ArrayCache(256);
}

$executor = $this->createExecutor($nameserver, $loop);
$executor = $this->createExecutor($config, $loop);
$executor = new CachingExecutor($executor, $cache);
$executor = $this->decorateHostsFileExecutor($executor);

Expand Down Expand Up @@ -80,8 +99,22 @@ private function decorateHostsFileExecutor(ExecutorInterface $executor)
return $executor;
}

/**
* @param Config|string $nameserver
* @param LoopInterface $loop
* @return CoopExecutor
* @throws \InvalidArgumentException for invalid DNS server address
* @throws \UnderflowException when given DNS Config object has an empty list of nameservers
*/
private function createExecutor($nameserver, LoopInterface $loop)
{
if ($nameserver instanceof Config) {
$nameserver = \reset($nameserver->nameservers);
if ($nameserver === false) {
throw new \UnderflowException('Empty config with no DNS servers');
}
}

$parts = \parse_url($nameserver);

if (isset($parts['scheme']) && $parts['scheme'] === 'tcp') {
Expand Down
59 changes: 58 additions & 1 deletion tests/Resolver/FactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

namespace React\Tests\Dns\Resolver;

use React\Dns\Config\Config;
use React\Dns\Query\HostsFileExecutor;
use React\Dns\Resolver\Factory;
use React\Tests\Dns\TestCase;
use React\Dns\Query\HostsFileExecutor;

class FactoryTest extends TestCase
{
Expand Down Expand Up @@ -134,16 +135,72 @@ public function createWithTcpSchemeShouldCreateResolverWithTcpExecutorStack()
$this->assertInstanceOf('React\Dns\Query\TcpTransportExecutor', $tcpExecutor);
}

/** @test */
public function createWithConfigWithTcpNameserverSchemeShouldCreateResolverWithTcpExecutorStack()
{
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();

$config = new Config();
$config->nameservers[] = 'tcp://8.8.8.8:53';

$factory = new Factory();
$resolver = $factory->create($config, $loop);

$this->assertInstanceOf('React\Dns\Resolver\Resolver', $resolver);

$coopExecutor = $this->getResolverPrivateExecutor($resolver);

$this->assertInstanceOf('React\Dns\Query\CoopExecutor', $coopExecutor);

$ref = new \ReflectionProperty($coopExecutor, 'executor');
$ref->setAccessible(true);
$timeoutExecutor = $ref->getValue($coopExecutor);

$this->assertInstanceOf('React\Dns\Query\TimeoutExecutor', $timeoutExecutor);

$ref = new \ReflectionProperty($timeoutExecutor, 'executor');
$ref->setAccessible(true);
$tcpExecutor = $ref->getValue($timeoutExecutor);

$this->assertInstanceOf('React\Dns\Query\TcpTransportExecutor', $tcpExecutor);
}

/** @test */
public function createShouldThrowWhenNameserverIsInvalid()
{
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();

$factory = new Factory();

$this->setExpectedException('InvalidArgumentException');
$factory->create('///', $loop);
}

/** @test */
public function createShouldThrowWhenConfigHasNoNameservers()
{
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();

$factory = new Factory();

$this->setExpectedException('UnderflowException');
$factory->create(new Config(), $loop);
}

/** @test */
public function createShouldThrowWhenConfigHasInvalidNameserver()
{
$loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();

$factory = new Factory();

$config = new Config();
$config->nameservers[] = '///';

$this->setExpectedException('InvalidArgumentException');
$factory->create($config, $loop);
}

/** @test */
public function createCachedShouldCreateResolverWithCachingExecutor()
{
Expand Down