summaryrefslogtreecommitdiffstats
path: root/vendor/clue/connection-manager-extra
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/clue/connection-manager-extra')
-rw-r--r--vendor/clue/connection-manager-extra/LICENSE21
-rw-r--r--vendor/clue/connection-manager-extra/composer.json29
-rw-r--r--vendor/clue/connection-manager-extra/src/ConnectionManagerDelay.php30
-rw-r--r--vendor/clue/connection-manager-extra/src/ConnectionManagerReject.php41
-rw-r--r--vendor/clue/connection-manager-extra/src/ConnectionManagerRepeat.php52
-rw-r--r--vendor/clue/connection-manager-extra/src/ConnectionManagerSwappable.php26
-rw-r--r--vendor/clue/connection-manager-extra/src/ConnectionManagerTimeout.php35
-rw-r--r--vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConcurrent.php36
-rw-r--r--vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConsecutive.php62
-rw-r--r--vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerRandom.php14
-rw-r--r--vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerSelective.php111
11 files changed, 457 insertions, 0 deletions
diff --git a/vendor/clue/connection-manager-extra/LICENSE b/vendor/clue/connection-manager-extra/LICENSE
new file mode 100644
index 0000000..da15612
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Christian Lück
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/clue/connection-manager-extra/composer.json b/vendor/clue/connection-manager-extra/composer.json
new file mode 100644
index 0000000..7534f80
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/composer.json
@@ -0,0 +1,29 @@
+{
+ "name": "clue/connection-manager-extra",
+ "description": "Extra decorators for creating async TCP/IP connections, built on top of ReactPHP's Socket component",
+ "keywords": ["Socket", "network", "connection", "timeout", "delay", "reject", "repeat", "retry", "random", "acl", "firewall", "ReactPHP"],
+ "homepage": "https://github.com/clue/reactphp-connection-manager-extra",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Christian Lück",
+ "email": "christian@clue.engineering"
+ }
+ ],
+ "autoload": {
+ "psr-4": { "ConnectionManager\\Extra\\": "src" }
+ },
+ "autoload-dev": {
+ "psr-4": { "ConnectionManager\\Tests\\Extra\\": "tests/" }
+ },
+ "require": {
+ "php": ">=5.3",
+ "react/socket": "^1.0 || ^0.8 || ^0.7",
+ "react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5",
+ "react/promise": "^2.1 || ^1.2.1",
+ "react/promise-timer": "^1.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8"
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/ConnectionManagerDelay.php b/vendor/clue/connection-manager-extra/src/ConnectionManagerDelay.php
new file mode 100644
index 0000000..b5112c6
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/ConnectionManagerDelay.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace ConnectionManager\Extra;
+
+use React\Socket\ConnectorInterface;
+use React\EventLoop\LoopInterface;
+use React\Promise\Timer;
+
+class ConnectionManagerDelay implements ConnectorInterface
+{
+ private $connectionManager;
+ private $delay;
+ private $loop;
+
+ public function __construct(ConnectorInterface $connectionManager, $delay, LoopInterface $loop)
+ {
+ $this->connectionManager = $connectionManager;
+ $this->delay = $delay;
+ $this->loop = $loop;
+ }
+
+ public function connect($uri)
+ {
+ $connectionManager = $this->connectionManager;
+
+ return Timer\resolve($this->delay, $this->loop)->then(function () use ($connectionManager, $uri) {
+ return $connectionManager->connect($uri);
+ });
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/ConnectionManagerReject.php b/vendor/clue/connection-manager-extra/src/ConnectionManagerReject.php
new file mode 100644
index 0000000..1222c83
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/ConnectionManagerReject.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace ConnectionManager\Extra;
+
+use React\Socket\ConnectorInterface;
+use React\Promise;
+use Exception;
+
+// a simple connection manager that rejects every single connection attempt
+class ConnectionManagerReject implements ConnectorInterface
+{
+ private $reason = 'Connection rejected';
+
+ /**
+ * @param null|string|callable $reason
+ */
+ public function __construct($reason = null)
+ {
+ if ($reason !== null) {
+ $this->reason = $reason;
+ }
+ }
+
+ public function connect($uri)
+ {
+ $reason = $this->reason;
+ if (!is_string($reason)) {
+ try {
+ $reason = $reason($uri);
+ } catch (\Exception $e) {
+ $reason = $e;
+ }
+ }
+
+ if (!$reason instanceof \Exception) {
+ $reason = new Exception($reason);
+ }
+
+ return Promise\reject($reason);
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/ConnectionManagerRepeat.php b/vendor/clue/connection-manager-extra/src/ConnectionManagerRepeat.php
new file mode 100644
index 0000000..10f3f5a
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/ConnectionManagerRepeat.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace ConnectionManager\Extra;
+
+use React\Socket\ConnectorInterface;
+use InvalidArgumentException;
+use Exception;
+use React\Promise\Promise;
+use React\Promise\CancellablePromiseInterface;
+
+class ConnectionManagerRepeat implements ConnectorInterface
+{
+ protected $connectionManager;
+ protected $maximumTries;
+
+ public function __construct(ConnectorInterface $connectionManager, $maximumTries)
+ {
+ if ($maximumTries < 1) {
+ throw new InvalidArgumentException('Maximum number of tries must be >= 1');
+ }
+ $this->connectionManager = $connectionManager;
+ $this->maximumTries = $maximumTries;
+ }
+
+ public function connect($uri)
+ {
+ $tries = $this->maximumTries;
+ $connector = $this->connectionManager;
+
+ return new Promise(function ($resolve, $reject) use ($uri, &$pending, &$tries, $connector) {
+ $try = function ($error = null) use (&$try, &$pending, &$tries, $uri, $connector, $resolve, $reject) {
+ if ($tries > 0) {
+ --$tries;
+ $pending = $connector->connect($uri);
+ $pending->then($resolve, $try);
+ } else {
+ $reject(new Exception('Connection still fails even after retrying', 0, $error));
+ }
+ };
+
+ $try();
+ }, function ($_, $reject) use (&$pending, &$tries) {
+ // stop retrying, reject results and cancel pending attempt
+ $tries = 0;
+ $reject(new \RuntimeException('Cancelled'));
+
+ if ($pending instanceof CancellablePromiseInterface) {
+ $pending->cancel();
+ }
+ });
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/ConnectionManagerSwappable.php b/vendor/clue/connection-manager-extra/src/ConnectionManagerSwappable.php
new file mode 100644
index 0000000..d133225
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/ConnectionManagerSwappable.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace ConnectionManager\Extra;
+
+use React\Socket\ConnectorInterface;
+
+// connection manager decorator which simplifies exchanging the actual connection manager during runtime
+class ConnectionManagerSwappable implements ConnectorInterface
+{
+ protected $connectionManager;
+
+ public function __construct(ConnectorInterface $connectionManager)
+ {
+ $this->connectionManager = $connectionManager;
+ }
+
+ public function connect($uri)
+ {
+ return $this->connectionManager->connect($uri);
+ }
+
+ public function setConnectionManager(ConnectorInterface $connectionManager)
+ {
+ $this->connectionManager = $connectionManager;
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/ConnectionManagerTimeout.php b/vendor/clue/connection-manager-extra/src/ConnectionManagerTimeout.php
new file mode 100644
index 0000000..5ec0872
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/ConnectionManagerTimeout.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace ConnectionManager\Extra;
+
+use React\Socket\ConnectorInterface;
+use React\EventLoop\LoopInterface;
+use React\Promise\Timer;
+
+class ConnectionManagerTimeout implements ConnectorInterface
+{
+ private $connectionManager;
+ private $timeout;
+ private $loop;
+
+ public function __construct(ConnectorInterface $connectionManager, $timeout, LoopInterface $loop)
+ {
+ $this->connectionManager = $connectionManager;
+ $this->timeout = $timeout;
+ $this->loop = $loop;
+ }
+
+ public function connect($uri)
+ {
+ $promise = $this->connectionManager->connect($uri);
+
+ return Timer\timeout($promise, $this->timeout, $this->loop)->then(null, function ($e) use ($promise) {
+ // connection successfully established but timeout already expired => close successful connection
+ $promise->then(function ($connection) {
+ $connection->end();
+ });
+
+ throw $e;
+ });
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConcurrent.php b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConcurrent.php
new file mode 100644
index 0000000..c1eb9cf
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConcurrent.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace ConnectionManager\Extra\Multiple;
+
+use ConnectionManager\Extra\Multiple\ConnectionManagerConsecutive;
+use React\Promise;
+use React\Promise\CancellablePromiseInterface;
+
+class ConnectionManagerConcurrent extends ConnectionManagerConsecutive
+{
+ public function connect($uri)
+ {
+ $all = array();
+ foreach ($this->managers as $connector) {
+ /* @var $connection Connector */
+ $all []= $connector->connect($uri);
+ }
+ return Promise\any($all)->then(function ($conn) use ($all) {
+ // a connection attempt succeeded
+ // => cancel all pending connection attempts
+ foreach ($all as $promise) {
+ if ($promise instanceof CancellablePromiseInterface) {
+ $promise->cancel();
+ }
+
+ // if promise resolves despite cancellation, immediately close stream
+ $promise->then(function ($stream) use ($conn) {
+ if ($stream !== $conn) {
+ $stream->close();
+ }
+ });
+ }
+ return $conn;
+ });
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConsecutive.php b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConsecutive.php
new file mode 100644
index 0000000..1474b85
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerConsecutive.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace ConnectionManager\Extra\Multiple;
+
+use React\Socket\ConnectorInterface;
+use React\Promise;
+use UnderflowException;
+use React\Promise\CancellablePromiseInterface;
+
+class ConnectionManagerConsecutive implements ConnectorInterface
+{
+ protected $managers;
+
+ /**
+ *
+ * @param ConnectorInterface[] $managers
+ */
+ public function __construct(array $managers)
+ {
+ if (!$managers) {
+ throw new \InvalidArgumentException('List of connectors must not be empty');
+ }
+ $this->managers = $managers;
+ }
+
+ public function connect($uri)
+ {
+ return $this->tryConnection($this->managers, $uri);
+ }
+
+ /**
+ *
+ * @param ConnectorInterface[] $managers
+ * @param string $uri
+ * @return Promise
+ * @internal
+ */
+ public function tryConnection(array $managers, $uri)
+ {
+ return new Promise\Promise(function ($resolve, $reject) use (&$managers, &$pending, $uri) {
+ $try = function () use (&$try, &$managers, $uri, $resolve, $reject, &$pending) {
+ if (!$managers) {
+ return $reject(new UnderflowException('No more managers to try to connect through'));
+ }
+
+ $manager = array_shift($managers);
+ $pending = $manager->connect($uri);
+ $pending->then($resolve, $try);
+ };
+
+ $try();
+ }, function ($_, $reject) use (&$managers, &$pending) {
+ // stop retrying, reject results and cancel pending attempt
+ $managers = array();
+ $reject(new \RuntimeException('Cancelled'));
+
+ if ($pending instanceof CancellablePromiseInterface) {
+ $pending->cancel();
+ }
+ });
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerRandom.php b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerRandom.php
new file mode 100644
index 0000000..88d1fd6
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerRandom.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace ConnectionManager\Extra\Multiple;
+
+class ConnectionManagerRandom extends ConnectionManagerConsecutive
+{
+ public function connect($uri)
+ {
+ $managers = $this->managers;
+ shuffle($managers);
+
+ return $this->tryConnection($managers, $uri);
+ }
+}
diff --git a/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerSelective.php b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerSelective.php
new file mode 100644
index 0000000..859ea90
--- /dev/null
+++ b/vendor/clue/connection-manager-extra/src/Multiple/ConnectionManagerSelective.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace ConnectionManager\Extra\Multiple;
+
+use React\Socket\ConnectorInterface;
+use React\Promise;
+use UnderflowException;
+use InvalidArgumentException;
+
+class ConnectionManagerSelective implements ConnectorInterface
+{
+ private $managers;
+
+ /**
+ *
+ * @param ConnectorInterface[] $managers
+ */
+ public function __construct(array $managers)
+ {
+ foreach ($managers as $filter => $manager) {
+ $host = $filter;
+ $portMin = 0;
+ $portMax = 65535;
+
+ // search colon (either single one OR preceded by "]" due to IPv6)
+ $colon = strrpos($host, ':');
+ if ($colon !== false && (strpos($host, ':') === $colon || substr($host, $colon - 1, 1) === ']' )) {
+ if (!isset($host[$colon + 1])) {
+ throw new InvalidArgumentException('Entry "' . $filter . '" has no port after colon');
+ }
+
+ $minus = strpos($host, '-', $colon);
+ if ($minus === false) {
+ $portMin = $portMax = (int)substr($host, $colon + 1);
+
+ if (substr($host, $colon + 1) !== (string)$portMin) {
+ throw new InvalidArgumentException('Entry "' . $filter . '" has no valid port after colon');
+ }
+ } else {
+ $portMin = (int)substr($host, $colon + 1, ($minus - $colon));
+ $portMax = (int)substr($host, $minus + 1);
+
+ if (substr($host, $colon + 1) !== ($portMin . '-' . $portMax)) {
+ throw new InvalidArgumentException('Entry "' . $filter . '" has no valid port range after colon');
+ }
+
+ if ($portMin > $portMax) {
+ throw new InvalidArgumentException('Entry "' . $filter . '" has port range mixed up');
+ }
+ }
+ $host = substr($host, 0, $colon);
+ }
+
+ if ($host === '') {
+ throw new InvalidArgumentException('Entry "' . $filter . '" has an empty host');
+ }
+
+ if (!$manager instanceof ConnectorInterface) {
+ throw new InvalidArgumentException('Entry "' . $filter . '" is not a valid connector');
+ }
+ }
+
+ $this->managers = $managers;
+ }
+
+ public function connect($uri)
+ {
+ $parts = parse_url((strpos($uri, '://') === false ? 'tcp://' : '') . $uri);
+ if (!isset($parts) || !isset($parts['scheme'], $parts['host'], $parts['port'])) {
+ return Promise\reject(new InvalidArgumentException('Invalid URI'));
+ }
+
+ $connector = $this->getConnectorForTarget(
+ trim($parts['host'], '[]'),
+ $parts['port']
+ );
+
+ if ($connector === null) {
+ return Promise\reject(new UnderflowException('No connector for given target found'));
+ }
+
+ return $connector->connect($uri);
+ }
+
+ private function getConnectorForTarget($targetHost, $targetPort)
+ {
+ foreach ($this->managers as $host => $connector) {
+ $portMin = 0;
+ $portMax = 65535;
+
+ // search colon (either single one OR preceded by "]" due to IPv6)
+ $colon = strrpos($host, ':');
+ if ($colon !== false && (strpos($host, ':') === $colon || substr($host, $colon - 1, 1) === ']' )) {
+ $minus = strpos($host, '-', $colon);
+ if ($minus === false) {
+ $portMin = $portMax = (int)substr($host, $colon + 1);
+ } else {
+ $portMin = (int)substr($host, $colon + 1, ($minus - $colon));
+ $portMax = (int)substr($host, $minus + 1);
+ }
+ $host = trim(substr($host, 0, $colon), '[]');
+ }
+
+ if ($targetPort >= $portMin && $targetPort <= $portMax && fnmatch($host, $targetHost)) {
+ return $connector;
+ }
+ }
+
+ return null;
+ }
+}