Initial Commit
This commit is contained in:
97
dependencies/amphp/dns/lib/Internal/TcpSocket.php
vendored
Normal file
97
dependencies/amphp/dns/lib/Internal/TcpSocket.php
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Ultimo\Dependencies\Amp\Dns\Internal;
|
||||
|
||||
use WP_Ultimo\Dependencies\Amp;
|
||||
use WP_Ultimo\Dependencies\Amp\Deferred;
|
||||
use WP_Ultimo\Dependencies\Amp\Dns\DnsException;
|
||||
use WP_Ultimo\Dependencies\Amp\Dns\TimeoutException;
|
||||
use WP_Ultimo\Dependencies\Amp\Loop;
|
||||
use WP_Ultimo\Dependencies\Amp\Parser\Parser;
|
||||
use WP_Ultimo\Dependencies\Amp\Promise;
|
||||
use WP_Ultimo\Dependencies\Amp\Success;
|
||||
use WP_Ultimo\Dependencies\LibDNS\Decoder\DecoderFactory;
|
||||
use WP_Ultimo\Dependencies\LibDNS\Encoder\EncoderFactory;
|
||||
use WP_Ultimo\Dependencies\LibDNS\Messages\Message;
|
||||
use function WP_Ultimo\Dependencies\Amp\call;
|
||||
/** @internal */
|
||||
final class TcpSocket extends Socket
|
||||
{
|
||||
/** @var \LibDNS\Encoder\Encoder */
|
||||
private $encoder;
|
||||
/** @var \SplQueue */
|
||||
private $queue;
|
||||
/** @var Parser */
|
||||
private $parser;
|
||||
/** @var bool */
|
||||
private $isAlive = \true;
|
||||
public static function connect(string $uri, int $timeout = 5000) : Promise
|
||||
{
|
||||
if (!($socket = @\stream_socket_client($uri, $errno, $errstr, 0, \STREAM_CLIENT_ASYNC_CONNECT))) {
|
||||
throw new DnsException(\sprintf("Connection to %s failed: [Error #%d] %s", $uri, $errno, $errstr));
|
||||
}
|
||||
\stream_set_blocking($socket, \false);
|
||||
return call(function () use($uri, $socket, $timeout) {
|
||||
$deferred = new Deferred();
|
||||
$watcher = Loop::onWritable($socket, static function () use($socket, $deferred) {
|
||||
$deferred->resolve(new self($socket));
|
||||
});
|
||||
try {
|
||||
return (yield Promise\timeout($deferred->promise(), $timeout));
|
||||
} catch (Amp\TimeoutException $e) {
|
||||
throw new TimeoutException("Name resolution timed out, could not connect to server at {$uri}");
|
||||
} finally {
|
||||
Loop::cancel($watcher);
|
||||
}
|
||||
});
|
||||
}
|
||||
public static function parser(callable $callback) : \Generator
|
||||
{
|
||||
$decoder = (new DecoderFactory())->create();
|
||||
while (\true) {
|
||||
$length = (yield 2);
|
||||
$length = \unpack("n", $length)[1];
|
||||
$rawData = (yield $length);
|
||||
$callback($decoder->decode($rawData));
|
||||
}
|
||||
}
|
||||
protected function __construct($socket)
|
||||
{
|
||||
parent::__construct($socket);
|
||||
$this->encoder = (new EncoderFactory())->create();
|
||||
$this->queue = new \SplQueue();
|
||||
$this->parser = new Parser(self::parser([$this->queue, 'push']));
|
||||
}
|
||||
protected function send(Message $message) : Promise
|
||||
{
|
||||
$data = $this->encoder->encode($message);
|
||||
$promise = $this->write(\pack("n", \strlen($data)) . $data);
|
||||
$promise->onResolve(function ($error) {
|
||||
if ($error) {
|
||||
$this->isAlive = \false;
|
||||
}
|
||||
});
|
||||
return $promise;
|
||||
}
|
||||
protected function receive() : Promise
|
||||
{
|
||||
if ($this->queue->isEmpty()) {
|
||||
return call(function () {
|
||||
do {
|
||||
$chunk = (yield $this->read());
|
||||
if ($chunk === null) {
|
||||
$this->isAlive = \false;
|
||||
throw new DnsException("Reading from the server failed");
|
||||
}
|
||||
$this->parser->push($chunk);
|
||||
} while ($this->queue->isEmpty());
|
||||
return $this->queue->shift();
|
||||
});
|
||||
}
|
||||
return new Success($this->queue->shift());
|
||||
}
|
||||
public function isAlive() : bool
|
||||
{
|
||||
return $this->isAlive;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user