@@ -10,32 +10,32 @@ |
||
| 10 | 10 | */ |
| 11 | 11 | class RejectionException extends \RuntimeException |
| 12 | 12 | { |
| 13 | - /** @var mixed Rejection reason. */ |
|
| 14 | - private $reason; |
|
| 15 | - /** |
|
| 16 | - * @param mixed $reason Rejection reason. |
|
| 17 | - * @param string|null $description Optional description. |
|
| 18 | - */ |
|
| 19 | - public function __construct($reason, ?string $description = null) |
|
| 20 | - { |
|
| 21 | - $this->reason = $reason; |
|
| 22 | - $message = 'The promise was rejected'; |
|
| 23 | - if ($description) { |
|
| 24 | - $message .= ' with reason: ' . $description; |
|
| 25 | - } elseif (\is_string($reason) || \is_object($reason) && \method_exists($reason, '__toString')) { |
|
| 26 | - $message .= ' with reason: ' . $this->reason; |
|
| 27 | - } elseif ($reason instanceof \JsonSerializable) { |
|
| 28 | - $message .= ' with reason: ' . \json_encode($this->reason, \JSON_PRETTY_PRINT); |
|
| 29 | - } |
|
| 30 | - parent::__construct($message); |
|
| 31 | - } |
|
| 32 | - /** |
|
| 33 | - * Returns the rejection reason. |
|
| 34 | - * |
|
| 35 | - * @return mixed |
|
| 36 | - */ |
|
| 37 | - public function getReason() |
|
| 38 | - { |
|
| 39 | - return $this->reason; |
|
| 40 | - } |
|
| 13 | + /** @var mixed Rejection reason. */ |
|
| 14 | + private $reason; |
|
| 15 | + /** |
|
| 16 | + * @param mixed $reason Rejection reason. |
|
| 17 | + * @param string|null $description Optional description. |
|
| 18 | + */ |
|
| 19 | + public function __construct($reason, ?string $description = null) |
|
| 20 | + { |
|
| 21 | + $this->reason = $reason; |
|
| 22 | + $message = 'The promise was rejected'; |
|
| 23 | + if ($description) { |
|
| 24 | + $message .= ' with reason: ' . $description; |
|
| 25 | + } elseif (\is_string($reason) || \is_object($reason) && \method_exists($reason, '__toString')) { |
|
| 26 | + $message .= ' with reason: ' . $this->reason; |
|
| 27 | + } elseif ($reason instanceof \JsonSerializable) { |
|
| 28 | + $message .= ' with reason: ' . \json_encode($this->reason, \JSON_PRETTY_PRINT); |
|
| 29 | + } |
|
| 30 | + parent::__construct($message); |
|
| 31 | + } |
|
| 32 | + /** |
|
| 33 | + * Returns the rejection reason. |
|
| 34 | + * |
|
| 35 | + * @return mixed |
|
| 36 | + */ |
|
| 37 | + public function getReason() |
|
| 38 | + { |
|
| 39 | + return $this->reason; |
|
| 40 | + } |
|
| 41 | 41 | } |
@@ -13,66 +13,66 @@ |
||
| 13 | 13 | */ |
| 14 | 14 | class RejectedPromise implements PromiseInterface |
| 15 | 15 | { |
| 16 | - private $reason; |
|
| 17 | - /** |
|
| 18 | - * @param mixed $reason |
|
| 19 | - */ |
|
| 20 | - public function __construct($reason) |
|
| 21 | - { |
|
| 22 | - if (\is_object($reason) && \method_exists($reason, 'then')) { |
|
| 23 | - throw new \InvalidArgumentException('You cannot create a RejectedPromise with a promise.'); |
|
| 24 | - } |
|
| 25 | - $this->reason = $reason; |
|
| 26 | - } |
|
| 27 | - public function then(?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface |
|
| 28 | - { |
|
| 29 | - // If there's no onRejected callback then just return self. |
|
| 30 | - if (!$onRejected) { |
|
| 31 | - return $this; |
|
| 32 | - } |
|
| 33 | - $queue = Utils::queue(); |
|
| 34 | - $reason = $this->reason; |
|
| 35 | - $p = new Promise([$queue, 'run']); |
|
| 36 | - $queue->add(static function () use($p, $reason, $onRejected) : void { |
|
| 37 | - if (Is::pending($p)) { |
|
| 38 | - try { |
|
| 39 | - // Return a resolved promise if onRejected does not throw. |
|
| 40 | - $p->resolve($onRejected($reason)); |
|
| 41 | - } catch (\Throwable $e) { |
|
| 42 | - // onRejected threw, so return a rejected promise. |
|
| 43 | - $p->reject($e); |
|
| 44 | - } |
|
| 45 | - } |
|
| 46 | - }); |
|
| 47 | - return $p; |
|
| 48 | - } |
|
| 49 | - public function otherwise(callable $onRejected) : PromiseInterface |
|
| 50 | - { |
|
| 51 | - return $this->then(null, $onRejected); |
|
| 52 | - } |
|
| 53 | - public function wait(bool $unwrap = \true) |
|
| 54 | - { |
|
| 55 | - if ($unwrap) { |
|
| 56 | - throw Create::exceptionFor($this->reason); |
|
| 57 | - } |
|
| 58 | - return null; |
|
| 59 | - } |
|
| 60 | - public function getState() : string |
|
| 61 | - { |
|
| 62 | - return self::REJECTED; |
|
| 63 | - } |
|
| 64 | - public function resolve($value) : void |
|
| 65 | - { |
|
| 66 | - throw new \LogicException('Cannot resolve a rejected promise'); |
|
| 67 | - } |
|
| 68 | - public function reject($reason) : void |
|
| 69 | - { |
|
| 70 | - if ($reason !== $this->reason) { |
|
| 71 | - throw new \LogicException('Cannot reject a rejected promise'); |
|
| 72 | - } |
|
| 73 | - } |
|
| 74 | - public function cancel() : void |
|
| 75 | - { |
|
| 76 | - // pass |
|
| 77 | - } |
|
| 16 | + private $reason; |
|
| 17 | + /** |
|
| 18 | + * @param mixed $reason |
|
| 19 | + */ |
|
| 20 | + public function __construct($reason) |
|
| 21 | + { |
|
| 22 | + if (\is_object($reason) && \method_exists($reason, 'then')) { |
|
| 23 | + throw new \InvalidArgumentException('You cannot create a RejectedPromise with a promise.'); |
|
| 24 | + } |
|
| 25 | + $this->reason = $reason; |
|
| 26 | + } |
|
| 27 | + public function then(?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface |
|
| 28 | + { |
|
| 29 | + // If there's no onRejected callback then just return self. |
|
| 30 | + if (!$onRejected) { |
|
| 31 | + return $this; |
|
| 32 | + } |
|
| 33 | + $queue = Utils::queue(); |
|
| 34 | + $reason = $this->reason; |
|
| 35 | + $p = new Promise([$queue, 'run']); |
|
| 36 | + $queue->add(static function () use($p, $reason, $onRejected) : void { |
|
| 37 | + if (Is::pending($p)) { |
|
| 38 | + try { |
|
| 39 | + // Return a resolved promise if onRejected does not throw. |
|
| 40 | + $p->resolve($onRejected($reason)); |
|
| 41 | + } catch (\Throwable $e) { |
|
| 42 | + // onRejected threw, so return a rejected promise. |
|
| 43 | + $p->reject($e); |
|
| 44 | + } |
|
| 45 | + } |
|
| 46 | + }); |
|
| 47 | + return $p; |
|
| 48 | + } |
|
| 49 | + public function otherwise(callable $onRejected) : PromiseInterface |
|
| 50 | + { |
|
| 51 | + return $this->then(null, $onRejected); |
|
| 52 | + } |
|
| 53 | + public function wait(bool $unwrap = \true) |
|
| 54 | + { |
|
| 55 | + if ($unwrap) { |
|
| 56 | + throw Create::exceptionFor($this->reason); |
|
| 57 | + } |
|
| 58 | + return null; |
|
| 59 | + } |
|
| 60 | + public function getState() : string |
|
| 61 | + { |
|
| 62 | + return self::REJECTED; |
|
| 63 | + } |
|
| 64 | + public function resolve($value) : void |
|
| 65 | + { |
|
| 66 | + throw new \LogicException('Cannot resolve a rejected promise'); |
|
| 67 | + } |
|
| 68 | + public function reject($reason) : void |
|
| 69 | + { |
|
| 70 | + if ($reason !== $this->reason) { |
|
| 71 | + throw new \LogicException('Cannot reject a rejected promise'); |
|
| 72 | + } |
|
| 73 | + } |
|
| 74 | + public function cancel() : void |
|
| 75 | + { |
|
| 76 | + // pass |
|
| 77 | + } |
|
| 78 | 78 | } |
@@ -13,61 +13,61 @@ |
||
| 13 | 13 | */ |
| 14 | 14 | class FulfilledPromise implements PromiseInterface |
| 15 | 15 | { |
| 16 | - private $value; |
|
| 17 | - /** |
|
| 18 | - * @param mixed $value |
|
| 19 | - */ |
|
| 20 | - public function __construct($value) |
|
| 21 | - { |
|
| 22 | - if (\is_object($value) && \method_exists($value, 'then')) { |
|
| 23 | - throw new \InvalidArgumentException('You cannot create a FulfilledPromise with a promise.'); |
|
| 24 | - } |
|
| 25 | - $this->value = $value; |
|
| 26 | - } |
|
| 27 | - public function then(?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface |
|
| 28 | - { |
|
| 29 | - // Return itself if there is no onFulfilled function. |
|
| 30 | - if (!$onFulfilled) { |
|
| 31 | - return $this; |
|
| 32 | - } |
|
| 33 | - $queue = Utils::queue(); |
|
| 34 | - $p = new Promise([$queue, 'run']); |
|
| 35 | - $value = $this->value; |
|
| 36 | - $queue->add(static function () use($p, $value, $onFulfilled) : void { |
|
| 37 | - if (Is::pending($p)) { |
|
| 38 | - try { |
|
| 39 | - $p->resolve($onFulfilled($value)); |
|
| 40 | - } catch (\Throwable $e) { |
|
| 41 | - $p->reject($e); |
|
| 42 | - } |
|
| 43 | - } |
|
| 44 | - }); |
|
| 45 | - return $p; |
|
| 46 | - } |
|
| 47 | - public function otherwise(callable $onRejected) : PromiseInterface |
|
| 48 | - { |
|
| 49 | - return $this->then(null, $onRejected); |
|
| 50 | - } |
|
| 51 | - public function wait(bool $unwrap = \true) |
|
| 52 | - { |
|
| 53 | - return $unwrap ? $this->value : null; |
|
| 54 | - } |
|
| 55 | - public function getState() : string |
|
| 56 | - { |
|
| 57 | - return self::FULFILLED; |
|
| 58 | - } |
|
| 59 | - public function resolve($value) : void |
|
| 60 | - { |
|
| 61 | - if ($value !== $this->value) { |
|
| 62 | - throw new \LogicException('Cannot resolve a fulfilled promise'); |
|
| 63 | - } |
|
| 64 | - } |
|
| 65 | - public function reject($reason) : void |
|
| 66 | - { |
|
| 67 | - throw new \LogicException('Cannot reject a fulfilled promise'); |
|
| 68 | - } |
|
| 69 | - public function cancel() : void |
|
| 70 | - { |
|
| 71 | - // pass |
|
| 72 | - } |
|
| 16 | + private $value; |
|
| 17 | + /** |
|
| 18 | + * @param mixed $value |
|
| 19 | + */ |
|
| 20 | + public function __construct($value) |
|
| 21 | + { |
|
| 22 | + if (\is_object($value) && \method_exists($value, 'then')) { |
|
| 23 | + throw new \InvalidArgumentException('You cannot create a FulfilledPromise with a promise.'); |
|
| 24 | + } |
|
| 25 | + $this->value = $value; |
|
| 26 | + } |
|
| 27 | + public function then(?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface |
|
| 28 | + { |
|
| 29 | + // Return itself if there is no onFulfilled function. |
|
| 30 | + if (!$onFulfilled) { |
|
| 31 | + return $this; |
|
| 32 | + } |
|
| 33 | + $queue = Utils::queue(); |
|
| 34 | + $p = new Promise([$queue, 'run']); |
|
| 35 | + $value = $this->value; |
|
| 36 | + $queue->add(static function () use($p, $value, $onFulfilled) : void { |
|
| 37 | + if (Is::pending($p)) { |
|
| 38 | + try { |
|
| 39 | + $p->resolve($onFulfilled($value)); |
|
| 40 | + } catch (\Throwable $e) { |
|
| 41 | + $p->reject($e); |
|
| 42 | + } |
|
| 43 | + } |
|
| 44 | + }); |
|
| 45 | + return $p; |
|
| 46 | + } |
|
| 47 | + public function otherwise(callable $onRejected) : PromiseInterface |
|
| 48 | + { |
|
| 49 | + return $this->then(null, $onRejected); |
|
| 50 | + } |
|
| 51 | + public function wait(bool $unwrap = \true) |
|
| 52 | + { |
|
| 53 | + return $unwrap ? $this->value : null; |
|
| 54 | + } |
|
| 55 | + public function getState() : string |
|
| 56 | + { |
|
| 57 | + return self::FULFILLED; |
|
| 58 | + } |
|
| 59 | + public function resolve($value) : void |
|
| 60 | + { |
|
| 61 | + if ($value !== $this->value) { |
|
| 62 | + throw new \LogicException('Cannot resolve a fulfilled promise'); |
|
| 63 | + } |
|
| 64 | + } |
|
| 65 | + public function reject($reason) : void |
|
| 66 | + { |
|
| 67 | + throw new \LogicException('Cannot reject a fulfilled promise'); |
|
| 68 | + } |
|
| 69 | + public function cancel() : void |
|
| 70 | + { |
|
| 71 | + // pass |
|
| 72 | + } |
|
| 73 | 73 | } |
@@ -5,52 +5,52 @@ |
||
| 5 | 5 | |
| 6 | 6 | final class Each |
| 7 | 7 | { |
| 8 | - /** |
|
| 9 | - * Given an iterator that yields promises or values, returns a promise that |
|
| 10 | - * is fulfilled with a null value when the iterator has been consumed or |
|
| 11 | - * the aggregate promise has been fulfilled or rejected. |
|
| 12 | - * |
|
| 13 | - * $onFulfilled is a function that accepts the fulfilled value, iterator |
|
| 14 | - * index, and the aggregate promise. The callback can invoke any necessary |
|
| 15 | - * side effects and choose to resolve or reject the aggregate if needed. |
|
| 16 | - * |
|
| 17 | - * $onRejected is a function that accepts the rejection reason, iterator |
|
| 18 | - * index, and the aggregate promise. The callback can invoke any necessary |
|
| 19 | - * side effects and choose to resolve or reject the aggregate if needed. |
|
| 20 | - * |
|
| 21 | - * @param mixed $iterable Iterator or array to iterate over. |
|
| 22 | - */ |
|
| 23 | - public static function of($iterable, ?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface |
|
| 24 | - { |
|
| 25 | - return (new EachPromise($iterable, ['fulfilled' => $onFulfilled, 'rejected' => $onRejected]))->promise(); |
|
| 26 | - } |
|
| 27 | - /** |
|
| 28 | - * Like of, but only allows a certain number of outstanding promises at any |
|
| 29 | - * given time. |
|
| 30 | - * |
|
| 31 | - * $concurrency may be an integer or a function that accepts the number of |
|
| 32 | - * pending promises and returns a numeric concurrency limit value to allow |
|
| 33 | - * for dynamic a concurrency size. |
|
| 34 | - * |
|
| 35 | - * @param mixed $iterable |
|
| 36 | - * @param int|callable $concurrency |
|
| 37 | - */ |
|
| 38 | - public static function ofLimit($iterable, $concurrency, ?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface |
|
| 39 | - { |
|
| 40 | - return (new EachPromise($iterable, ['fulfilled' => $onFulfilled, 'rejected' => $onRejected, 'concurrency' => $concurrency]))->promise(); |
|
| 41 | - } |
|
| 42 | - /** |
|
| 43 | - * Like limit, but ensures that no promise in the given $iterable argument |
|
| 44 | - * is rejected. If any promise is rejected, then the aggregate promise is |
|
| 45 | - * rejected with the encountered rejection. |
|
| 46 | - * |
|
| 47 | - * @param mixed $iterable |
|
| 48 | - * @param int|callable $concurrency |
|
| 49 | - */ |
|
| 50 | - public static function ofLimitAll($iterable, $concurrency, ?callable $onFulfilled = null) : PromiseInterface |
|
| 51 | - { |
|
| 52 | - return self::ofLimit($iterable, $concurrency, $onFulfilled, function ($reason, $idx, PromiseInterface $aggregate) : void { |
|
| 53 | - $aggregate->reject($reason); |
|
| 54 | - }); |
|
| 55 | - } |
|
| 8 | + /** |
|
| 9 | + * Given an iterator that yields promises or values, returns a promise that |
|
| 10 | + * is fulfilled with a null value when the iterator has been consumed or |
|
| 11 | + * the aggregate promise has been fulfilled or rejected. |
|
| 12 | + * |
|
| 13 | + * $onFulfilled is a function that accepts the fulfilled value, iterator |
|
| 14 | + * index, and the aggregate promise. The callback can invoke any necessary |
|
| 15 | + * side effects and choose to resolve or reject the aggregate if needed. |
|
| 16 | + * |
|
| 17 | + * $onRejected is a function that accepts the rejection reason, iterator |
|
| 18 | + * index, and the aggregate promise. The callback can invoke any necessary |
|
| 19 | + * side effects and choose to resolve or reject the aggregate if needed. |
|
| 20 | + * |
|
| 21 | + * @param mixed $iterable Iterator or array to iterate over. |
|
| 22 | + */ |
|
| 23 | + public static function of($iterable, ?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface |
|
| 24 | + { |
|
| 25 | + return (new EachPromise($iterable, ['fulfilled' => $onFulfilled, 'rejected' => $onRejected]))->promise(); |
|
| 26 | + } |
|
| 27 | + /** |
|
| 28 | + * Like of, but only allows a certain number of outstanding promises at any |
|
| 29 | + * given time. |
|
| 30 | + * |
|
| 31 | + * $concurrency may be an integer or a function that accepts the number of |
|
| 32 | + * pending promises and returns a numeric concurrency limit value to allow |
|
| 33 | + * for dynamic a concurrency size. |
|
| 34 | + * |
|
| 35 | + * @param mixed $iterable |
|
| 36 | + * @param int|callable $concurrency |
|
| 37 | + */ |
|
| 38 | + public static function ofLimit($iterable, $concurrency, ?callable $onFulfilled = null, ?callable $onRejected = null) : PromiseInterface |
|
| 39 | + { |
|
| 40 | + return (new EachPromise($iterable, ['fulfilled' => $onFulfilled, 'rejected' => $onRejected, 'concurrency' => $concurrency]))->promise(); |
|
| 41 | + } |
|
| 42 | + /** |
|
| 43 | + * Like limit, but ensures that no promise in the given $iterable argument |
|
| 44 | + * is rejected. If any promise is rejected, then the aggregate promise is |
|
| 45 | + * rejected with the encountered rejection. |
|
| 46 | + * |
|
| 47 | + * @param mixed $iterable |
|
| 48 | + * @param int|callable $concurrency |
|
| 49 | + */ |
|
| 50 | + public static function ofLimitAll($iterable, $concurrency, ?callable $onFulfilled = null) : PromiseInterface |
|
| 51 | + { |
|
| 52 | + return self::ofLimit($iterable, $concurrency, $onFulfilled, function ($reason, $idx, PromiseInterface $aggregate) : void { |
|
| 53 | + $aggregate->reject($reason); |
|
| 54 | + }); |
|
| 55 | + } |
|
| 56 | 56 | } |
@@ -1,6 +1,6 @@ discard block |
||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | -declare (strict_types=1); |
|
| 3 | +declare(strict_types=1); |
|
| 4 | 4 | namespace OCA\FullTextSearch_Elasticsearch\Vendor\GuzzleHttp\Promise; |
| 5 | 5 | |
| 6 | 6 | final class Each |
@@ -49,7 +49,7 @@ discard block |
||
| 49 | 49 | */ |
| 50 | 50 | public static function ofLimitAll($iterable, $concurrency, ?callable $onFulfilled = null) : PromiseInterface |
| 51 | 51 | { |
| 52 | - return self::ofLimit($iterable, $concurrency, $onFulfilled, function ($reason, $idx, PromiseInterface $aggregate) : void { |
|
| 52 | + return self::ofLimit($iterable, $concurrency, $onFulfilled, function($reason, $idx, PromiseInterface $aggregate) : void { |
|
| 53 | 53 | $aggregate->reject($reason); |
| 54 | 54 | }); |
| 55 | 55 | } |
@@ -9,236 +9,236 @@ |
||
| 9 | 9 | */ |
| 10 | 10 | final class RequestOptions |
| 11 | 11 | { |
| 12 | - /** |
|
| 13 | - * allow_redirects: (bool|array) Controls redirect behavior. Pass false |
|
| 14 | - * to disable redirects, pass true to enable redirects, pass an |
|
| 15 | - * associative to provide custom redirect settings. Defaults to "false". |
|
| 16 | - * This option only works if your handler has the RedirectMiddleware. When |
|
| 17 | - * passing an associative array, you can provide the following key value |
|
| 18 | - * pairs: |
|
| 19 | - * |
|
| 20 | - * - max: (int, default=5) maximum number of allowed redirects. |
|
| 21 | - * - strict: (bool, default=false) Set to true to use strict redirects |
|
| 22 | - * meaning redirect POST requests with POST requests vs. doing what most |
|
| 23 | - * browsers do which is redirect POST requests with GET requests |
|
| 24 | - * - referer: (bool, default=false) Set to true to enable the Referer |
|
| 25 | - * header. |
|
| 26 | - * - protocols: (array, default=['http', 'https']) Allowed redirect |
|
| 27 | - * protocols. |
|
| 28 | - * - on_redirect: (callable) PHP callable that is invoked when a redirect |
|
| 29 | - * is encountered. The callable is invoked with the request, the redirect |
|
| 30 | - * response that was received, and the effective URI. Any return value |
|
| 31 | - * from the on_redirect function is ignored. |
|
| 32 | - */ |
|
| 33 | - public const ALLOW_REDIRECTS = 'allow_redirects'; |
|
| 34 | - /** |
|
| 35 | - * auth: (array) Pass an array of HTTP authentication parameters to use |
|
| 36 | - * with the request. The array must contain the username in index [0], |
|
| 37 | - * the password in index [1], and you can optionally provide a built-in |
|
| 38 | - * authentication type in index [2]. Pass null to disable authentication |
|
| 39 | - * for a request. |
|
| 40 | - */ |
|
| 41 | - public const AUTH = 'auth'; |
|
| 42 | - /** |
|
| 43 | - * body: (resource|string|null|int|float|StreamInterface|callable|\Iterator) |
|
| 44 | - * Body to send in the request. |
|
| 45 | - */ |
|
| 46 | - public const BODY = 'body'; |
|
| 47 | - /** |
|
| 48 | - * cert: (string|array) Set to a string to specify the path to a file |
|
| 49 | - * containing a PEM formatted SSL client side certificate. If a password |
|
| 50 | - * is required, then set cert to an array containing the path to the PEM |
|
| 51 | - * file in the first array element followed by the certificate password |
|
| 52 | - * in the second array element. |
|
| 53 | - */ |
|
| 54 | - public const CERT = 'cert'; |
|
| 55 | - /** |
|
| 56 | - * cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false) |
|
| 57 | - * Specifies whether or not cookies are used in a request or what cookie |
|
| 58 | - * jar to use or what cookies to send. This option only works if your |
|
| 59 | - * handler has the `cookie` middleware. Valid values are `false` and |
|
| 60 | - * an instance of {@see Cookie\CookieJarInterface}. |
|
| 61 | - */ |
|
| 62 | - public const COOKIES = 'cookies'; |
|
| 63 | - /** |
|
| 64 | - * connect_timeout: (float, default=0) Float describing the number of |
|
| 65 | - * seconds to wait while trying to connect to a server. Use 0 to wait |
|
| 66 | - * 300 seconds (the default behavior). |
|
| 67 | - */ |
|
| 68 | - public const CONNECT_TIMEOUT = 'connect_timeout'; |
|
| 69 | - /** |
|
| 70 | - * crypto_method: (int) A value describing the minimum TLS protocol |
|
| 71 | - * version to use. |
|
| 72 | - * |
|
| 73 | - * This setting must be set to one of the |
|
| 74 | - * ``STREAM_CRYPTO_METHOD_TLS*_CLIENT`` constants. PHP 7.4 or higher is |
|
| 75 | - * required in order to use TLS 1.3, and cURL 7.34.0 or higher is required |
|
| 76 | - * in order to specify a crypto method, with cURL 7.52.0 or higher being |
|
| 77 | - * required to use TLS 1.3. |
|
| 78 | - */ |
|
| 79 | - public const CRYPTO_METHOD = 'crypto_method'; |
|
| 80 | - /** |
|
| 81 | - * debug: (bool|resource) Set to true or set to a PHP stream returned by |
|
| 82 | - * fopen() enable debug output with the HTTP handler used to send a |
|
| 83 | - * request. |
|
| 84 | - */ |
|
| 85 | - public const DEBUG = 'debug'; |
|
| 86 | - /** |
|
| 87 | - * decode_content: (bool, default=true) Specify whether or not |
|
| 88 | - * Content-Encoding responses (gzip, deflate, etc.) are automatically |
|
| 89 | - * decoded. |
|
| 90 | - */ |
|
| 91 | - public const DECODE_CONTENT = 'decode_content'; |
|
| 92 | - /** |
|
| 93 | - * delay: (int) The amount of time to delay before sending in milliseconds. |
|
| 94 | - */ |
|
| 95 | - public const DELAY = 'delay'; |
|
| 96 | - /** |
|
| 97 | - * expect: (bool|integer) Controls the behavior of the |
|
| 98 | - * "Expect: 100-Continue" header. |
|
| 99 | - * |
|
| 100 | - * Set to `true` to enable the "Expect: 100-Continue" header for all |
|
| 101 | - * requests that sends a body. Set to `false` to disable the |
|
| 102 | - * "Expect: 100-Continue" header for all requests. Set to a number so that |
|
| 103 | - * the size of the payload must be greater than the number in order to send |
|
| 104 | - * the Expect header. Setting to a number will send the Expect header for |
|
| 105 | - * all requests in which the size of the payload cannot be determined or |
|
| 106 | - * where the body is not rewindable. |
|
| 107 | - * |
|
| 108 | - * By default, Guzzle will add the "Expect: 100-Continue" header when the |
|
| 109 | - * size of the body of a request is greater than 1 MB and a request is |
|
| 110 | - * using HTTP/1.1. |
|
| 111 | - */ |
|
| 112 | - public const EXPECT = 'expect'; |
|
| 113 | - /** |
|
| 114 | - * form_params: (array) Associative array of form field names to values |
|
| 115 | - * where each value is a string or array of strings. Sets the Content-Type |
|
| 116 | - * header to application/x-www-form-urlencoded when no Content-Type header |
|
| 117 | - * is already present. |
|
| 118 | - */ |
|
| 119 | - public const FORM_PARAMS = 'form_params'; |
|
| 120 | - /** |
|
| 121 | - * headers: (array) Associative array of HTTP headers. Each value MUST be |
|
| 122 | - * a string or array of strings. |
|
| 123 | - */ |
|
| 124 | - public const HEADERS = 'headers'; |
|
| 125 | - /** |
|
| 126 | - * http_errors: (bool, default=true) Set to false to disable exceptions |
|
| 127 | - * when a non- successful HTTP response is received. By default, |
|
| 128 | - * exceptions will be thrown for 4xx and 5xx responses. This option only |
|
| 129 | - * works if your handler has the `httpErrors` middleware. |
|
| 130 | - */ |
|
| 131 | - public const HTTP_ERRORS = 'http_errors'; |
|
| 132 | - /** |
|
| 133 | - * idn: (bool|int, default=true) A combination of IDNA_* constants for |
|
| 134 | - * idn_to_ascii() PHP's function (see "options" parameter). Set to false to |
|
| 135 | - * disable IDN support completely, or to true to use the default |
|
| 136 | - * configuration (IDNA_DEFAULT constant). |
|
| 137 | - */ |
|
| 138 | - public const IDN_CONVERSION = 'idn_conversion'; |
|
| 139 | - /** |
|
| 140 | - * json: (mixed) Adds JSON data to a request. The provided value is JSON |
|
| 141 | - * encoded and a Content-Type header of application/json will be added to |
|
| 142 | - * the request if no Content-Type header is already present. |
|
| 143 | - */ |
|
| 144 | - public const JSON = 'json'; |
|
| 145 | - /** |
|
| 146 | - * multipart: (array) Array of associative arrays, each containing a |
|
| 147 | - * required "name" key mapping to the form field, name, a required |
|
| 148 | - * "contents" key mapping to a StreamInterface|resource|string, an |
|
| 149 | - * optional "headers" associative array of custom headers, and an |
|
| 150 | - * optional "filename" key mapping to a string to send as the filename in |
|
| 151 | - * the part. If no "filename" key is present, then no "filename" attribute |
|
| 152 | - * will be added to the part. |
|
| 153 | - */ |
|
| 154 | - public const MULTIPART = 'multipart'; |
|
| 155 | - /** |
|
| 156 | - * on_headers: (callable) A callable that is invoked when the HTTP headers |
|
| 157 | - * of the response have been received but the body has not yet begun to |
|
| 158 | - * download. |
|
| 159 | - */ |
|
| 160 | - public const ON_HEADERS = 'on_headers'; |
|
| 161 | - /** |
|
| 162 | - * on_stats: (callable) allows you to get access to transfer statistics of |
|
| 163 | - * a request and access the lower level transfer details of the handler |
|
| 164 | - * associated with your client. ``on_stats`` is a callable that is invoked |
|
| 165 | - * when a handler has finished sending a request. The callback is invoked |
|
| 166 | - * with transfer statistics about the request, the response received, or |
|
| 167 | - * the error encountered. Included in the data is the total amount of time |
|
| 168 | - * taken to send the request. |
|
| 169 | - */ |
|
| 170 | - public const ON_STATS = 'on_stats'; |
|
| 171 | - /** |
|
| 172 | - * progress: (callable) Defines a function to invoke when transfer |
|
| 173 | - * progress is made. The function accepts the following positional |
|
| 174 | - * arguments: the total number of bytes expected to be downloaded, the |
|
| 175 | - * number of bytes downloaded so far, the number of bytes expected to be |
|
| 176 | - * uploaded, the number of bytes uploaded so far. |
|
| 177 | - */ |
|
| 178 | - public const PROGRESS = 'progress'; |
|
| 179 | - /** |
|
| 180 | - * proxy: (string|array) Pass a string to specify an HTTP proxy, or an |
|
| 181 | - * array to specify different proxies for different protocols (where the |
|
| 182 | - * key is the protocol and the value is a proxy string). |
|
| 183 | - */ |
|
| 184 | - public const PROXY = 'proxy'; |
|
| 185 | - /** |
|
| 186 | - * query: (array|string) Associative array of query string values to add |
|
| 187 | - * to the request. This option uses PHP's http_build_query() to create |
|
| 188 | - * the string representation. Pass a string value if you need more |
|
| 189 | - * control than what this method provides |
|
| 190 | - */ |
|
| 191 | - public const QUERY = 'query'; |
|
| 192 | - /** |
|
| 193 | - * sink: (resource|string|StreamInterface) Where the data of the |
|
| 194 | - * response is written to. Defaults to a PHP temp stream. Providing a |
|
| 195 | - * string will write data to a file by the given name. |
|
| 196 | - */ |
|
| 197 | - public const SINK = 'sink'; |
|
| 198 | - /** |
|
| 199 | - * synchronous: (bool) Set to true to inform HTTP handlers that you intend |
|
| 200 | - * on waiting on the response. This can be useful for optimizations. Note |
|
| 201 | - * that a promise is still returned if you are using one of the async |
|
| 202 | - * client methods. |
|
| 203 | - */ |
|
| 204 | - public const SYNCHRONOUS = 'synchronous'; |
|
| 205 | - /** |
|
| 206 | - * ssl_key: (array|string) Specify the path to a file containing a private |
|
| 207 | - * SSL key in PEM format. If a password is required, then set to an array |
|
| 208 | - * containing the path to the SSL key in the first array element followed |
|
| 209 | - * by the password required for the certificate in the second element. |
|
| 210 | - */ |
|
| 211 | - public const SSL_KEY = 'ssl_key'; |
|
| 212 | - /** |
|
| 213 | - * stream: Set to true to attempt to stream a response rather than |
|
| 214 | - * download it all up-front. |
|
| 215 | - */ |
|
| 216 | - public const STREAM = 'stream'; |
|
| 217 | - /** |
|
| 218 | - * verify: (bool|string, default=true) Describes the SSL certificate |
|
| 219 | - * verification behavior of a request. Set to true to enable SSL |
|
| 220 | - * certificate verification using the system CA bundle when available |
|
| 221 | - * (the default). Set to false to disable certificate verification (this |
|
| 222 | - * is insecure!). Set to a string to provide the path to a CA bundle on |
|
| 223 | - * disk to enable verification using a custom certificate. |
|
| 224 | - */ |
|
| 225 | - public const VERIFY = 'verify'; |
|
| 226 | - /** |
|
| 227 | - * timeout: (float, default=0) Float describing the timeout of the |
|
| 228 | - * request in seconds. Use 0 to wait indefinitely (the default behavior). |
|
| 229 | - */ |
|
| 230 | - public const TIMEOUT = 'timeout'; |
|
| 231 | - /** |
|
| 232 | - * read_timeout: (float, default=default_socket_timeout ini setting) Float describing |
|
| 233 | - * the body read timeout, for stream requests. |
|
| 234 | - */ |
|
| 235 | - public const READ_TIMEOUT = 'read_timeout'; |
|
| 236 | - /** |
|
| 237 | - * version: (float) Specifies the HTTP protocol version to attempt to use. |
|
| 238 | - */ |
|
| 239 | - public const VERSION = 'version'; |
|
| 240 | - /** |
|
| 241 | - * force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol |
|
| 242 | - */ |
|
| 243 | - public const FORCE_IP_RESOLVE = 'force_ip_resolve'; |
|
| 12 | + /** |
|
| 13 | + * allow_redirects: (bool|array) Controls redirect behavior. Pass false |
|
| 14 | + * to disable redirects, pass true to enable redirects, pass an |
|
| 15 | + * associative to provide custom redirect settings. Defaults to "false". |
|
| 16 | + * This option only works if your handler has the RedirectMiddleware. When |
|
| 17 | + * passing an associative array, you can provide the following key value |
|
| 18 | + * pairs: |
|
| 19 | + * |
|
| 20 | + * - max: (int, default=5) maximum number of allowed redirects. |
|
| 21 | + * - strict: (bool, default=false) Set to true to use strict redirects |
|
| 22 | + * meaning redirect POST requests with POST requests vs. doing what most |
|
| 23 | + * browsers do which is redirect POST requests with GET requests |
|
| 24 | + * - referer: (bool, default=false) Set to true to enable the Referer |
|
| 25 | + * header. |
|
| 26 | + * - protocols: (array, default=['http', 'https']) Allowed redirect |
|
| 27 | + * protocols. |
|
| 28 | + * - on_redirect: (callable) PHP callable that is invoked when a redirect |
|
| 29 | + * is encountered. The callable is invoked with the request, the redirect |
|
| 30 | + * response that was received, and the effective URI. Any return value |
|
| 31 | + * from the on_redirect function is ignored. |
|
| 32 | + */ |
|
| 33 | + public const ALLOW_REDIRECTS = 'allow_redirects'; |
|
| 34 | + /** |
|
| 35 | + * auth: (array) Pass an array of HTTP authentication parameters to use |
|
| 36 | + * with the request. The array must contain the username in index [0], |
|
| 37 | + * the password in index [1], and you can optionally provide a built-in |
|
| 38 | + * authentication type in index [2]. Pass null to disable authentication |
|
| 39 | + * for a request. |
|
| 40 | + */ |
|
| 41 | + public const AUTH = 'auth'; |
|
| 42 | + /** |
|
| 43 | + * body: (resource|string|null|int|float|StreamInterface|callable|\Iterator) |
|
| 44 | + * Body to send in the request. |
|
| 45 | + */ |
|
| 46 | + public const BODY = 'body'; |
|
| 47 | + /** |
|
| 48 | + * cert: (string|array) Set to a string to specify the path to a file |
|
| 49 | + * containing a PEM formatted SSL client side certificate. If a password |
|
| 50 | + * is required, then set cert to an array containing the path to the PEM |
|
| 51 | + * file in the first array element followed by the certificate password |
|
| 52 | + * in the second array element. |
|
| 53 | + */ |
|
| 54 | + public const CERT = 'cert'; |
|
| 55 | + /** |
|
| 56 | + * cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false) |
|
| 57 | + * Specifies whether or not cookies are used in a request or what cookie |
|
| 58 | + * jar to use or what cookies to send. This option only works if your |
|
| 59 | + * handler has the `cookie` middleware. Valid values are `false` and |
|
| 60 | + * an instance of {@see Cookie\CookieJarInterface}. |
|
| 61 | + */ |
|
| 62 | + public const COOKIES = 'cookies'; |
|
| 63 | + /** |
|
| 64 | + * connect_timeout: (float, default=0) Float describing the number of |
|
| 65 | + * seconds to wait while trying to connect to a server. Use 0 to wait |
|
| 66 | + * 300 seconds (the default behavior). |
|
| 67 | + */ |
|
| 68 | + public const CONNECT_TIMEOUT = 'connect_timeout'; |
|
| 69 | + /** |
|
| 70 | + * crypto_method: (int) A value describing the minimum TLS protocol |
|
| 71 | + * version to use. |
|
| 72 | + * |
|
| 73 | + * This setting must be set to one of the |
|
| 74 | + * ``STREAM_CRYPTO_METHOD_TLS*_CLIENT`` constants. PHP 7.4 or higher is |
|
| 75 | + * required in order to use TLS 1.3, and cURL 7.34.0 or higher is required |
|
| 76 | + * in order to specify a crypto method, with cURL 7.52.0 or higher being |
|
| 77 | + * required to use TLS 1.3. |
|
| 78 | + */ |
|
| 79 | + public const CRYPTO_METHOD = 'crypto_method'; |
|
| 80 | + /** |
|
| 81 | + * debug: (bool|resource) Set to true or set to a PHP stream returned by |
|
| 82 | + * fopen() enable debug output with the HTTP handler used to send a |
|
| 83 | + * request. |
|
| 84 | + */ |
|
| 85 | + public const DEBUG = 'debug'; |
|
| 86 | + /** |
|
| 87 | + * decode_content: (bool, default=true) Specify whether or not |
|
| 88 | + * Content-Encoding responses (gzip, deflate, etc.) are automatically |
|
| 89 | + * decoded. |
|
| 90 | + */ |
|
| 91 | + public const DECODE_CONTENT = 'decode_content'; |
|
| 92 | + /** |
|
| 93 | + * delay: (int) The amount of time to delay before sending in milliseconds. |
|
| 94 | + */ |
|
| 95 | + public const DELAY = 'delay'; |
|
| 96 | + /** |
|
| 97 | + * expect: (bool|integer) Controls the behavior of the |
|
| 98 | + * "Expect: 100-Continue" header. |
|
| 99 | + * |
|
| 100 | + * Set to `true` to enable the "Expect: 100-Continue" header for all |
|
| 101 | + * requests that sends a body. Set to `false` to disable the |
|
| 102 | + * "Expect: 100-Continue" header for all requests. Set to a number so that |
|
| 103 | + * the size of the payload must be greater than the number in order to send |
|
| 104 | + * the Expect header. Setting to a number will send the Expect header for |
|
| 105 | + * all requests in which the size of the payload cannot be determined or |
|
| 106 | + * where the body is not rewindable. |
|
| 107 | + * |
|
| 108 | + * By default, Guzzle will add the "Expect: 100-Continue" header when the |
|
| 109 | + * size of the body of a request is greater than 1 MB and a request is |
|
| 110 | + * using HTTP/1.1. |
|
| 111 | + */ |
|
| 112 | + public const EXPECT = 'expect'; |
|
| 113 | + /** |
|
| 114 | + * form_params: (array) Associative array of form field names to values |
|
| 115 | + * where each value is a string or array of strings. Sets the Content-Type |
|
| 116 | + * header to application/x-www-form-urlencoded when no Content-Type header |
|
| 117 | + * is already present. |
|
| 118 | + */ |
|
| 119 | + public const FORM_PARAMS = 'form_params'; |
|
| 120 | + /** |
|
| 121 | + * headers: (array) Associative array of HTTP headers. Each value MUST be |
|
| 122 | + * a string or array of strings. |
|
| 123 | + */ |
|
| 124 | + public const HEADERS = 'headers'; |
|
| 125 | + /** |
|
| 126 | + * http_errors: (bool, default=true) Set to false to disable exceptions |
|
| 127 | + * when a non- successful HTTP response is received. By default, |
|
| 128 | + * exceptions will be thrown for 4xx and 5xx responses. This option only |
|
| 129 | + * works if your handler has the `httpErrors` middleware. |
|
| 130 | + */ |
|
| 131 | + public const HTTP_ERRORS = 'http_errors'; |
|
| 132 | + /** |
|
| 133 | + * idn: (bool|int, default=true) A combination of IDNA_* constants for |
|
| 134 | + * idn_to_ascii() PHP's function (see "options" parameter). Set to false to |
|
| 135 | + * disable IDN support completely, or to true to use the default |
|
| 136 | + * configuration (IDNA_DEFAULT constant). |
|
| 137 | + */ |
|
| 138 | + public const IDN_CONVERSION = 'idn_conversion'; |
|
| 139 | + /** |
|
| 140 | + * json: (mixed) Adds JSON data to a request. The provided value is JSON |
|
| 141 | + * encoded and a Content-Type header of application/json will be added to |
|
| 142 | + * the request if no Content-Type header is already present. |
|
| 143 | + */ |
|
| 144 | + public const JSON = 'json'; |
|
| 145 | + /** |
|
| 146 | + * multipart: (array) Array of associative arrays, each containing a |
|
| 147 | + * required "name" key mapping to the form field, name, a required |
|
| 148 | + * "contents" key mapping to a StreamInterface|resource|string, an |
|
| 149 | + * optional "headers" associative array of custom headers, and an |
|
| 150 | + * optional "filename" key mapping to a string to send as the filename in |
|
| 151 | + * the part. If no "filename" key is present, then no "filename" attribute |
|
| 152 | + * will be added to the part. |
|
| 153 | + */ |
|
| 154 | + public const MULTIPART = 'multipart'; |
|
| 155 | + /** |
|
| 156 | + * on_headers: (callable) A callable that is invoked when the HTTP headers |
|
| 157 | + * of the response have been received but the body has not yet begun to |
|
| 158 | + * download. |
|
| 159 | + */ |
|
| 160 | + public const ON_HEADERS = 'on_headers'; |
|
| 161 | + /** |
|
| 162 | + * on_stats: (callable) allows you to get access to transfer statistics of |
|
| 163 | + * a request and access the lower level transfer details of the handler |
|
| 164 | + * associated with your client. ``on_stats`` is a callable that is invoked |
|
| 165 | + * when a handler has finished sending a request. The callback is invoked |
|
| 166 | + * with transfer statistics about the request, the response received, or |
|
| 167 | + * the error encountered. Included in the data is the total amount of time |
|
| 168 | + * taken to send the request. |
|
| 169 | + */ |
|
| 170 | + public const ON_STATS = 'on_stats'; |
|
| 171 | + /** |
|
| 172 | + * progress: (callable) Defines a function to invoke when transfer |
|
| 173 | + * progress is made. The function accepts the following positional |
|
| 174 | + * arguments: the total number of bytes expected to be downloaded, the |
|
| 175 | + * number of bytes downloaded so far, the number of bytes expected to be |
|
| 176 | + * uploaded, the number of bytes uploaded so far. |
|
| 177 | + */ |
|
| 178 | + public const PROGRESS = 'progress'; |
|
| 179 | + /** |
|
| 180 | + * proxy: (string|array) Pass a string to specify an HTTP proxy, or an |
|
| 181 | + * array to specify different proxies for different protocols (where the |
|
| 182 | + * key is the protocol and the value is a proxy string). |
|
| 183 | + */ |
|
| 184 | + public const PROXY = 'proxy'; |
|
| 185 | + /** |
|
| 186 | + * query: (array|string) Associative array of query string values to add |
|
| 187 | + * to the request. This option uses PHP's http_build_query() to create |
|
| 188 | + * the string representation. Pass a string value if you need more |
|
| 189 | + * control than what this method provides |
|
| 190 | + */ |
|
| 191 | + public const QUERY = 'query'; |
|
| 192 | + /** |
|
| 193 | + * sink: (resource|string|StreamInterface) Where the data of the |
|
| 194 | + * response is written to. Defaults to a PHP temp stream. Providing a |
|
| 195 | + * string will write data to a file by the given name. |
|
| 196 | + */ |
|
| 197 | + public const SINK = 'sink'; |
|
| 198 | + /** |
|
| 199 | + * synchronous: (bool) Set to true to inform HTTP handlers that you intend |
|
| 200 | + * on waiting on the response. This can be useful for optimizations. Note |
|
| 201 | + * that a promise is still returned if you are using one of the async |
|
| 202 | + * client methods. |
|
| 203 | + */ |
|
| 204 | + public const SYNCHRONOUS = 'synchronous'; |
|
| 205 | + /** |
|
| 206 | + * ssl_key: (array|string) Specify the path to a file containing a private |
|
| 207 | + * SSL key in PEM format. If a password is required, then set to an array |
|
| 208 | + * containing the path to the SSL key in the first array element followed |
|
| 209 | + * by the password required for the certificate in the second element. |
|
| 210 | + */ |
|
| 211 | + public const SSL_KEY = 'ssl_key'; |
|
| 212 | + /** |
|
| 213 | + * stream: Set to true to attempt to stream a response rather than |
|
| 214 | + * download it all up-front. |
|
| 215 | + */ |
|
| 216 | + public const STREAM = 'stream'; |
|
| 217 | + /** |
|
| 218 | + * verify: (bool|string, default=true) Describes the SSL certificate |
|
| 219 | + * verification behavior of a request. Set to true to enable SSL |
|
| 220 | + * certificate verification using the system CA bundle when available |
|
| 221 | + * (the default). Set to false to disable certificate verification (this |
|
| 222 | + * is insecure!). Set to a string to provide the path to a CA bundle on |
|
| 223 | + * disk to enable verification using a custom certificate. |
|
| 224 | + */ |
|
| 225 | + public const VERIFY = 'verify'; |
|
| 226 | + /** |
|
| 227 | + * timeout: (float, default=0) Float describing the timeout of the |
|
| 228 | + * request in seconds. Use 0 to wait indefinitely (the default behavior). |
|
| 229 | + */ |
|
| 230 | + public const TIMEOUT = 'timeout'; |
|
| 231 | + /** |
|
| 232 | + * read_timeout: (float, default=default_socket_timeout ini setting) Float describing |
|
| 233 | + * the body read timeout, for stream requests. |
|
| 234 | + */ |
|
| 235 | + public const READ_TIMEOUT = 'read_timeout'; |
|
| 236 | + /** |
|
| 237 | + * version: (float) Specifies the HTTP protocol version to attempt to use. |
|
| 238 | + */ |
|
| 239 | + public const VERSION = 'version'; |
|
| 240 | + /** |
|
| 241 | + * force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol |
|
| 242 | + */ |
|
| 243 | + public const FORCE_IP_RESOLVE = 'force_ip_resolve'; |
|
| 244 | 244 | } |
@@ -5,19 +5,19 @@ |
||
| 5 | 5 | use OCA\FullTextSearch_Elasticsearch\Vendor\Psr\Http\Message\MessageInterface; |
| 6 | 6 | final class BodySummarizer implements BodySummarizerInterface |
| 7 | 7 | { |
| 8 | - /** |
|
| 9 | - * @var int|null |
|
| 10 | - */ |
|
| 11 | - private $truncateAt; |
|
| 12 | - public function __construct(?int $truncateAt = null) |
|
| 13 | - { |
|
| 14 | - $this->truncateAt = $truncateAt; |
|
| 15 | - } |
|
| 16 | - /** |
|
| 17 | - * Returns a summarized message body. |
|
| 18 | - */ |
|
| 19 | - public function summarize(MessageInterface $message) : ?string |
|
| 20 | - { |
|
| 21 | - return $this->truncateAt === null ? Psr7\Message::bodySummary($message) : Psr7\Message::bodySummary($message, $this->truncateAt); |
|
| 22 | - } |
|
| 8 | + /** |
|
| 9 | + * @var int|null |
|
| 10 | + */ |
|
| 11 | + private $truncateAt; |
|
| 12 | + public function __construct(?int $truncateAt = null) |
|
| 13 | + { |
|
| 14 | + $this->truncateAt = $truncateAt; |
|
| 15 | + } |
|
| 16 | + /** |
|
| 17 | + * Returns a summarized message body. |
|
| 18 | + */ |
|
| 19 | + public function summarize(MessageInterface $message) : ?string |
|
| 20 | + { |
|
| 21 | + return $this->truncateAt === null ? Psr7\Message::bodySummary($message) : Psr7\Message::bodySummary($message, $this->truncateAt); |
|
| 22 | + } |
|
| 23 | 23 | } |
@@ -49,384 +49,384 @@ |
||
| 49 | 49 | use function strtolower; |
| 50 | 50 | final class Transport implements ClientInterface, HttpAsyncClient |
| 51 | 51 | { |
| 52 | - const VERSION = "8.10.0"; |
|
| 53 | - private ClientInterface $client; |
|
| 54 | - private LoggerInterface $logger; |
|
| 55 | - private NodePoolInterface $nodePool; |
|
| 56 | - private array $headers = []; |
|
| 57 | - private string $user; |
|
| 58 | - private string $password; |
|
| 59 | - private RequestInterface $lastRequest; |
|
| 60 | - private ResponseInterface $lastResponse; |
|
| 61 | - private string $OSVersion; |
|
| 62 | - private int $retries = 0; |
|
| 63 | - private HttpAsyncClient $asyncClient; |
|
| 64 | - private OnSuccessInterface $onAsyncSuccess; |
|
| 65 | - private OnFailureInterface $onAsyncFailure; |
|
| 66 | - private TracerInterface $otelTracer; |
|
| 67 | - public function __construct(ClientInterface $client, NodePoolInterface $nodePool, LoggerInterface $logger) |
|
| 68 | - { |
|
| 69 | - $this->client = $client; |
|
| 70 | - $this->nodePool = $nodePool; |
|
| 71 | - $this->logger = $logger; |
|
| 72 | - } |
|
| 73 | - public function getClient() : ClientInterface |
|
| 74 | - { |
|
| 75 | - return $this->client; |
|
| 76 | - } |
|
| 77 | - public function getNodePool() : NodePoolInterface |
|
| 78 | - { |
|
| 79 | - return $this->nodePool; |
|
| 80 | - } |
|
| 81 | - public function getLogger() : LoggerInterface |
|
| 82 | - { |
|
| 83 | - return $this->logger; |
|
| 84 | - } |
|
| 85 | - public function getOTelTracer() : TracerInterface |
|
| 86 | - { |
|
| 87 | - if (empty($this->otelTracer)) { |
|
| 88 | - $this->otelTracer = OpenTelemetry::getTracer(Globals::tracerProvider()); |
|
| 89 | - } |
|
| 90 | - return $this->otelTracer; |
|
| 91 | - } |
|
| 92 | - public function setOTelTracer(TracerInterface $tracer) : self |
|
| 93 | - { |
|
| 94 | - $this->otelTracer = $tracer; |
|
| 95 | - return $this; |
|
| 96 | - } |
|
| 97 | - public function setHeader(string $name, string $value) : self |
|
| 98 | - { |
|
| 99 | - $this->headers[$name] = $value; |
|
| 100 | - return $this; |
|
| 101 | - } |
|
| 102 | - /** |
|
| 103 | - * @throws InvalidArgumentException |
|
| 104 | - */ |
|
| 105 | - public function setRetries(int $num) : self |
|
| 106 | - { |
|
| 107 | - if ($num < 0) { |
|
| 108 | - throw new InvalidArgumentException('The retries number must be a positive integer'); |
|
| 109 | - } |
|
| 110 | - $this->retries = $num; |
|
| 111 | - return $this; |
|
| 112 | - } |
|
| 113 | - public function getRetries() : int |
|
| 114 | - { |
|
| 115 | - return $this->retries; |
|
| 116 | - } |
|
| 117 | - public function getHeaders() : array |
|
| 118 | - { |
|
| 119 | - return $this->headers; |
|
| 120 | - } |
|
| 121 | - public function setUserInfo(string $user, string $password = '') : self |
|
| 122 | - { |
|
| 123 | - $this->user = $user; |
|
| 124 | - $this->password = $password; |
|
| 125 | - return $this; |
|
| 126 | - } |
|
| 127 | - public function setUserAgent(string $name, string $version) : self |
|
| 128 | - { |
|
| 129 | - $this->headers['User-Agent'] = sprintf("%s/%s (%s %s; PHP %s)", $name, $version, \PHP_OS, $this->getOSVersion(), phpversion()); |
|
| 130 | - return $this; |
|
| 131 | - } |
|
| 132 | - /** |
|
| 133 | - * Set the x-elastic-client-meta header |
|
| 134 | - * |
|
| 135 | - * The header format is specified by the following regex: |
|
| 136 | - * ^[a-z]{1,}=[a-z0-9\.\-]{1,}(?:,[a-z]{1,}=[a-z0-9\.\-]+)*$ |
|
| 137 | - */ |
|
| 138 | - public function setElasticMetaHeader(string $clientName, string $clientVersion, bool $async = \false) : self |
|
| 139 | - { |
|
| 140 | - $phpSemVersion = sprintf("%d.%d.%d", \PHP_MAJOR_VERSION, \PHP_MINOR_VERSION, \PHP_RELEASE_VERSION); |
|
| 141 | - $meta = sprintf("%s=%s,php=%s,t=%s,a=%d", $clientName, $this->purgePreReleaseTag($clientVersion), $phpSemVersion, $this->purgePreReleaseTag(self::VERSION), $async ? 1 : 0); |
|
| 142 | - $lib = $this->getClientLibraryInfo(); |
|
| 143 | - if (!empty($lib)) { |
|
| 144 | - $meta .= sprintf(",%s=%s", $lib[0], $lib[1]); |
|
| 145 | - } |
|
| 146 | - $this->headers['x-elastic-client-meta'] = $meta; |
|
| 147 | - return $this; |
|
| 148 | - } |
|
| 149 | - /** |
|
| 150 | - * Remove pre-release suffix with a single 'p' letter |
|
| 151 | - */ |
|
| 152 | - private function purgePreReleaseTag(string $version) : string |
|
| 153 | - { |
|
| 154 | - return str_replace(['alpha', 'beta', 'snapshot', 'rc', 'pre'], 'p', strtolower($version)); |
|
| 155 | - } |
|
| 156 | - public function getLastRequest() : RequestInterface |
|
| 157 | - { |
|
| 158 | - return $this->lastRequest; |
|
| 159 | - } |
|
| 160 | - public function getLastResponse() : ResponseInterface |
|
| 161 | - { |
|
| 162 | - return $this->lastResponse; |
|
| 163 | - } |
|
| 164 | - /** |
|
| 165 | - * Setup the headers, if not already present |
|
| 166 | - */ |
|
| 167 | - private function setupHeaders(RequestInterface $request) : RequestInterface |
|
| 168 | - { |
|
| 169 | - foreach ($this->headers as $name => $value) { |
|
| 170 | - if (!$request->hasHeader($name)) { |
|
| 171 | - $request = $request->withHeader($name, $value); |
|
| 172 | - } |
|
| 173 | - } |
|
| 174 | - return $request; |
|
| 175 | - } |
|
| 176 | - /** |
|
| 177 | - * Setup the user info, if not already present |
|
| 178 | - */ |
|
| 179 | - private function setupUserInfo(RequestInterface $request) : RequestInterface |
|
| 180 | - { |
|
| 181 | - $uri = $request->getUri(); |
|
| 182 | - if (empty($uri->getUserInfo())) { |
|
| 183 | - if (isset($this->user)) { |
|
| 184 | - $request = $request->withUri($uri->withUserInfo($this->user, $this->password)); |
|
| 185 | - } |
|
| 186 | - } |
|
| 187 | - return $request; |
|
| 188 | - } |
|
| 189 | - /** |
|
| 190 | - * Setup the connection Uri |
|
| 191 | - */ |
|
| 192 | - private function setupConnectionUri(Node $node, RequestInterface $request) : RequestInterface |
|
| 193 | - { |
|
| 194 | - $uri = $node->getUri(); |
|
| 195 | - $path = $request->getUri()->getPath(); |
|
| 196 | - $nodePath = $uri->getPath(); |
|
| 197 | - // If the node has a path we need to use it as prefix for the existing path |
|
| 198 | - // @see https://github.com/elastic/elastic-transport-php/pull/20 |
|
| 199 | - if (!empty($nodePath)) { |
|
| 200 | - $path = sprintf("%s/%s", \rtrim($nodePath, '/'), \ltrim($path, '/')); |
|
| 201 | - } |
|
| 202 | - // If the user information is not in the request, we check if it is present in the node uri |
|
| 203 | - // @see https://github.com/elastic/elastic-transport-php/issues/18 |
|
| 204 | - if (empty($request->getUri()->getUserInfo()) && !empty($uri->getUserInfo())) { |
|
| 205 | - $userInfo = \explode(':', $uri->getUserInfo()); |
|
| 206 | - $request = $request->withUri($request->getUri()->withUserInfo($userInfo[0], $userInfo[1] ?? null)); |
|
| 207 | - } |
|
| 208 | - return $request->withUri($request->getUri()->withHost($uri->getHost())->withPort($uri->getPort())->withScheme($uri->getScheme())->withPath($path)); |
|
| 209 | - } |
|
| 210 | - private function decorateRequest(RequestInterface $request) : RequestInterface |
|
| 211 | - { |
|
| 212 | - $request = $this->setupHeaders($request); |
|
| 213 | - return $this->setupUserInfo($request); |
|
| 214 | - } |
|
| 215 | - private function logHeaders(MessageInterface $message) : void |
|
| 216 | - { |
|
| 217 | - $this->logger->debug(sprintf("Headers: %s\nBody: %s", json_encode($message->getHeaders()), (string) $message->getBody())); |
|
| 218 | - } |
|
| 219 | - private function logRequest(string $title, RequestInterface $request) : void |
|
| 220 | - { |
|
| 221 | - $this->logger->info(sprintf("%s: %s %s", $title, $request->getMethod(), (string) $request->getUri()), ['request' => $request]); |
|
| 222 | - $this->logHeaders($request); |
|
| 223 | - } |
|
| 224 | - private function logResponse(string $title, ResponseInterface $response, int $retry) : void |
|
| 225 | - { |
|
| 226 | - $this->logger->info(sprintf("%s (retry %d): %d", $title, $retry, $response->getStatusCode()), ['response' => $response, 'retry' => $retry]); |
|
| 227 | - $this->logHeaders($response); |
|
| 228 | - } |
|
| 229 | - /** |
|
| 230 | - * @throws NoNodeAvailableException |
|
| 231 | - * @throws ClientExceptionInterface |
|
| 232 | - */ |
|
| 233 | - public function sendRequest(RequestInterface $request) : ResponseInterface |
|
| 234 | - { |
|
| 235 | - if (empty($request->getUri()->getHost())) { |
|
| 236 | - $node = $this->nodePool->nextNode(); |
|
| 237 | - $request = $this->setupConnectionUri($node, $request); |
|
| 238 | - } |
|
| 239 | - $request = $this->decorateRequest($request); |
|
| 240 | - $this->lastRequest = $request; |
|
| 241 | - $this->logRequest("Request", $request); |
|
| 242 | - // OpenTelemetry get tracer |
|
| 243 | - if (\getenv(OpenTelemetry::ENV_VARIABLE_ENABLED)) { |
|
| 244 | - $tracer = $this->getOTelTracer(); |
|
| 245 | - } |
|
| 246 | - $count = -1; |
|
| 247 | - while ($count < $this->getRetries()) { |
|
| 248 | - try { |
|
| 249 | - $count++; |
|
| 250 | - // OpenTelemetry span start |
|
| 251 | - if (!empty($tracer)) { |
|
| 252 | - if ($request instanceof ServerRequestInterface) { |
|
| 253 | - $opts = $request->getAttribute(OpenTelemetry::PSR7_OTEL_ATTRIBUTE_NAME, []); |
|
| 254 | - } |
|
| 255 | - $spanName = $opts['db.operation.name'] ?? $request->getUri()->getPath(); |
|
| 256 | - $span = $tracer->spanBuilder($spanName)->startSpan(); |
|
| 257 | - $span->setAttribute('http.request.method', $request->getMethod()); |
|
| 258 | - $span->setAttribute('url.full', $this->getFullUrl($request)); |
|
| 259 | - $span->setAttribute('server.address', $request->getUri()->getHost()); |
|
| 260 | - $span->setAttribute('server.port', $request->getUri()->getPort()); |
|
| 261 | - if (!empty($opts)) { |
|
| 262 | - $span->setAttributes($opts); |
|
| 263 | - } |
|
| 264 | - } |
|
| 265 | - $response = $this->client->sendRequest($request); |
|
| 266 | - $this->lastResponse = $response; |
|
| 267 | - $this->logResponse("Response", $response, $count); |
|
| 268 | - return $response; |
|
| 269 | - } catch (NetworkExceptionInterface $e) { |
|
| 270 | - $this->logger->error(sprintf("Retry %d: %s", $count, $e->getMessage())); |
|
| 271 | - if (!empty($span)) { |
|
| 272 | - $span->setAttribute('error.type', $e->getMessage()); |
|
| 273 | - } |
|
| 274 | - if (isset($node)) { |
|
| 275 | - $node->markAlive(\false); |
|
| 276 | - $node = $this->nodePool->nextNode(); |
|
| 277 | - $request = $this->setupConnectionUri($node, $request); |
|
| 278 | - } |
|
| 279 | - } catch (ClientExceptionInterface $e) { |
|
| 280 | - $this->logger->error(sprintf("Retry %d: %s", $count, $e->getMessage())); |
|
| 281 | - if (!empty($span)) { |
|
| 282 | - $span->setAttribute('error.type', $e->getMessage()); |
|
| 283 | - } |
|
| 284 | - throw $e; |
|
| 285 | - } finally { |
|
| 286 | - // OpenTelemetry span end |
|
| 287 | - if (!empty($span)) { |
|
| 288 | - $span->end(); |
|
| 289 | - } |
|
| 290 | - } |
|
| 291 | - } |
|
| 292 | - $exceededMsg = sprintf("Exceeded maximum number of retries (%d)", $this->getRetries()); |
|
| 293 | - $this->logger->error($exceededMsg); |
|
| 294 | - throw new NoNodeAvailableException($exceededMsg); |
|
| 295 | - } |
|
| 296 | - public function setAsyncClient(HttpAsyncClient $asyncClient) : self |
|
| 297 | - { |
|
| 298 | - $this->asyncClient = $asyncClient; |
|
| 299 | - return $this; |
|
| 300 | - } |
|
| 301 | - /** |
|
| 302 | - * @throws NoAsyncClientException |
|
| 303 | - */ |
|
| 304 | - public function getAsyncClient() : HttpAsyncClient |
|
| 305 | - { |
|
| 306 | - if (!empty($this->asyncClient)) { |
|
| 307 | - return $this->asyncClient; |
|
| 308 | - } |
|
| 309 | - if ($this->client instanceof HttpAsyncClient) { |
|
| 310 | - return $this->client; |
|
| 311 | - } |
|
| 312 | - try { |
|
| 313 | - $this->asyncClient = HttpAsyncClientDiscovery::find(); |
|
| 314 | - } catch (Exception $e) { |
|
| 315 | - throw new NoAsyncClientException(sprintf("I did not find any HTTP library with HttpAsyncClient interface. " . "Make sure to install a package providing \"php-http/async-client-implementation\". " . "You can also set a specific async library using %s::setAsyncClient()", self::class)); |
|
| 316 | - } |
|
| 317 | - return $this->asyncClient; |
|
| 318 | - } |
|
| 319 | - public function setAsyncOnSuccess(OnSuccessInterface $success) : self |
|
| 320 | - { |
|
| 321 | - $this->onAsyncSuccess = $success; |
|
| 322 | - return $this; |
|
| 323 | - } |
|
| 324 | - public function getAsyncOnSuccess() : OnSuccessInterface |
|
| 325 | - { |
|
| 326 | - if (empty($this->onAsyncSuccess)) { |
|
| 327 | - $this->onAsyncSuccess = new OnSuccessDefault(); |
|
| 328 | - } |
|
| 329 | - return $this->onAsyncSuccess; |
|
| 330 | - } |
|
| 331 | - public function setAsyncOnFailure(OnFailureInterface $failure) : self |
|
| 332 | - { |
|
| 333 | - $this->onAsyncFailure = $failure; |
|
| 334 | - return $this; |
|
| 335 | - } |
|
| 336 | - public function getAsyncOnFailure() : OnFailureInterface |
|
| 337 | - { |
|
| 338 | - if (empty($this->onAsyncFailure)) { |
|
| 339 | - $this->onAsyncFailure = new OnFailureDefault(); |
|
| 340 | - } |
|
| 341 | - return $this->onAsyncFailure; |
|
| 342 | - } |
|
| 343 | - /** |
|
| 344 | - * @throws Exception |
|
| 345 | - */ |
|
| 346 | - public function sendAsyncRequest(RequestInterface $request) : Promise |
|
| 347 | - { |
|
| 348 | - $client = $this->getAsyncClient(); |
|
| 349 | - $node = null; |
|
| 350 | - if (empty($request->getUri()->getHost())) { |
|
| 351 | - $node = $this->nodePool->nextNode(); |
|
| 352 | - $request = $this->setupConnectionUri($node, $request); |
|
| 353 | - } |
|
| 354 | - $request = $this->decorateRequest($request); |
|
| 355 | - $this->lastRequest = $request; |
|
| 356 | - $this->logRequest("Async Request", $request); |
|
| 357 | - $count = 0; |
|
| 358 | - $promise = $client->sendAsyncRequest($request); |
|
| 359 | - // onFulfilled callable |
|
| 360 | - $onFulfilled = function (ResponseInterface $response) use(&$count) { |
|
| 361 | - $this->lastResponse = $response; |
|
| 362 | - $this->logResponse("Async Response", $response, $count); |
|
| 363 | - return $this->getAsyncOnSuccess()->success($response, $count); |
|
| 364 | - }; |
|
| 365 | - // onRejected callable |
|
| 366 | - $onRejected = function (Exception $e) use($client, $request, &$count, $node) { |
|
| 367 | - $this->logger->error(sprintf("Retry %d: %s", $count, $e->getMessage())); |
|
| 368 | - $this->getAsyncOnFailure()->failure($e, $request, $count, $node ?? null); |
|
| 369 | - if (isset($node)) { |
|
| 370 | - $node->markAlive(\false); |
|
| 371 | - $node = $this->nodePool->nextNode(); |
|
| 372 | - $request = $this->setupConnectionUri($node, $request); |
|
| 373 | - } |
|
| 374 | - $count++; |
|
| 375 | - return $client->sendAsyncRequest($request); |
|
| 376 | - }; |
|
| 377 | - // Add getRetries() callables using then() |
|
| 378 | - for ($i = 0; $i < $this->getRetries(); $i++) { |
|
| 379 | - $promise = $promise->then($onFulfilled, $onRejected); |
|
| 380 | - } |
|
| 381 | - // Add the last getRetries()+1 callable for managing the exceeded error |
|
| 382 | - $promise = $promise->then($onFulfilled, function (Exception $e) use(&$count) { |
|
| 383 | - $exceededMsg = sprintf("Exceeded maximum number of retries (%d)", $this->getRetries()); |
|
| 384 | - $this->logger->error(sprintf("Retry %d: %s", $count, $e->getMessage())); |
|
| 385 | - $this->logger->error($exceededMsg); |
|
| 386 | - throw new NoNodeAvailableException(sprintf("%s: %s", $exceededMsg, $e->getMessage())); |
|
| 387 | - }); |
|
| 388 | - return $promise; |
|
| 389 | - } |
|
| 390 | - /** |
|
| 391 | - * Get the OS version using php_uname if available |
|
| 392 | - * otherwise it returns an empty string |
|
| 393 | - */ |
|
| 394 | - private function getOSVersion() : string |
|
| 395 | - { |
|
| 396 | - if (!isset($this->OSVersion)) { |
|
| 397 | - $disable_functions = (string) ini_get('disable_functions'); |
|
| 398 | - $this->OSVersion = strpos(strtolower($disable_functions), 'php_uname') !== \false ? '' : php_uname("r"); |
|
| 399 | - } |
|
| 400 | - return $this->OSVersion; |
|
| 401 | - } |
|
| 402 | - /** |
|
| 403 | - * Returns the name and the version of the Client HTTP library used |
|
| 404 | - * Here a list of supported libraries: |
|
| 405 | - * gu => guzzlehttp/guzzle |
|
| 406 | - * sy => symfony/http-client |
|
| 407 | - */ |
|
| 408 | - private function getClientLibraryInfo() : array |
|
| 409 | - { |
|
| 410 | - $clientClass = get_class($this->client); |
|
| 411 | - if (\false !== strpos($clientClass, 'OCA\\FullTextSearch_Elasticsearch\\Vendor\\GuzzleHttp\\Client')) { |
|
| 412 | - return ['gu', InstalledVersions::getPrettyVersion('guzzlehttp/guzzle')]; |
|
| 413 | - } |
|
| 414 | - if (\false !== strpos($clientClass, 'OCA\\FullTextSearch_Elasticsearch\\Vendor\\Symfony\\Component\\HttpClient')) { |
|
| 415 | - return ['sy', InstalledVersions::getPrettyVersion('symfony/http-client')]; |
|
| 416 | - } |
|
| 417 | - return []; |
|
| 418 | - } |
|
| 419 | - /** |
|
| 420 | - * Return the full URL in the format |
|
| 421 | - * scheme://host:port/path?query_string |
|
| 422 | - */ |
|
| 423 | - private function getFullUrl(RequestInterface $request) : string |
|
| 424 | - { |
|
| 425 | - $fullUrl = sprintf("%s://%s:%s%s", $request->getUri()->getScheme(), $request->getUri()->getHost(), $request->getUri()->getPort(), $request->getUri()->getPath()); |
|
| 426 | - $queryString = $request->getUri()->getQuery(); |
|
| 427 | - if (!empty($queryString)) { |
|
| 428 | - $fullUrl .= '?' . $queryString; |
|
| 429 | - } |
|
| 430 | - return $fullUrl; |
|
| 431 | - } |
|
| 52 | + const VERSION = "8.10.0"; |
|
| 53 | + private ClientInterface $client; |
|
| 54 | + private LoggerInterface $logger; |
|
| 55 | + private NodePoolInterface $nodePool; |
|
| 56 | + private array $headers = []; |
|
| 57 | + private string $user; |
|
| 58 | + private string $password; |
|
| 59 | + private RequestInterface $lastRequest; |
|
| 60 | + private ResponseInterface $lastResponse; |
|
| 61 | + private string $OSVersion; |
|
| 62 | + private int $retries = 0; |
|
| 63 | + private HttpAsyncClient $asyncClient; |
|
| 64 | + private OnSuccessInterface $onAsyncSuccess; |
|
| 65 | + private OnFailureInterface $onAsyncFailure; |
|
| 66 | + private TracerInterface $otelTracer; |
|
| 67 | + public function __construct(ClientInterface $client, NodePoolInterface $nodePool, LoggerInterface $logger) |
|
| 68 | + { |
|
| 69 | + $this->client = $client; |
|
| 70 | + $this->nodePool = $nodePool; |
|
| 71 | + $this->logger = $logger; |
|
| 72 | + } |
|
| 73 | + public function getClient() : ClientInterface |
|
| 74 | + { |
|
| 75 | + return $this->client; |
|
| 76 | + } |
|
| 77 | + public function getNodePool() : NodePoolInterface |
|
| 78 | + { |
|
| 79 | + return $this->nodePool; |
|
| 80 | + } |
|
| 81 | + public function getLogger() : LoggerInterface |
|
| 82 | + { |
|
| 83 | + return $this->logger; |
|
| 84 | + } |
|
| 85 | + public function getOTelTracer() : TracerInterface |
|
| 86 | + { |
|
| 87 | + if (empty($this->otelTracer)) { |
|
| 88 | + $this->otelTracer = OpenTelemetry::getTracer(Globals::tracerProvider()); |
|
| 89 | + } |
|
| 90 | + return $this->otelTracer; |
|
| 91 | + } |
|
| 92 | + public function setOTelTracer(TracerInterface $tracer) : self |
|
| 93 | + { |
|
| 94 | + $this->otelTracer = $tracer; |
|
| 95 | + return $this; |
|
| 96 | + } |
|
| 97 | + public function setHeader(string $name, string $value) : self |
|
| 98 | + { |
|
| 99 | + $this->headers[$name] = $value; |
|
| 100 | + return $this; |
|
| 101 | + } |
|
| 102 | + /** |
|
| 103 | + * @throws InvalidArgumentException |
|
| 104 | + */ |
|
| 105 | + public function setRetries(int $num) : self |
|
| 106 | + { |
|
| 107 | + if ($num < 0) { |
|
| 108 | + throw new InvalidArgumentException('The retries number must be a positive integer'); |
|
| 109 | + } |
|
| 110 | + $this->retries = $num; |
|
| 111 | + return $this; |
|
| 112 | + } |
|
| 113 | + public function getRetries() : int |
|
| 114 | + { |
|
| 115 | + return $this->retries; |
|
| 116 | + } |
|
| 117 | + public function getHeaders() : array |
|
| 118 | + { |
|
| 119 | + return $this->headers; |
|
| 120 | + } |
|
| 121 | + public function setUserInfo(string $user, string $password = '') : self |
|
| 122 | + { |
|
| 123 | + $this->user = $user; |
|
| 124 | + $this->password = $password; |
|
| 125 | + return $this; |
|
| 126 | + } |
|
| 127 | + public function setUserAgent(string $name, string $version) : self |
|
| 128 | + { |
|
| 129 | + $this->headers['User-Agent'] = sprintf("%s/%s (%s %s; PHP %s)", $name, $version, \PHP_OS, $this->getOSVersion(), phpversion()); |
|
| 130 | + return $this; |
|
| 131 | + } |
|
| 132 | + /** |
|
| 133 | + * Set the x-elastic-client-meta header |
|
| 134 | + * |
|
| 135 | + * The header format is specified by the following regex: |
|
| 136 | + * ^[a-z]{1,}=[a-z0-9\.\-]{1,}(?:,[a-z]{1,}=[a-z0-9\.\-]+)*$ |
|
| 137 | + */ |
|
| 138 | + public function setElasticMetaHeader(string $clientName, string $clientVersion, bool $async = \false) : self |
|
| 139 | + { |
|
| 140 | + $phpSemVersion = sprintf("%d.%d.%d", \PHP_MAJOR_VERSION, \PHP_MINOR_VERSION, \PHP_RELEASE_VERSION); |
|
| 141 | + $meta = sprintf("%s=%s,php=%s,t=%s,a=%d", $clientName, $this->purgePreReleaseTag($clientVersion), $phpSemVersion, $this->purgePreReleaseTag(self::VERSION), $async ? 1 : 0); |
|
| 142 | + $lib = $this->getClientLibraryInfo(); |
|
| 143 | + if (!empty($lib)) { |
|
| 144 | + $meta .= sprintf(",%s=%s", $lib[0], $lib[1]); |
|
| 145 | + } |
|
| 146 | + $this->headers['x-elastic-client-meta'] = $meta; |
|
| 147 | + return $this; |
|
| 148 | + } |
|
| 149 | + /** |
|
| 150 | + * Remove pre-release suffix with a single 'p' letter |
|
| 151 | + */ |
|
| 152 | + private function purgePreReleaseTag(string $version) : string |
|
| 153 | + { |
|
| 154 | + return str_replace(['alpha', 'beta', 'snapshot', 'rc', 'pre'], 'p', strtolower($version)); |
|
| 155 | + } |
|
| 156 | + public function getLastRequest() : RequestInterface |
|
| 157 | + { |
|
| 158 | + return $this->lastRequest; |
|
| 159 | + } |
|
| 160 | + public function getLastResponse() : ResponseInterface |
|
| 161 | + { |
|
| 162 | + return $this->lastResponse; |
|
| 163 | + } |
|
| 164 | + /** |
|
| 165 | + * Setup the headers, if not already present |
|
| 166 | + */ |
|
| 167 | + private function setupHeaders(RequestInterface $request) : RequestInterface |
|
| 168 | + { |
|
| 169 | + foreach ($this->headers as $name => $value) { |
|
| 170 | + if (!$request->hasHeader($name)) { |
|
| 171 | + $request = $request->withHeader($name, $value); |
|
| 172 | + } |
|
| 173 | + } |
|
| 174 | + return $request; |
|
| 175 | + } |
|
| 176 | + /** |
|
| 177 | + * Setup the user info, if not already present |
|
| 178 | + */ |
|
| 179 | + private function setupUserInfo(RequestInterface $request) : RequestInterface |
|
| 180 | + { |
|
| 181 | + $uri = $request->getUri(); |
|
| 182 | + if (empty($uri->getUserInfo())) { |
|
| 183 | + if (isset($this->user)) { |
|
| 184 | + $request = $request->withUri($uri->withUserInfo($this->user, $this->password)); |
|
| 185 | + } |
|
| 186 | + } |
|
| 187 | + return $request; |
|
| 188 | + } |
|
| 189 | + /** |
|
| 190 | + * Setup the connection Uri |
|
| 191 | + */ |
|
| 192 | + private function setupConnectionUri(Node $node, RequestInterface $request) : RequestInterface |
|
| 193 | + { |
|
| 194 | + $uri = $node->getUri(); |
|
| 195 | + $path = $request->getUri()->getPath(); |
|
| 196 | + $nodePath = $uri->getPath(); |
|
| 197 | + // If the node has a path we need to use it as prefix for the existing path |
|
| 198 | + // @see https://github.com/elastic/elastic-transport-php/pull/20 |
|
| 199 | + if (!empty($nodePath)) { |
|
| 200 | + $path = sprintf("%s/%s", \rtrim($nodePath, '/'), \ltrim($path, '/')); |
|
| 201 | + } |
|
| 202 | + // If the user information is not in the request, we check if it is present in the node uri |
|
| 203 | + // @see https://github.com/elastic/elastic-transport-php/issues/18 |
|
| 204 | + if (empty($request->getUri()->getUserInfo()) && !empty($uri->getUserInfo())) { |
|
| 205 | + $userInfo = \explode(':', $uri->getUserInfo()); |
|
| 206 | + $request = $request->withUri($request->getUri()->withUserInfo($userInfo[0], $userInfo[1] ?? null)); |
|
| 207 | + } |
|
| 208 | + return $request->withUri($request->getUri()->withHost($uri->getHost())->withPort($uri->getPort())->withScheme($uri->getScheme())->withPath($path)); |
|
| 209 | + } |
|
| 210 | + private function decorateRequest(RequestInterface $request) : RequestInterface |
|
| 211 | + { |
|
| 212 | + $request = $this->setupHeaders($request); |
|
| 213 | + return $this->setupUserInfo($request); |
|
| 214 | + } |
|
| 215 | + private function logHeaders(MessageInterface $message) : void |
|
| 216 | + { |
|
| 217 | + $this->logger->debug(sprintf("Headers: %s\nBody: %s", json_encode($message->getHeaders()), (string) $message->getBody())); |
|
| 218 | + } |
|
| 219 | + private function logRequest(string $title, RequestInterface $request) : void |
|
| 220 | + { |
|
| 221 | + $this->logger->info(sprintf("%s: %s %s", $title, $request->getMethod(), (string) $request->getUri()), ['request' => $request]); |
|
| 222 | + $this->logHeaders($request); |
|
| 223 | + } |
|
| 224 | + private function logResponse(string $title, ResponseInterface $response, int $retry) : void |
|
| 225 | + { |
|
| 226 | + $this->logger->info(sprintf("%s (retry %d): %d", $title, $retry, $response->getStatusCode()), ['response' => $response, 'retry' => $retry]); |
|
| 227 | + $this->logHeaders($response); |
|
| 228 | + } |
|
| 229 | + /** |
|
| 230 | + * @throws NoNodeAvailableException |
|
| 231 | + * @throws ClientExceptionInterface |
|
| 232 | + */ |
|
| 233 | + public function sendRequest(RequestInterface $request) : ResponseInterface |
|
| 234 | + { |
|
| 235 | + if (empty($request->getUri()->getHost())) { |
|
| 236 | + $node = $this->nodePool->nextNode(); |
|
| 237 | + $request = $this->setupConnectionUri($node, $request); |
|
| 238 | + } |
|
| 239 | + $request = $this->decorateRequest($request); |
|
| 240 | + $this->lastRequest = $request; |
|
| 241 | + $this->logRequest("Request", $request); |
|
| 242 | + // OpenTelemetry get tracer |
|
| 243 | + if (\getenv(OpenTelemetry::ENV_VARIABLE_ENABLED)) { |
|
| 244 | + $tracer = $this->getOTelTracer(); |
|
| 245 | + } |
|
| 246 | + $count = -1; |
|
| 247 | + while ($count < $this->getRetries()) { |
|
| 248 | + try { |
|
| 249 | + $count++; |
|
| 250 | + // OpenTelemetry span start |
|
| 251 | + if (!empty($tracer)) { |
|
| 252 | + if ($request instanceof ServerRequestInterface) { |
|
| 253 | + $opts = $request->getAttribute(OpenTelemetry::PSR7_OTEL_ATTRIBUTE_NAME, []); |
|
| 254 | + } |
|
| 255 | + $spanName = $opts['db.operation.name'] ?? $request->getUri()->getPath(); |
|
| 256 | + $span = $tracer->spanBuilder($spanName)->startSpan(); |
|
| 257 | + $span->setAttribute('http.request.method', $request->getMethod()); |
|
| 258 | + $span->setAttribute('url.full', $this->getFullUrl($request)); |
|
| 259 | + $span->setAttribute('server.address', $request->getUri()->getHost()); |
|
| 260 | + $span->setAttribute('server.port', $request->getUri()->getPort()); |
|
| 261 | + if (!empty($opts)) { |
|
| 262 | + $span->setAttributes($opts); |
|
| 263 | + } |
|
| 264 | + } |
|
| 265 | + $response = $this->client->sendRequest($request); |
|
| 266 | + $this->lastResponse = $response; |
|
| 267 | + $this->logResponse("Response", $response, $count); |
|
| 268 | + return $response; |
|
| 269 | + } catch (NetworkExceptionInterface $e) { |
|
| 270 | + $this->logger->error(sprintf("Retry %d: %s", $count, $e->getMessage())); |
|
| 271 | + if (!empty($span)) { |
|
| 272 | + $span->setAttribute('error.type', $e->getMessage()); |
|
| 273 | + } |
|
| 274 | + if (isset($node)) { |
|
| 275 | + $node->markAlive(\false); |
|
| 276 | + $node = $this->nodePool->nextNode(); |
|
| 277 | + $request = $this->setupConnectionUri($node, $request); |
|
| 278 | + } |
|
| 279 | + } catch (ClientExceptionInterface $e) { |
|
| 280 | + $this->logger->error(sprintf("Retry %d: %s", $count, $e->getMessage())); |
|
| 281 | + if (!empty($span)) { |
|
| 282 | + $span->setAttribute('error.type', $e->getMessage()); |
|
| 283 | + } |
|
| 284 | + throw $e; |
|
| 285 | + } finally { |
|
| 286 | + // OpenTelemetry span end |
|
| 287 | + if (!empty($span)) { |
|
| 288 | + $span->end(); |
|
| 289 | + } |
|
| 290 | + } |
|
| 291 | + } |
|
| 292 | + $exceededMsg = sprintf("Exceeded maximum number of retries (%d)", $this->getRetries()); |
|
| 293 | + $this->logger->error($exceededMsg); |
|
| 294 | + throw new NoNodeAvailableException($exceededMsg); |
|
| 295 | + } |
|
| 296 | + public function setAsyncClient(HttpAsyncClient $asyncClient) : self |
|
| 297 | + { |
|
| 298 | + $this->asyncClient = $asyncClient; |
|
| 299 | + return $this; |
|
| 300 | + } |
|
| 301 | + /** |
|
| 302 | + * @throws NoAsyncClientException |
|
| 303 | + */ |
|
| 304 | + public function getAsyncClient() : HttpAsyncClient |
|
| 305 | + { |
|
| 306 | + if (!empty($this->asyncClient)) { |
|
| 307 | + return $this->asyncClient; |
|
| 308 | + } |
|
| 309 | + if ($this->client instanceof HttpAsyncClient) { |
|
| 310 | + return $this->client; |
|
| 311 | + } |
|
| 312 | + try { |
|
| 313 | + $this->asyncClient = HttpAsyncClientDiscovery::find(); |
|
| 314 | + } catch (Exception $e) { |
|
| 315 | + throw new NoAsyncClientException(sprintf("I did not find any HTTP library with HttpAsyncClient interface. " . "Make sure to install a package providing \"php-http/async-client-implementation\". " . "You can also set a specific async library using %s::setAsyncClient()", self::class)); |
|
| 316 | + } |
|
| 317 | + return $this->asyncClient; |
|
| 318 | + } |
|
| 319 | + public function setAsyncOnSuccess(OnSuccessInterface $success) : self |
|
| 320 | + { |
|
| 321 | + $this->onAsyncSuccess = $success; |
|
| 322 | + return $this; |
|
| 323 | + } |
|
| 324 | + public function getAsyncOnSuccess() : OnSuccessInterface |
|
| 325 | + { |
|
| 326 | + if (empty($this->onAsyncSuccess)) { |
|
| 327 | + $this->onAsyncSuccess = new OnSuccessDefault(); |
|
| 328 | + } |
|
| 329 | + return $this->onAsyncSuccess; |
|
| 330 | + } |
|
| 331 | + public function setAsyncOnFailure(OnFailureInterface $failure) : self |
|
| 332 | + { |
|
| 333 | + $this->onAsyncFailure = $failure; |
|
| 334 | + return $this; |
|
| 335 | + } |
|
| 336 | + public function getAsyncOnFailure() : OnFailureInterface |
|
| 337 | + { |
|
| 338 | + if (empty($this->onAsyncFailure)) { |
|
| 339 | + $this->onAsyncFailure = new OnFailureDefault(); |
|
| 340 | + } |
|
| 341 | + return $this->onAsyncFailure; |
|
| 342 | + } |
|
| 343 | + /** |
|
| 344 | + * @throws Exception |
|
| 345 | + */ |
|
| 346 | + public function sendAsyncRequest(RequestInterface $request) : Promise |
|
| 347 | + { |
|
| 348 | + $client = $this->getAsyncClient(); |
|
| 349 | + $node = null; |
|
| 350 | + if (empty($request->getUri()->getHost())) { |
|
| 351 | + $node = $this->nodePool->nextNode(); |
|
| 352 | + $request = $this->setupConnectionUri($node, $request); |
|
| 353 | + } |
|
| 354 | + $request = $this->decorateRequest($request); |
|
| 355 | + $this->lastRequest = $request; |
|
| 356 | + $this->logRequest("Async Request", $request); |
|
| 357 | + $count = 0; |
|
| 358 | + $promise = $client->sendAsyncRequest($request); |
|
| 359 | + // onFulfilled callable |
|
| 360 | + $onFulfilled = function (ResponseInterface $response) use(&$count) { |
|
| 361 | + $this->lastResponse = $response; |
|
| 362 | + $this->logResponse("Async Response", $response, $count); |
|
| 363 | + return $this->getAsyncOnSuccess()->success($response, $count); |
|
| 364 | + }; |
|
| 365 | + // onRejected callable |
|
| 366 | + $onRejected = function (Exception $e) use($client, $request, &$count, $node) { |
|
| 367 | + $this->logger->error(sprintf("Retry %d: %s", $count, $e->getMessage())); |
|
| 368 | + $this->getAsyncOnFailure()->failure($e, $request, $count, $node ?? null); |
|
| 369 | + if (isset($node)) { |
|
| 370 | + $node->markAlive(\false); |
|
| 371 | + $node = $this->nodePool->nextNode(); |
|
| 372 | + $request = $this->setupConnectionUri($node, $request); |
|
| 373 | + } |
|
| 374 | + $count++; |
|
| 375 | + return $client->sendAsyncRequest($request); |
|
| 376 | + }; |
|
| 377 | + // Add getRetries() callables using then() |
|
| 378 | + for ($i = 0; $i < $this->getRetries(); $i++) { |
|
| 379 | + $promise = $promise->then($onFulfilled, $onRejected); |
|
| 380 | + } |
|
| 381 | + // Add the last getRetries()+1 callable for managing the exceeded error |
|
| 382 | + $promise = $promise->then($onFulfilled, function (Exception $e) use(&$count) { |
|
| 383 | + $exceededMsg = sprintf("Exceeded maximum number of retries (%d)", $this->getRetries()); |
|
| 384 | + $this->logger->error(sprintf("Retry %d: %s", $count, $e->getMessage())); |
|
| 385 | + $this->logger->error($exceededMsg); |
|
| 386 | + throw new NoNodeAvailableException(sprintf("%s: %s", $exceededMsg, $e->getMessage())); |
|
| 387 | + }); |
|
| 388 | + return $promise; |
|
| 389 | + } |
|
| 390 | + /** |
|
| 391 | + * Get the OS version using php_uname if available |
|
| 392 | + * otherwise it returns an empty string |
|
| 393 | + */ |
|
| 394 | + private function getOSVersion() : string |
|
| 395 | + { |
|
| 396 | + if (!isset($this->OSVersion)) { |
|
| 397 | + $disable_functions = (string) ini_get('disable_functions'); |
|
| 398 | + $this->OSVersion = strpos(strtolower($disable_functions), 'php_uname') !== \false ? '' : php_uname("r"); |
|
| 399 | + } |
|
| 400 | + return $this->OSVersion; |
|
| 401 | + } |
|
| 402 | + /** |
|
| 403 | + * Returns the name and the version of the Client HTTP library used |
|
| 404 | + * Here a list of supported libraries: |
|
| 405 | + * gu => guzzlehttp/guzzle |
|
| 406 | + * sy => symfony/http-client |
|
| 407 | + */ |
|
| 408 | + private function getClientLibraryInfo() : array |
|
| 409 | + { |
|
| 410 | + $clientClass = get_class($this->client); |
|
| 411 | + if (\false !== strpos($clientClass, 'OCA\\FullTextSearch_Elasticsearch\\Vendor\\GuzzleHttp\\Client')) { |
|
| 412 | + return ['gu', InstalledVersions::getPrettyVersion('guzzlehttp/guzzle')]; |
|
| 413 | + } |
|
| 414 | + if (\false !== strpos($clientClass, 'OCA\\FullTextSearch_Elasticsearch\\Vendor\\Symfony\\Component\\HttpClient')) { |
|
| 415 | + return ['sy', InstalledVersions::getPrettyVersion('symfony/http-client')]; |
|
| 416 | + } |
|
| 417 | + return []; |
|
| 418 | + } |
|
| 419 | + /** |
|
| 420 | + * Return the full URL in the format |
|
| 421 | + * scheme://host:port/path?query_string |
|
| 422 | + */ |
|
| 423 | + private function getFullUrl(RequestInterface $request) : string |
|
| 424 | + { |
|
| 425 | + $fullUrl = sprintf("%s://%s:%s%s", $request->getUri()->getScheme(), $request->getUri()->getHost(), $request->getUri()->getPort(), $request->getUri()->getPath()); |
|
| 426 | + $queryString = $request->getUri()->getQuery(); |
|
| 427 | + if (!empty($queryString)) { |
|
| 428 | + $fullUrl .= '?' . $queryString; |
|
| 429 | + } |
|
| 430 | + return $fullUrl; |
|
| 431 | + } |
|
| 432 | 432 | } |
@@ -11,7 +11,7 @@ discard block |
||
| 11 | 11 | * Elasticsearch B.V licenses this file to you under the MIT License. |
| 12 | 12 | * See the LICENSE file in the project root for more information. |
| 13 | 13 | */ |
| 14 | -declare (strict_types=1); |
|
| 14 | +declare(strict_types=1); |
|
| 15 | 15 | namespace OCA\FullTextSearch_Elasticsearch\Vendor\Elastic\Transport; |
| 16 | 16 | |
| 17 | 17 | use Composer\InstalledVersions; |
@@ -214,11 +214,11 @@ discard block |
||
| 214 | 214 | } |
| 215 | 215 | private function logHeaders(MessageInterface $message) : void |
| 216 | 216 | { |
| 217 | - $this->logger->debug(sprintf("Headers: %s\nBody: %s", json_encode($message->getHeaders()), (string) $message->getBody())); |
|
| 217 | + $this->logger->debug(sprintf("Headers: %s\nBody: %s", json_encode($message->getHeaders()), (string)$message->getBody())); |
|
| 218 | 218 | } |
| 219 | 219 | private function logRequest(string $title, RequestInterface $request) : void |
| 220 | 220 | { |
| 221 | - $this->logger->info(sprintf("%s: %s %s", $title, $request->getMethod(), (string) $request->getUri()), ['request' => $request]); |
|
| 221 | + $this->logger->info(sprintf("%s: %s %s", $title, $request->getMethod(), (string)$request->getUri()), ['request' => $request]); |
|
| 222 | 222 | $this->logHeaders($request); |
| 223 | 223 | } |
| 224 | 224 | private function logResponse(string $title, ResponseInterface $response, int $retry) : void |
@@ -312,7 +312,7 @@ discard block |
||
| 312 | 312 | try { |
| 313 | 313 | $this->asyncClient = HttpAsyncClientDiscovery::find(); |
| 314 | 314 | } catch (Exception $e) { |
| 315 | - throw new NoAsyncClientException(sprintf("I did not find any HTTP library with HttpAsyncClient interface. " . "Make sure to install a package providing \"php-http/async-client-implementation\". " . "You can also set a specific async library using %s::setAsyncClient()", self::class)); |
|
| 315 | + throw new NoAsyncClientException(sprintf("I did not find any HTTP library with HttpAsyncClient interface. "."Make sure to install a package providing \"php-http/async-client-implementation\". "."You can also set a specific async library using %s::setAsyncClient()", self::class)); |
|
| 316 | 316 | } |
| 317 | 317 | return $this->asyncClient; |
| 318 | 318 | } |
@@ -357,13 +357,13 @@ discard block |
||
| 357 | 357 | $count = 0; |
| 358 | 358 | $promise = $client->sendAsyncRequest($request); |
| 359 | 359 | // onFulfilled callable |
| 360 | - $onFulfilled = function (ResponseInterface $response) use(&$count) { |
|
| 360 | + $onFulfilled = function(ResponseInterface $response) use(&$count) { |
|
| 361 | 361 | $this->lastResponse = $response; |
| 362 | 362 | $this->logResponse("Async Response", $response, $count); |
| 363 | 363 | return $this->getAsyncOnSuccess()->success($response, $count); |
| 364 | 364 | }; |
| 365 | 365 | // onRejected callable |
| 366 | - $onRejected = function (Exception $e) use($client, $request, &$count, $node) { |
|
| 366 | + $onRejected = function(Exception $e) use($client, $request, &$count, $node) { |
|
| 367 | 367 | $this->logger->error(sprintf("Retry %d: %s", $count, $e->getMessage())); |
| 368 | 368 | $this->getAsyncOnFailure()->failure($e, $request, $count, $node ?? null); |
| 369 | 369 | if (isset($node)) { |
@@ -379,7 +379,7 @@ discard block |
||
| 379 | 379 | $promise = $promise->then($onFulfilled, $onRejected); |
| 380 | 380 | } |
| 381 | 381 | // Add the last getRetries()+1 callable for managing the exceeded error |
| 382 | - $promise = $promise->then($onFulfilled, function (Exception $e) use(&$count) { |
|
| 382 | + $promise = $promise->then($onFulfilled, function(Exception $e) use(&$count) { |
|
| 383 | 383 | $exceededMsg = sprintf("Exceeded maximum number of retries (%d)", $this->getRetries()); |
| 384 | 384 | $this->logger->error(sprintf("Retry %d: %s", $count, $e->getMessage())); |
| 385 | 385 | $this->logger->error($exceededMsg); |
@@ -394,7 +394,7 @@ discard block |
||
| 394 | 394 | private function getOSVersion() : string |
| 395 | 395 | { |
| 396 | 396 | if (!isset($this->OSVersion)) { |
| 397 | - $disable_functions = (string) ini_get('disable_functions'); |
|
| 397 | + $disable_functions = (string)ini_get('disable_functions'); |
|
| 398 | 398 | $this->OSVersion = strpos(strtolower($disable_functions), 'php_uname') !== \false ? '' : php_uname("r"); |
| 399 | 399 | } |
| 400 | 400 | return $this->OSVersion; |
@@ -425,7 +425,7 @@ discard block |
||
| 425 | 425 | $fullUrl = sprintf("%s://%s:%s%s", $request->getUri()->getScheme(), $request->getUri()->getHost(), $request->getUri()->getPort(), $request->getUri()->getPath()); |
| 426 | 426 | $queryString = $request->getUri()->getQuery(); |
| 427 | 427 | if (!empty($queryString)) { |
| 428 | - $fullUrl .= '?' . $queryString; |
|
| 428 | + $fullUrl .= '?'.$queryString; |
|
| 429 | 429 | } |
| 430 | 430 | return $fullUrl; |
| 431 | 431 | } |
@@ -27,84 +27,84 @@ |
||
| 27 | 27 | use Throwable; |
| 28 | 28 | class TransportBuilder |
| 29 | 29 | { |
| 30 | - protected ClientInterface $client; |
|
| 31 | - protected NodePoolInterface $nodePool; |
|
| 32 | - protected LoggerInterface $logger; |
|
| 33 | - protected array $hosts = []; |
|
| 34 | - protected TracerInterface $OTelTracer; |
|
| 35 | - public final function __construct() |
|
| 36 | - { |
|
| 37 | - } |
|
| 38 | - public static function create() : TransportBuilder |
|
| 39 | - { |
|
| 40 | - return new static(); |
|
| 41 | - } |
|
| 42 | - public function setClient(ClientInterface $client) : self |
|
| 43 | - { |
|
| 44 | - $this->client = $client; |
|
| 45 | - return $this; |
|
| 46 | - } |
|
| 47 | - public function getClient() : ClientInterface |
|
| 48 | - { |
|
| 49 | - if (empty($this->client)) { |
|
| 50 | - $this->client = Psr18ClientDiscovery::find(); |
|
| 51 | - } |
|
| 52 | - return $this->client; |
|
| 53 | - } |
|
| 54 | - public function setNodePool(NodePoolInterface $nodePool) : self |
|
| 55 | - { |
|
| 56 | - $this->nodePool = $nodePool; |
|
| 57 | - return $this; |
|
| 58 | - } |
|
| 59 | - public function getNodePool() : NodePoolInterface |
|
| 60 | - { |
|
| 61 | - if (empty($this->nodePool)) { |
|
| 62 | - $this->nodePool = new SimpleNodePool(new RoundRobin(), new NoResurrect()); |
|
| 63 | - } |
|
| 64 | - return $this->nodePool; |
|
| 65 | - } |
|
| 66 | - public function setLogger(LoggerInterface $logger) : self |
|
| 67 | - { |
|
| 68 | - $this->logger = $logger; |
|
| 69 | - return $this; |
|
| 70 | - } |
|
| 71 | - public function getLogger() : LoggerInterface |
|
| 72 | - { |
|
| 73 | - if (empty($this->logger)) { |
|
| 74 | - $this->logger = new NullLogger(); |
|
| 75 | - } |
|
| 76 | - return $this->logger; |
|
| 77 | - } |
|
| 78 | - public function setHosts(array $hosts) : self |
|
| 79 | - { |
|
| 80 | - $this->hosts = $hosts; |
|
| 81 | - return $this; |
|
| 82 | - } |
|
| 83 | - public function getHosts() : array |
|
| 84 | - { |
|
| 85 | - return $this->hosts; |
|
| 86 | - } |
|
| 87 | - public function setCloudId(string $cloudId) : self |
|
| 88 | - { |
|
| 89 | - $this->hosts = [$this->parseElasticCloudId($cloudId)]; |
|
| 90 | - return $this; |
|
| 91 | - } |
|
| 92 | - public function build() : Transport |
|
| 93 | - { |
|
| 94 | - return new Transport($this->getClient(), $this->getNodePool()->setHosts($this->hosts), $this->getLogger()); |
|
| 95 | - } |
|
| 96 | - /** |
|
| 97 | - * Return the URL of Elastic Cloud from the Cloud ID |
|
| 98 | - */ |
|
| 99 | - private function parseElasticCloudId(string $cloudId) : string |
|
| 100 | - { |
|
| 101 | - try { |
|
| 102 | - list($name, $encoded) = \explode(':', $cloudId); |
|
| 103 | - list($uri, $uuids) = \explode('$', \base64_decode($encoded)); |
|
| 104 | - list($es, ) = \explode(':', $uuids); |
|
| 105 | - return \sprintf("https://%s.%s", $es, $uri); |
|
| 106 | - } catch (Throwable $t) { |
|
| 107 | - throw new Exception\CloudIdParseException('Cloud ID not valid'); |
|
| 108 | - } |
|
| 109 | - } |
|
| 30 | + protected ClientInterface $client; |
|
| 31 | + protected NodePoolInterface $nodePool; |
|
| 32 | + protected LoggerInterface $logger; |
|
| 33 | + protected array $hosts = []; |
|
| 34 | + protected TracerInterface $OTelTracer; |
|
| 35 | + public final function __construct() |
|
| 36 | + { |
|
| 37 | + } |
|
| 38 | + public static function create() : TransportBuilder |
|
| 39 | + { |
|
| 40 | + return new static(); |
|
| 41 | + } |
|
| 42 | + public function setClient(ClientInterface $client) : self |
|
| 43 | + { |
|
| 44 | + $this->client = $client; |
|
| 45 | + return $this; |
|
| 46 | + } |
|
| 47 | + public function getClient() : ClientInterface |
|
| 48 | + { |
|
| 49 | + if (empty($this->client)) { |
|
| 50 | + $this->client = Psr18ClientDiscovery::find(); |
|
| 51 | + } |
|
| 52 | + return $this->client; |
|
| 53 | + } |
|
| 54 | + public function setNodePool(NodePoolInterface $nodePool) : self |
|
| 55 | + { |
|
| 56 | + $this->nodePool = $nodePool; |
|
| 57 | + return $this; |
|
| 58 | + } |
|
| 59 | + public function getNodePool() : NodePoolInterface |
|
| 60 | + { |
|
| 61 | + if (empty($this->nodePool)) { |
|
| 62 | + $this->nodePool = new SimpleNodePool(new RoundRobin(), new NoResurrect()); |
|
| 63 | + } |
|
| 64 | + return $this->nodePool; |
|
| 65 | + } |
|
| 66 | + public function setLogger(LoggerInterface $logger) : self |
|
| 67 | + { |
|
| 68 | + $this->logger = $logger; |
|
| 69 | + return $this; |
|
| 70 | + } |
|
| 71 | + public function getLogger() : LoggerInterface |
|
| 72 | + { |
|
| 73 | + if (empty($this->logger)) { |
|
| 74 | + $this->logger = new NullLogger(); |
|
| 75 | + } |
|
| 76 | + return $this->logger; |
|
| 77 | + } |
|
| 78 | + public function setHosts(array $hosts) : self |
|
| 79 | + { |
|
| 80 | + $this->hosts = $hosts; |
|
| 81 | + return $this; |
|
| 82 | + } |
|
| 83 | + public function getHosts() : array |
|
| 84 | + { |
|
| 85 | + return $this->hosts; |
|
| 86 | + } |
|
| 87 | + public function setCloudId(string $cloudId) : self |
|
| 88 | + { |
|
| 89 | + $this->hosts = [$this->parseElasticCloudId($cloudId)]; |
|
| 90 | + return $this; |
|
| 91 | + } |
|
| 92 | + public function build() : Transport |
|
| 93 | + { |
|
| 94 | + return new Transport($this->getClient(), $this->getNodePool()->setHosts($this->hosts), $this->getLogger()); |
|
| 95 | + } |
|
| 96 | + /** |
|
| 97 | + * Return the URL of Elastic Cloud from the Cloud ID |
|
| 98 | + */ |
|
| 99 | + private function parseElasticCloudId(string $cloudId) : string |
|
| 100 | + { |
|
| 101 | + try { |
|
| 102 | + list($name, $encoded) = \explode(':', $cloudId); |
|
| 103 | + list($uri, $uuids) = \explode('$', \base64_decode($encoded)); |
|
| 104 | + list($es, ) = \explode(':', $uuids); |
|
| 105 | + return \sprintf("https://%s.%s", $es, $uri); |
|
| 106 | + } catch (Throwable $t) { |
|
| 107 | + throw new Exception\CloudIdParseException('Cloud ID not valid'); |
|
| 108 | + } |
|
| 109 | + } |
|
| 110 | 110 | } |
@@ -20,72 +20,72 @@ |
||
| 20 | 20 | use OCA\FullTextSearch_Elasticsearch\Vendor\OpenTelemetry\API\Trace\TracerProviderInterface; |
| 21 | 21 | class OpenTelemetry |
| 22 | 22 | { |
| 23 | - const OTEL_TRACER_NAME = 'elasticsearch-api'; |
|
| 24 | - const PSR7_OTEL_ATTRIBUTE_NAME = 'otel-elastic-transport'; |
|
| 25 | - // Valid values for the enabled config are 'true' and 'false' |
|
| 26 | - const ENV_VARIABLE_ENABLED = 'OTEL_PHP_INSTRUMENTATION_ELASTICSEARCH_ENABLED'; |
|
| 27 | - /** |
|
| 28 | - * Describes how to handle search queries in the request body when assigned to |
|
| 29 | - * span attribute. |
|
| 30 | - * Valid values are 'raw', 'omit', 'sanitize'. Default is 'omit' |
|
| 31 | - */ |
|
| 32 | - const ALLOWED_BODY_STRATEGIES = ['raw', 'omit', 'sanitize']; |
|
| 33 | - const ENV_VARIABLE_BODY_STRATEGY = 'OTEL_PHP_INSTRUMENTATION_ELASTICSEARCH_CAPTURE_SEARCH_QUERY'; |
|
| 34 | - const DEFAULT_BODY_STRATEGY = 'omit'; |
|
| 35 | - /** |
|
| 36 | - * A string list of keys whose values are redacted. This is only relevant if the body strategy is |
|
| 37 | - * 'sanitize'. For example, a config 'sensitive-key,other-key' will redact the values at |
|
| 38 | - * 'sensitive-key' and 'other-key' in addition to the default keys |
|
| 39 | - */ |
|
| 40 | - const ENV_VARIABLE_BODY_SANITIZE_KEYS = 'OTEL_PHP_INSTRUMENTATION_ELASTICSEARCH_SEARCH_QUERY_SANITIZE_KEYS'; |
|
| 41 | - const DEFAULT_SANITIZER_KEY_PATTERNS = ['password', 'passwd', 'pwd', 'secret', 'key', 'token', 'session', 'credit', 'card', 'auth', 'set-cookie', 'email', 'tel', 'phone']; |
|
| 42 | - const REDACTED_STRING = 'REDACTED'; |
|
| 43 | - public static function redactBody(string $body) : string |
|
| 44 | - { |
|
| 45 | - switch (self::getBodyStrategy()) { |
|
| 46 | - case 'sanitize': |
|
| 47 | - $sanitizeKeys = \getenv(self::ENV_VARIABLE_BODY_SANITIZE_KEYS); |
|
| 48 | - $sanitizeKeys = \false !== $sanitizeKeys ? \explode(',', $sanitizeKeys) : []; |
|
| 49 | - return self::sanitizeBody($body, $sanitizeKeys); |
|
| 50 | - case 'raw': |
|
| 51 | - return $body; |
|
| 52 | - default: |
|
| 53 | - return ''; |
|
| 54 | - } |
|
| 55 | - } |
|
| 56 | - private static function getBodyStrategy() : string |
|
| 57 | - { |
|
| 58 | - $strategy = \getenv(self::ENV_VARIABLE_BODY_STRATEGY); |
|
| 59 | - if (\false === $strategy) { |
|
| 60 | - $strategy = self::DEFAULT_BODY_STRATEGY; |
|
| 61 | - } |
|
| 62 | - if (!\in_array($strategy, self::ALLOWED_BODY_STRATEGIES)) { |
|
| 63 | - throw new InvalidArgumentException(\sprintf('The body strategy specified %s is not valid. The available strategies are %s', $strategy, \implode(',', self::ALLOWED_BODY_STRATEGIES))); |
|
| 64 | - } |
|
| 65 | - return $strategy; |
|
| 66 | - } |
|
| 67 | - public static function getTracer(TracerProviderInterface $tracerProvider) : TracerInterface |
|
| 68 | - { |
|
| 69 | - return $tracerProvider->getTracer(self::OTEL_TRACER_NAME, Transport::VERSION); |
|
| 70 | - } |
|
| 71 | - private static function sanitizeBody(string $body, array $sanitizeKeys) : string |
|
| 72 | - { |
|
| 73 | - if (empty($body)) { |
|
| 74 | - return ''; |
|
| 75 | - } |
|
| 76 | - $json = \json_decode($body, \true); |
|
| 77 | - if (!\is_array($json)) { |
|
| 78 | - return ''; |
|
| 79 | - } |
|
| 80 | - $patterns = \array_merge(self::DEFAULT_SANITIZER_KEY_PATTERNS, $sanitizeKeys); |
|
| 81 | - // Convert the patterns array into a regex |
|
| 82 | - $regex = \sprintf('/%s/', \implode('|', $patterns)); |
|
| 83 | - // Recursively traverse the array and redact the specified keys |
|
| 84 | - \array_walk_recursive($json, function (&$value, $key) use($regex) { |
|
| 85 | - if (\preg_match($regex, $key, $matches)) { |
|
| 86 | - $value = self::REDACTED_STRING; |
|
| 87 | - } |
|
| 88 | - }); |
|
| 89 | - return JsonSerializer::serialize($json); |
|
| 90 | - } |
|
| 23 | + const OTEL_TRACER_NAME = 'elasticsearch-api'; |
|
| 24 | + const PSR7_OTEL_ATTRIBUTE_NAME = 'otel-elastic-transport'; |
|
| 25 | + // Valid values for the enabled config are 'true' and 'false' |
|
| 26 | + const ENV_VARIABLE_ENABLED = 'OTEL_PHP_INSTRUMENTATION_ELASTICSEARCH_ENABLED'; |
|
| 27 | + /** |
|
| 28 | + * Describes how to handle search queries in the request body when assigned to |
|
| 29 | + * span attribute. |
|
| 30 | + * Valid values are 'raw', 'omit', 'sanitize'. Default is 'omit' |
|
| 31 | + */ |
|
| 32 | + const ALLOWED_BODY_STRATEGIES = ['raw', 'omit', 'sanitize']; |
|
| 33 | + const ENV_VARIABLE_BODY_STRATEGY = 'OTEL_PHP_INSTRUMENTATION_ELASTICSEARCH_CAPTURE_SEARCH_QUERY'; |
|
| 34 | + const DEFAULT_BODY_STRATEGY = 'omit'; |
|
| 35 | + /** |
|
| 36 | + * A string list of keys whose values are redacted. This is only relevant if the body strategy is |
|
| 37 | + * 'sanitize'. For example, a config 'sensitive-key,other-key' will redact the values at |
|
| 38 | + * 'sensitive-key' and 'other-key' in addition to the default keys |
|
| 39 | + */ |
|
| 40 | + const ENV_VARIABLE_BODY_SANITIZE_KEYS = 'OTEL_PHP_INSTRUMENTATION_ELASTICSEARCH_SEARCH_QUERY_SANITIZE_KEYS'; |
|
| 41 | + const DEFAULT_SANITIZER_KEY_PATTERNS = ['password', 'passwd', 'pwd', 'secret', 'key', 'token', 'session', 'credit', 'card', 'auth', 'set-cookie', 'email', 'tel', 'phone']; |
|
| 42 | + const REDACTED_STRING = 'REDACTED'; |
|
| 43 | + public static function redactBody(string $body) : string |
|
| 44 | + { |
|
| 45 | + switch (self::getBodyStrategy()) { |
|
| 46 | + case 'sanitize': |
|
| 47 | + $sanitizeKeys = \getenv(self::ENV_VARIABLE_BODY_SANITIZE_KEYS); |
|
| 48 | + $sanitizeKeys = \false !== $sanitizeKeys ? \explode(',', $sanitizeKeys) : []; |
|
| 49 | + return self::sanitizeBody($body, $sanitizeKeys); |
|
| 50 | + case 'raw': |
|
| 51 | + return $body; |
|
| 52 | + default: |
|
| 53 | + return ''; |
|
| 54 | + } |
|
| 55 | + } |
|
| 56 | + private static function getBodyStrategy() : string |
|
| 57 | + { |
|
| 58 | + $strategy = \getenv(self::ENV_VARIABLE_BODY_STRATEGY); |
|
| 59 | + if (\false === $strategy) { |
|
| 60 | + $strategy = self::DEFAULT_BODY_STRATEGY; |
|
| 61 | + } |
|
| 62 | + if (!\in_array($strategy, self::ALLOWED_BODY_STRATEGIES)) { |
|
| 63 | + throw new InvalidArgumentException(\sprintf('The body strategy specified %s is not valid. The available strategies are %s', $strategy, \implode(',', self::ALLOWED_BODY_STRATEGIES))); |
|
| 64 | + } |
|
| 65 | + return $strategy; |
|
| 66 | + } |
|
| 67 | + public static function getTracer(TracerProviderInterface $tracerProvider) : TracerInterface |
|
| 68 | + { |
|
| 69 | + return $tracerProvider->getTracer(self::OTEL_TRACER_NAME, Transport::VERSION); |
|
| 70 | + } |
|
| 71 | + private static function sanitizeBody(string $body, array $sanitizeKeys) : string |
|
| 72 | + { |
|
| 73 | + if (empty($body)) { |
|
| 74 | + return ''; |
|
| 75 | + } |
|
| 76 | + $json = \json_decode($body, \true); |
|
| 77 | + if (!\is_array($json)) { |
|
| 78 | + return ''; |
|
| 79 | + } |
|
| 80 | + $patterns = \array_merge(self::DEFAULT_SANITIZER_KEY_PATTERNS, $sanitizeKeys); |
|
| 81 | + // Convert the patterns array into a regex |
|
| 82 | + $regex = \sprintf('/%s/', \implode('|', $patterns)); |
|
| 83 | + // Recursively traverse the array and redact the specified keys |
|
| 84 | + \array_walk_recursive($json, function (&$value, $key) use($regex) { |
|
| 85 | + if (\preg_match($regex, $key, $matches)) { |
|
| 86 | + $value = self::REDACTED_STRING; |
|
| 87 | + } |
|
| 88 | + }); |
|
| 89 | + return JsonSerializer::serialize($json); |
|
| 90 | + } |
|
| 91 | 91 | } |
@@ -11,7 +11,7 @@ discard block |
||
| 11 | 11 | * Elasticsearch B.V licenses this file to you under the MIT License. |
| 12 | 12 | * See the LICENSE file in the project root for more information. |
| 13 | 13 | */ |
| 14 | -declare (strict_types=1); |
|
| 14 | +declare(strict_types=1); |
|
| 15 | 15 | namespace OCA\FullTextSearch_Elasticsearch\Vendor\Elastic\Transport; |
| 16 | 16 | |
| 17 | 17 | use OCA\FullTextSearch_Elasticsearch\Vendor\Elastic\Transport\Exception\InvalidArgumentException; |
@@ -81,7 +81,7 @@ discard block |
||
| 81 | 81 | // Convert the patterns array into a regex |
| 82 | 82 | $regex = \sprintf('/%s/', \implode('|', $patterns)); |
| 83 | 83 | // Recursively traverse the array and redact the specified keys |
| 84 | - \array_walk_recursive($json, function (&$value, $key) use($regex) { |
|
| 84 | + \array_walk_recursive($json, function(&$value, $key) use($regex) { |
|
| 85 | 85 | if (\preg_match($regex, $key, $matches)) { |
| 86 | 86 | $value = self::REDACTED_STRING; |
| 87 | 87 | } |
@@ -18,8 +18,7 @@ |
||
| 18 | 18 | use OCA\FullTextSearch_Elasticsearch\Vendor\Elastic\Transport\Serializer\JsonSerializer; |
| 19 | 19 | use OCA\FullTextSearch_Elasticsearch\Vendor\OpenTelemetry\API\Trace\TracerInterface; |
| 20 | 20 | use OCA\FullTextSearch_Elasticsearch\Vendor\OpenTelemetry\API\Trace\TracerProviderInterface; |
| 21 | -class OpenTelemetry |
|
| 22 | -{ |
|
| 21 | +class OpenTelemetry { |
|
| 23 | 22 | const OTEL_TRACER_NAME = 'elasticsearch-api'; |
| 24 | 23 | const PSR7_OTEL_ATTRIBUTE_NAME = 'otel-elastic-transport'; |
| 25 | 24 | // Valid values for the enabled config are 'true' and 'false' |