diff options
Diffstat (limited to 'bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle')
-rw-r--r-- | bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/ClientFactory.php | 96 | ||||
-rw-r--r-- | bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/MiddlewareFactory.php | 158 |
2 files changed, 254 insertions, 0 deletions
diff --git a/bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/ClientFactory.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/ClientFactory.php new file mode 100644 index 00000000..704a1660 --- /dev/null +++ b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/ClientFactory.php @@ -0,0 +1,96 @@ +<?php + +namespace Mediawiki\Api\Guzzle; + +use GuzzleHttp\Client; +use GuzzleHttp\Handler\CurlHandler; +use GuzzleHttp\HandlerStack; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; + +/** + * @since 2.1 + * + * @author Addshore + */ +class ClientFactory implements LoggerAwareInterface { + + private $client; + private $logger; + private $config; + + /** + * @since 2.1 + * + * @param array $config All configuration settings supported by Guzzle, and these: + * middleware => array of extra middleware to pass to guzzle + * user-agent => string default user agent to use for requests + */ + public function __construct( array $config = [] ) { + $this->logger = new NullLogger(); + $this->config = $config; + } + + /** + * @since 2.1 + * + * @return Client + */ + public function getClient() { + if ( $this->client === null ) { + $this->client = $this->newClient(); + } + return $this->client; + } + + /** + * @return Client + */ + private function newClient() { + $this->config += [ + 'cookies' => true, + 'headers' => [], + 'middleware' => [], + ]; + + if ( !array_key_exists( 'User-Agent', $this->config['headers'] ) ) { + if ( array_key_exists( 'user-agent', $this->config ) ) { + $this->config['headers']['User-Agent'] = $this->config['user-agent']; + } else { + $this->config['headers']['User-Agent'] = 'Addwiki - mediawiki-api-base'; + } + } + unset( $this->config['user-agent'] ); + + if ( !array_key_exists( 'handler', $this->config ) ) { + $this->config['handler'] = HandlerStack::create( new CurlHandler() ); + } + + $middlewareFactory = new MiddlewareFactory(); + $middlewareFactory->setLogger( $this->logger ); + + $this->config['middleware'][] = $middlewareFactory->retry(); + + foreach ( $this->config['middleware'] as $name => $middleware ) { + $this->config['handler']->push( $middleware ); + } + unset( $this->config['middleware'] ); + + return new Client( $this->config ); + } + + /** + * Sets a logger instance on the object + * + * @since 2.1 + * + * @param LoggerInterface $logger The new Logger object. + * + * @return null + */ + public function setLogger( LoggerInterface $logger ) { + $this->logger = $logger; + } + +} diff --git a/bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/MiddlewareFactory.php b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/MiddlewareFactory.php new file mode 100644 index 00000000..9e03c02f --- /dev/null +++ b/bin/wiki/vendor/addwiki/mediawiki-api-base/src/Guzzle/MiddlewareFactory.php @@ -0,0 +1,158 @@ +<?php + +namespace Mediawiki\Api\Guzzle; + +use GuzzleHttp\Exception\ConnectException; +use GuzzleHttp\Exception\RequestException; +use GuzzleHttp\Middleware; +use GuzzleHttp\Psr7\Request; +use GuzzleHttp\Psr7\Response; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; + +/** + * @access private + * + * @author Addshore + */ +class MiddlewareFactory implements LoggerAwareInterface { + + /** + * @var LoggerInterface + */ + private $logger; + + public function __construct() { + $this->logger = new NullLogger(); + } + + /** + * @param LoggerInterface $logger The new Logger object. + */ + public function setLogger( LoggerInterface $logger ) { + $this->logger = $logger; + } + + /** + * @access private + * + * @param bool $delay default to true, can be false to speed up tests + * + * @return callable + */ + public function retry( $delay = true ) { + if ( $delay ) { + return Middleware::retry( $this->newRetryDecider(), $this->getRetryDelay() ); + } else { + return Middleware::retry( $this->newRetryDecider() ); + } + } + + /** + * Returns a method that takes the number of retries and returns the number of miliseconds + * to wait + * + * @return callable + */ + private function getRetryDelay() { + return function ( $numberOfRetries, Response $response = null ) { + // The $response argument is only passed as of Guzzle 6.2.2. + if ( $response !== null ) { + // Retry-After may be a number of seconds or an absolute date (RFC 7231, + // section 7.1.3). + $retryAfter = $response->getHeaderLine( 'Retry-After' ); + + if ( is_numeric( $retryAfter ) ) { + return 1000 * $retryAfter; + } + + if ( $retryAfter ) { + $seconds = strtotime( $retryAfter ) - time(); + return 1000 * max( 1, $seconds ); + } + } + + return 1000 * $numberOfRetries; + }; + } + + /** + * @return callable + */ + private function newRetryDecider() { + return function ( + $retries, + Request $request, + Response $response = null, + RequestException $exception = null + ) { + // Don't retry if we have run out of retries + if ( $retries >= 5 ) { + return false; + } + + $shouldRetry = false; + + // Retry connection exceptions + if ( $exception instanceof ConnectException ) { + $shouldRetry = true; + } + + if ( $response ) { + $data = json_decode( $response->getBody(), true ); + + // Retry on server errors + if ( $response->getStatusCode() >= 500 ) { + $shouldRetry = true; + } + + foreach ( $response->getHeader( 'Mediawiki-Api-Error' ) as $mediawikiApiErrorHeader ) { + if ( + // Retry if the API explicitly tells us to: + // https://www.mediawiki.org/wiki/Manual:Maxlag_parameter + $response->getHeaderLine( 'Retry-After' ) + || + // Retry if we have a response with an API error worth retrying + in_array( + $mediawikiApiErrorHeader, + [ + 'ratelimited', + 'maxlag', + 'readonly', + 'internal_api_error_DBQueryError', + ] + ) + || + // Or if we have been stopped from saving as an 'anti-abuse measure' + // Note: this tries to match "actionthrottledtext" i18n messagae for mediawiki + ( + $mediawikiApiErrorHeader == 'failed-save' && + strstr( $data['error']['info'], 'anti-abuse measure' ) + ) + ) { + $shouldRetry = true; + } + + } + } + + // Log if we are retrying + if ( $shouldRetry ) { + $this->logger->warning( + sprintf( + 'Retrying %s %s %s/5, %s', + $request->getMethod(), + $request->getUri(), + $retries + 1, + $response ? 'status code: ' . $response->getStatusCode() : + $exception->getMessage() + ) + ); + } + + return $shouldRetry; + }; + } + +} |