-
-
Notifications
You must be signed in to change notification settings - Fork 62
Expose Executer via factory class #194
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
base: 1.x
Are you sure you want to change the base?
Changes from 6 commits
8e75be0
706f60b
4a9886f
83bd2e1
400acf3
5ea88cb
6e10fb5
9cb8ca4
ee53f20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| <?php | ||
|
|
||
| namespace React\Dns\Query; | ||
|
|
||
| use React\Cache\ArrayCache; | ||
| use React\Cache\CacheInterface; | ||
| use React\Dns\Config\Config; | ||
| use React\Dns\Config\HostsFile; | ||
| use React\EventLoop\Loop; | ||
| use React\EventLoop\LoopInterface; | ||
|
|
||
| class ExecutorFactory | ||
|
||
| { | ||
|
|
||
| /** | ||
| * Creates a DNS executer 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, all DNS nameservers will be used in order. The primary DNS | ||
| * server will always be used first before falling back to the secondary or | ||
| * tertiary DNS server. | ||
| * | ||
| * @param Config|string $config DNS Config object (recommended) or single nameserver address | ||
| * @param ?LoopInterface $loop | ||
| * @return ExecutorInterface|HostsFileExecutor | ||
| * @throws \InvalidArgumentException for invalid DNS server address | ||
| * @throws \UnderflowException when given DNS Config object has an empty list of nameservers | ||
| */ | ||
| public function create($config, LoopInterface $loop = null) | ||
| { | ||
| return $this->decorateHostsFileExecutor($this->createExecutor($config, $loop ?: Loop::get())); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a cached DNS executer 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, all DNS nameservers will be used in order. The primary DNS | ||
| * server will always be used first before falling back to the secondary or | ||
| * tertiary DNS server. | ||
| * | ||
| * @param Config|string $config DNS Config object (recommended) or single nameserver address | ||
| * @param ?LoopInterface $loop | ||
| * @param ?CacheInterface $cache | ||
| * @return ExecutorInterface|HostsFileExecutor | ||
| * @throws \InvalidArgumentException for invalid DNS server address | ||
| * @throws \UnderflowException when given DNS Config object has an empty list of nameservers | ||
| */ | ||
| public function createCached($config, LoopInterface $loop = null, CacheInterface $cache = null) | ||
WyriHaximus marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| // default to keeping maximum of 256 responses in cache unless explicitly given | ||
| if (!($cache instanceof CacheInterface)) { | ||
| $cache = new ArrayCache(256); | ||
| } | ||
|
|
||
| $executor = $this->createExecutor($config, $loop ?: Loop::get()); | ||
| $executor = new CachingExecutor($executor, $cache); | ||
| $executor = $this->decorateHostsFileExecutor($executor); | ||
|
|
||
| return $executor; | ||
| } | ||
|
|
||
| /** | ||
| * Tries to load the hosts file and decorates the given executor on success | ||
| * | ||
| * @param ExecutorInterface $executor | ||
| * @return ExecutorInterface | ||
| * @codeCoverageIgnore | ||
| */ | ||
| protected function decorateHostsFileExecutor(ExecutorInterface $executor) | ||
| { | ||
| try { | ||
| $executor = new HostsFileExecutor( | ||
| HostsFile::loadFromPathBlocking(), | ||
| $executor | ||
| ); | ||
| } catch (\RuntimeException $e) { | ||
| // ignore this file if it can not be loaded | ||
| } | ||
|
|
||
| // Windows does not store localhost in hosts file by default but handles this internally | ||
| // To compensate for this, we explicitly use hard-coded defaults for localhost | ||
| if (DIRECTORY_SEPARATOR === '\\') { | ||
| $executor = new HostsFileExecutor( | ||
| new HostsFile("127.0.0.1 localhost\n::1 localhost"), | ||
| $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 | ||
| */ | ||
| protected function createExecutor($nameserver, LoopInterface $loop) | ||
| { | ||
| if ($nameserver instanceof Config) { | ||
| if (!$nameserver->nameservers) { | ||
| throw new \UnderflowException('Empty config with no DNS servers'); | ||
| } | ||
|
|
||
| // Hard-coded to check up to 3 DNS servers to match default limits in place in most systems (see MAXNS config). | ||
| // Note to future self: Recursion isn't too hard, but how deep do we really want to go? | ||
| $primary = reset($nameserver->nameservers); | ||
| $secondary = next($nameserver->nameservers); | ||
| $tertiary = next($nameserver->nameservers); | ||
|
|
||
| if ($tertiary !== false) { | ||
| // 3 DNS servers given => nest first with fallback for second and third | ||
| return new CoopExecutor( | ||
| new RetryExecutor( | ||
| new FallbackExecutor( | ||
| $this->createSingleExecutor($primary, $loop), | ||
| new FallbackExecutor( | ||
| $this->createSingleExecutor($secondary, $loop), | ||
| $this->createSingleExecutor($tertiary, $loop) | ||
| ) | ||
| ) | ||
| ) | ||
| ); | ||
| } elseif ($secondary !== false) { | ||
| // 2 DNS servers given => fallback from first to second | ||
| return new CoopExecutor( | ||
| new RetryExecutor( | ||
| new FallbackExecutor( | ||
| $this->createSingleExecutor($primary, $loop), | ||
| $this->createSingleExecutor($secondary, $loop) | ||
| ) | ||
| ) | ||
| ); | ||
| } else { | ||
| // 1 DNS server given => use single executor | ||
| $nameserver = $primary; | ||
| } | ||
| } | ||
|
|
||
| return new CoopExecutor(new RetryExecutor($this->createSingleExecutor($nameserver, $loop))); | ||
| } | ||
|
|
||
| /** | ||
| * @param string $nameserver | ||
| * @param LoopInterface $loop | ||
| * @return ExecutorInterface | ||
| * @throws \InvalidArgumentException for invalid DNS server address | ||
| */ | ||
| protected function createSingleExecutor($nameserver, LoopInterface $loop) | ||
| { | ||
| $parts = \parse_url($nameserver); | ||
|
|
||
| if (isset($parts['scheme']) && $parts['scheme'] === 'tcp') { | ||
| $executor = $this->createTcpExecutor($nameserver, $loop); | ||
| } elseif (isset($parts['scheme']) && $parts['scheme'] === 'udp') { | ||
| $executor = $this->createUdpExecutor($nameserver, $loop); | ||
| } else { | ||
| $executor = new SelectiveTransportExecutor( | ||
| $this->createUdpExecutor($nameserver, $loop), | ||
| $this->createTcpExecutor($nameserver, $loop) | ||
| ); | ||
| } | ||
|
|
||
| return $executor; | ||
| } | ||
|
|
||
| /** | ||
| * @param string $nameserver | ||
| * @param LoopInterface $loop | ||
| * @return TimeoutExecutor | ||
| * @throws \InvalidArgumentException for invalid DNS server address | ||
| */ | ||
| protected function createTcpExecutor($nameserver, LoopInterface $loop) | ||
| { | ||
| return new TimeoutExecutor( | ||
| new TcpTransportExecutor($nameserver, $loop), | ||
| 5.0, | ||
| $loop | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * @param string $nameserver | ||
| * @param LoopInterface $loop | ||
| * @return TimeoutExecutor | ||
| * @throws \InvalidArgumentException for invalid DNS server address | ||
| */ | ||
| protected function createUdpExecutor($nameserver, LoopInterface $loop) | ||
| { | ||
| return new TimeoutExecutor( | ||
| new UdpTransportExecutor( | ||
| $nameserver, | ||
| $loop | ||
| ), | ||
| 5.0, | ||
| $loop | ||
| ); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.