Обновление клиента (apps, 3rdparty, install)

This commit is contained in:
root
2026-03-16 08:42:57 +00:00
parent b8905de237
commit f390426546
3354 changed files with 505213 additions and 3 deletions
@@ -0,0 +1,200 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
use MicrosoftAzure\Storage\Common\Internal\Validate;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
use MicrosoftAzure\Storage\Common\Internal\Serialization\MessageSerializer;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Promise\RejectedPromise;
/**
* This class provides the functionality to log the requests/options/responses.
* Logging large number of entries without providing a file path may exhaust
* the memory.
*
* The middleware should be pushed into client options if the logging is
* intended to persist between different API calls.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class HistoryMiddleware extends MiddlewareBase
{
private $history;
private $path;
private $count;
const TITLE_LENGTH = 120;
/**
* Gets the saved paried history.
*
* @return array
*/
public function getHistory()
{
return $this->history;
}
/**
* Constructor
*
* @param string $path the path to save the history. If path is provided,
* no data is going to be saved to memory and the
* entries are going to be serialized and saved to given
* path.
*
*/
public function __construct($path = '')
{
$this->history = array();
$this->path = $path;
$this->count = 0;
}
/**
* Add an entry to history
*
* @param array $entry the entry to be added.
*/
public function addHistory(array $entry)
{
if ($this->path !== '') {
$this->appendNewEntryToPath($entry);
} else {
Validate::isTrue(
array_key_exists('request', $entry) &&
array_key_exists('options', $entry) &&
(array_key_exists('response', $entry) ||
array_key_exists('reason', $entry)),
'Given history entry not in correct format'
);
$this->history[] = $entry;
}
++$this->count;
}
/**
* Clear the history
*
* @return void
*/
public function clearHistory()
{
$this->history = array();
$this->count = 0;
}
/**
* This function will be invoked after the request is sent, if
* the promise is fulfilled.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onFulfilled(RequestInterface $request, array $options)
{
$reflection = $this;
return function (ResponseInterface $response) use (
$reflection,
$request,
$options
) {
$reflection->addHistory([
'request' => $request,
'response' => $response,
'options' => $options
]);
return $response;
};
}
/**
* This function will be executed after the request is sent, if
* the promise is rejected.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onRejected(RequestInterface $request, array $options)
{
$reflection = $this;
return function ($reason) use (
$reflection,
$request,
$options
) {
$reflection->addHistory([
'request' => $request,
'reason' => $reason,
'options' => $options
]);
return new RejectedPromise($reason);
};
}
/**
* Append the new entry to saved file path.
*
* @param array $entry the entry to be added.
*
* @return void
*/
private function appendNewEntryToPath(array $entry)
{
$entryNoString = "Entry " . $this->count;
$delimiter = str_pad(
$entryNoString,
self::TITLE_LENGTH,
'-',
STR_PAD_BOTH
) . PHP_EOL;
$entryString = $delimiter;
$entryString .= sprintf(
"Time: %s\n",
(new \DateTime("now", new \DateTimeZone('UTC')))->format('Y-m-d H:i:s')
);
$entryString .= MessageSerializer::objectSerialize($entry['request']);
if (array_key_exists('reason', $entry)) {
$entryString .= MessageSerializer::objectSerialize($entry['reason']);
} elseif (array_key_exists('response', $entry)) {
$entryString .= MessageSerializer::objectSerialize($entry['response']);
}
$entryString .= $delimiter;
Utilities::appendToFile($this->path, $entryString);
}
}
@@ -0,0 +1,71 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
/**
* IMiddleware is called before sending the request and after receiving the
* response.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
interface IMiddleware
{
/**
* This function will return a callable with $request and $options as
* its parameters and returns a promise. The callable can modify the
* request, fulfilled response or rejected reason when invoked with certain
* conditions. Sample middleware implementation:
*
* ```
* return function (
* RequestInterface $request,
* array $options
* ) use ($handler) {
* //do something prior to sending the request.
* $promise = $handler($request, $options);
* return $promise->then(
* function (ResponseInterface $response) use ($request, $options) {
* //do something
* return $response;
* },
* function ($reason) use ($request, $options) {
* //do something
* return new GuzzleHttp\Promise\RejectedPromise($reason);
* }
* );
* };
* ```
*
* @param callable $handler The next handler.
* @return callable
*/
public function __invoke(callable $handler);
}
@@ -0,0 +1,115 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Promise\RejectedPromise;
/**
* This class provides the base structure of middleware that can be used for
* doing customized behavior including modifying the request, response or
* other behaviors like logging, retrying and debugging.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class MiddlewareBase implements IMiddleware
{
/**
* Middleware augments the functionality of handlers by invoking them
* in the process of generating responses. And it returns a function
* that accepts the next handler to invoke. Refer to
* http://docs.guzzlephp.org/en/latest/handlers-and-middleware.html#middleware
* for more detailed information.
*
* @param callable The handler function.
*
* @return callable The function that accepts the next handler to invoke.
*/
public function __invoke(callable $handler)
{
$reflection = $this;
return function ($request, $options) use ($handler, $reflection) {
$request = $reflection->onRequest($request);
return $handler($request, $options)->then(
$reflection->onFulfilled($request, $options),
$reflection->onRejected($request, $options)
);
};
}
/**
* This function will be executed before the request is sent.
*
* @param RequestInterface $request the request before altered.
*
* @return RequestInterface the request after altered.
*/
protected function onRequest(RequestInterface $request)
{
//do nothing
return $request;
}
/**
* This function will be invoked after the request is sent, if
* the promise is fulfilled.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onFulfilled(RequestInterface $request, array $options)
{
return function (ResponseInterface $response) {
//do nothing
return $response;
};
}
/**
* This function will be executed after the request is sent, if
* the promise is rejected.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onRejected(RequestInterface $request, array $options)
{
return function ($reason) {
//do nothing
return new RejectedPromise($reason);
};
}
}
@@ -0,0 +1,70 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
/**
* This class provides the stack that handles the logic of applying each
* middlewares to the request or the response.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class MiddlewareStack
{
private $middlewares = array();
/**
* Push the given middleware into the middleware stack.
*
* @param IMiddleware|callable $middleware The middleware to be pushed.
*
* @return void
*/
public function push($middleware)
{
array_unshift($this->middlewares, $middleware);
}
/**
* Apply the middlewares to the handler.
*
* @param callable $handler the handler to which the middleware applies.
*
* @return callable
*/
public function apply(callable $handler)
{
$result = $handler;
foreach ($this->middlewares as $middleware) {
$result = $middleware($result);
}
return $result;
}
}
@@ -0,0 +1,181 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
use MicrosoftAzure\Storage\Common\LocationMode;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Utilities;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Promise\RejectedPromise;
/**
* This class provides the functionality of a middleware that handles all the
* retry logic for the request.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2017 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class RetryMiddleware extends MiddlewareBase
{
private $intervalCalculator;
private $decider;
public function __construct(
callable $intervalCalculator,
callable $decider
) {
$this->intervalCalculator = $intervalCalculator;
$this->decider = $decider;
}
/**
* This function will be invoked after the request is sent, if
* the promise is fulfilled.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onFulfilled(RequestInterface $request, array $options)
{
return function (ResponseInterface $response) use ($request, $options) {
$isSecondary = Utilities::requestSentToSecondary($request, $options);
if (!isset($options['retries'])) {
$options['retries'] = 0;
}
if (call_user_func(
$this->decider,
$options['retries'],
$request,
$response,
null,
$isSecondary
)) {
return $this->retry($request, $options, $response);
}
//Add the header that indicates the endpoint to be used if
//continuation token is used for subsequent request.
if ($isSecondary) {
$response = $response->withHeader(
Resources::X_MS_CONTINUATION_LOCATION_MODE,
LocationMode::SECONDARY_ONLY
);
} else {
$response = $response->withHeader(
Resources::X_MS_CONTINUATION_LOCATION_MODE,
LocationMode::PRIMARY_ONLY
);
}
return $response;
};
}
/**
* This function will be executed after the request is sent, if
* the promise is rejected.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
*
* @return callable
*/
protected function onRejected(RequestInterface $request, array $options)
{
return function ($reason) use ($request, $options) {
$isSecondary = Utilities::requestSentToSecondary($request, $options);
if (!isset($options['retries'])) {
$options['retries'] = 0;
}
if (call_user_func(
$this->decider,
$options['retries'],
$request,
null,
$reason,
$isSecondary
)) {
return $this->retry($request, $options);
}
return new RejectedPromise($reason);
};
}
/**
* This function does the real retry job.
*
* @param RequestInterface $request the request sent.
* @param array $options the options that the request sent with.
* @param ResponseInterface $response the response of the request
*
* @return callable
*/
private function retry(
RequestInterface $request,
array $options,
ResponseInterface $response = null
) {
$options['delay'] = call_user_func(
$this->intervalCalculator,
++$options['retries']
);
//Change the request URI according to the location mode.
if (array_key_exists(Resources::ROS_LOCATION_MODE, $options)) {
$locationMode = $options[Resources::ROS_LOCATION_MODE];
//If have RA-GRS enabled for the request, switch between
//primary and secondary.
if ($locationMode == LocationMode::PRIMARY_THEN_SECONDARY ||
$locationMode == LocationMode::SECONDARY_THEN_PRIMARY) {
$primaryUri = $options[Resources::ROS_PRIMARY_URI];
$secondaryUri = $options[Resources::ROS_SECONDARY_URI];
$target = $request->getRequestTarget();
if (Utilities::startsWith($target, '/')) {
$target = substr($target, 1);
$primaryUri = new Uri($primaryUri . $target);
$secondaryUri = new Uri($secondaryUri . $target);
}
//substitute the uri.
if ((string)$request->getUri() == (string)$primaryUri) {
$request = $request->withUri($secondaryUri);
} elseif ((string)$request->getUri() == (string)$secondaryUri) {
$request = $request->withUri($primaryUri);
}
}
}
$handler = $options[Resources::ROS_HANDLER];
return \call_user_func($handler, $request, $options);
}
}
@@ -0,0 +1,271 @@
<?php
/**
* LICENSE: The MIT License (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://github.com/azure/azure-storage-php/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* PHP version 5
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
namespace MicrosoftAzure\Storage\Common\Middlewares;
use MicrosoftAzure\Storage\Common\Internal\Resources;
use MicrosoftAzure\Storage\Common\Internal\Validate;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
/**
* This class provides static functions that creates retry handlers for Guzzle
* HTTP clients to handle retry policy.
*
* @category Microsoft
* @package MicrosoftAzure\Storage\Common\Middlewares
* @author Azure Storage PHP SDK <dmsh@microsoft.com>
* @copyright 2016 Microsoft Corporation
* @license https://github.com/azure/azure-storage-php/LICENSE
* @link https://github.com/azure/azure-storage-php
*/
class RetryMiddlewareFactory
{
//The interval will be increased linearly, the nth retry will have a
//wait time equal to n * interval.
const LINEAR_INTERVAL_ACCUMULATION = 'Linear';
//The interval will be increased exponentially, the nth retry will have a
//wait time equal to pow(2, n) * interval.
const EXPONENTIAL_INTERVAL_ACCUMULATION = 'Exponential';
//This is for the general type of logic that handles retry.
const GENERAL_RETRY_TYPE = 'General';
//This is for the append blob retry only.
const APPEND_BLOB_RETRY_TYPE = 'Append Blob Retry';
/**
* Create the retry handler for the Guzzle client, according to the given
* attributes.
*
* @param string $type The type that controls the logic of
* the decider of the retry handler.
* Possible value can be
* self::GENERAL_RETRY_TYPE or
* self::APPEND_BLOB_RETRY_TYPE
* @param int $numberOfRetries The maximum number of retries.
* @param int $interval The minimum interval between each retry
* @param string $accumulationMethod If the interval increases linearly or
* exponentially.
* Possible value can be
* self::LINEAR_INTERVAL_ACCUMULATION or
* self::EXPONENTIAL_INTERVAL_ACCUMULATION
* @param bool $retryConnect Whether to retry on connection failures.
* @return RetryMiddleware A RetryMiddleware object that contains
* the logic of how the request should be
* handled after a response.
*/
public static function create(
$type = self::GENERAL_RETRY_TYPE,
$numberOfRetries = Resources::DEFAULT_NUMBER_OF_RETRIES,
$interval = Resources::DEFAULT_RETRY_INTERVAL,
$accumulationMethod = self::LINEAR_INTERVAL_ACCUMULATION,
$retryConnect = false
) {
//Validate the input parameters
//type
Validate::isTrue(
$type == self::GENERAL_RETRY_TYPE ||
$type == self::APPEND_BLOB_RETRY_TYPE,
sprintf(
Resources::INVALID_PARAM_GENERAL,
'type'
)
);
//numberOfRetries
Validate::isTrue(
$numberOfRetries > 0,
sprintf(
Resources::INVALID_NEGATIVE_PARAM,
'numberOfRetries'
)
);
//interval
Validate::isTrue(
$interval > 0,
sprintf(
Resources::INVALID_NEGATIVE_PARAM,
'interval'
)
);
//accumulationMethod
Validate::isTrue(
$accumulationMethod == self::LINEAR_INTERVAL_ACCUMULATION ||
$accumulationMethod == self::EXPONENTIAL_INTERVAL_ACCUMULATION,
sprintf(
Resources::INVALID_PARAM_GENERAL,
'accumulationMethod'
)
);
//retryConnect
Validate::isBoolean($retryConnect);
//Get the interval calculator according to the type of the
//accumulation method.
$intervalCalculator =
$accumulationMethod == self::LINEAR_INTERVAL_ACCUMULATION ?
static::createLinearDelayCalculator($interval) :
static::createExponentialDelayCalculator($interval);
//Get the retry decider according to the type of the retry and
//the number of retries.
$retryDecider = static::createRetryDecider($type, $numberOfRetries, $retryConnect);
//construct the retry middle ware.
return new RetryMiddleware($intervalCalculator, $retryDecider);
}
/**
* Create the retry decider for the retry handler. It will return a callable
* that accepts the number of retries, the request, the response and the
* exception, and return the decision for a retry.
*
* @param string $type The type of the retry handler.
* @param int $maxRetries The maximum number of retries to be done.
* @param bool $retryConnect Whether to retry on connection failures.
*
* @return callable The callable that will return if the request should
* be retried.
*/
protected static function createRetryDecider($type, $maxRetries, $retryConnect)
{
return function (
$retries,
$request,
$response = null,
$exception = null,
$isSecondary = false
) use (
$type,
$maxRetries,
$retryConnect
) {
//Exceeds the retry limit. No retry.
if ($retries >= $maxRetries) {
return false;
}
if (!$response) {
if (!$exception || !($exception instanceof RequestException)) {
return false;
} elseif ($exception instanceof ConnectException) {
return $retryConnect;
} else {
$response = $exception->getResponse();
if (!$response) {
return true;
}
}
}
if ($type == self::GENERAL_RETRY_TYPE) {
return static::generalRetryDecider(
$response->getStatusCode(),
$isSecondary
);
} else {
return static::appendBlobRetryDecider(
$response->getStatusCode(),
$isSecondary
);
}
return true;
};
}
/**
* Decide if the given status code indicate the request should be retried.
*
* @param int $statusCode Status code of the previous request.
* @param bool $isSecondary Whether the request is sent to secondary endpoint.
*
* @return bool true if the request should be retried.
*/
protected static function generalRetryDecider($statusCode, $isSecondary)
{
$retry = false;
if ($statusCode == 408) {
$retry = true;
} elseif ($statusCode >= 500) {
if ($statusCode != 501 && $statusCode != 505) {
$retry = true;
}
} elseif ($isSecondary && $statusCode == 404) {
$retry = true;
}
return $retry;
}
/**
* Decide if the given status code indicate the request should be retried.
* This is for append blob.
*
* @param int $statusCode Status code of the previous request.
* @param bool $isSecondary Whether the request is sent to secondary endpoint.
*
* @return bool true if the request should be retried.
*/
protected static function appendBlobRetryDecider($statusCode, $isSecondary)
{
//The retry logic is different for append blob.
//First it will need to record the former status code if it is
//server error. Then if the following request is 412 then it
//needs to be retried. Currently this is not implemented so will
//only adapt to the general retry decider.
//TODO: add logic for append blob's retry when implemented.
$retry = static::generalRetryDecider($statusCode, $isSecondary);
return $retry;
}
/**
* Create the delay calculator that increases the interval linearly
* according to the number of retries.
*
* @param int $interval the minimum interval of the retry.
*
* @return callable a calculator that will return the interval
* according to the number of retries.
*/
protected static function createLinearDelayCalculator($interval)
{
return function ($retries) use ($interval) {
return $retries * $interval;
};
}
/**
* Create the delay calculator that increases the interval exponentially
* according to the number of retries.
*
* @param int $interval the minimum interval of the retry.
*
* @return callable a calculator that will return the interval
* according to the number of retries.
*/
protected static function createExponentialDelayCalculator($interval)
{
return function ($retries) use ($interval) {
return $interval * ((int)\pow(2, $retries));
};
}
}