radarrplexorganizrnginxsonarrdashboardhtpcserverhomepagesabnzbdheimdallembycouchpotatonzbgetbookmarkapplication-dashboardmuximuxlandingpagestartpagelanding
		
		
		
		
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							180 lines
						
					
					
						
							5.5 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							180 lines
						
					
					
						
							5.5 KiB
						
					
					
				
								<?php
							 | 
						|
								
							 | 
						|
								namespace Http\Client\Common;
							 | 
						|
								
							 | 
						|
								use Http\Client\Common\Exception\LoopException;
							 | 
						|
								use Http\Client\Exception as HttplugException;
							 | 
						|
								use Http\Client\HttpAsyncClient;
							 | 
						|
								use Http\Client\HttpClient;
							 | 
						|
								use Http\Client\Promise\HttpFulfilledPromise;
							 | 
						|
								use Http\Client\Promise\HttpRejectedPromise;
							 | 
						|
								use Psr\Http\Client\ClientInterface;
							 | 
						|
								use Psr\Http\Message\RequestInterface;
							 | 
						|
								use Symfony\Component\OptionsResolver\OptionsResolver;
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * The client managing plugins and providing a decorator around HTTP Clients.
							 | 
						|
								 *
							 | 
						|
								 * @author Joel Wurtz <joel.wurtz@gmail.com>
							 | 
						|
								 */
							 | 
						|
								final class PluginClient implements HttpClient, HttpAsyncClient
							 | 
						|
								{
							 | 
						|
								    /**
							 | 
						|
								     * An HTTP async client.
							 | 
						|
								     *
							 | 
						|
								     * @var HttpAsyncClient
							 | 
						|
								     */
							 | 
						|
								    private $client;
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * The plugin chain.
							 | 
						|
								     *
							 | 
						|
								     * @var Plugin[]
							 | 
						|
								     */
							 | 
						|
								    private $plugins;
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * A list of options.
							 | 
						|
								     *
							 | 
						|
								     * @var array
							 | 
						|
								     */
							 | 
						|
								    private $options;
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * @param HttpClient|HttpAsyncClient|ClientInterface $client
							 | 
						|
								     * @param Plugin[]                                   $plugins
							 | 
						|
								     * @param array                                      $options {
							 | 
						|
								     *
							 | 
						|
								     *     @var int      $max_restarts
							 | 
						|
								     *     @var Plugin[] $debug_plugins an array of plugins that are injected between each normal plugin
							 | 
						|
								     * }
							 | 
						|
								     *
							 | 
						|
								     * @throws \RuntimeException if client is not an instance of HttpClient or HttpAsyncClient
							 | 
						|
								     */
							 | 
						|
								    public function __construct($client, array $plugins = [], array $options = [])
							 | 
						|
								    {
							 | 
						|
								        if ($client instanceof HttpAsyncClient) {
							 | 
						|
								            $this->client = $client;
							 | 
						|
								        } elseif ($client instanceof HttpClient || $client instanceof ClientInterface) {
							 | 
						|
								            $this->client = new EmulatedHttpAsyncClient($client);
							 | 
						|
								        } else {
							 | 
						|
								            throw new \RuntimeException('Client must be an instance of Http\\Client\\HttpClient or Http\\Client\\HttpAsyncClient');
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $this->plugins = $plugins;
							 | 
						|
								        $this->options = $this->configure($options);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * {@inheritdoc}
							 | 
						|
								     */
							 | 
						|
								    public function sendRequest(RequestInterface $request)
							 | 
						|
								    {
							 | 
						|
								        // If we don't have an http client, use the async call
							 | 
						|
								        if (!($this->client instanceof HttpClient)) {
							 | 
						|
								            return $this->sendAsyncRequest($request)->wait();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Else we want to use the synchronous call of the underlying client, and not the async one in the case
							 | 
						|
								        // we have both an async and sync call
							 | 
						|
								        $pluginChain = $this->createPluginChain($this->plugins, function (RequestInterface $request) {
							 | 
						|
								            try {
							 | 
						|
								                return new HttpFulfilledPromise($this->client->sendRequest($request));
							 | 
						|
								            } catch (HttplugException $exception) {
							 | 
						|
								                return new HttpRejectedPromise($exception);
							 | 
						|
								            }
							 | 
						|
								        });
							 | 
						|
								
							 | 
						|
								        return $pluginChain($request)->wait();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * {@inheritdoc}
							 | 
						|
								     */
							 | 
						|
								    public function sendAsyncRequest(RequestInterface $request)
							 | 
						|
								    {
							 | 
						|
								        $pluginChain = $this->createPluginChain($this->plugins, function (RequestInterface $request) {
							 | 
						|
								            return $this->client->sendAsyncRequest($request);
							 | 
						|
								        });
							 | 
						|
								
							 | 
						|
								        return $pluginChain($request);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Configure the plugin client.
							 | 
						|
								     *
							 | 
						|
								     * @param array $options
							 | 
						|
								     *
							 | 
						|
								     * @return array
							 | 
						|
								     */
							 | 
						|
								    private function configure(array $options = [])
							 | 
						|
								    {
							 | 
						|
								        if (isset($options['debug_plugins'])) {
							 | 
						|
								            @trigger_error('The "debug_plugins" option is deprecated since 1.5 and will be removed in 2.0.', E_USER_DEPRECATED);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $resolver = new OptionsResolver();
							 | 
						|
								        $resolver->setDefaults([
							 | 
						|
								            'max_restarts' => 10,
							 | 
						|
								            'debug_plugins' => [],
							 | 
						|
								        ]);
							 | 
						|
								
							 | 
						|
								        $resolver
							 | 
						|
								            ->setAllowedTypes('debug_plugins', 'array')
							 | 
						|
								            ->setAllowedValues('debug_plugins', function (array $plugins) {
							 | 
						|
								                foreach ($plugins as $plugin) {
							 | 
						|
								                    // Make sure each object passed with the `debug_plugins` is an instance of Plugin.
							 | 
						|
								                    if (!$plugin instanceof Plugin) {
							 | 
						|
								                        return false;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                return true;
							 | 
						|
								            });
							 | 
						|
								
							 | 
						|
								        return $resolver->resolve($options);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Create the plugin chain.
							 | 
						|
								     *
							 | 
						|
								     * @param Plugin[] $pluginList     A list of plugins
							 | 
						|
								     * @param callable $clientCallable Callable making the HTTP call
							 | 
						|
								     *
							 | 
						|
								     * @return callable
							 | 
						|
								     */
							 | 
						|
								    private function createPluginChain($pluginList, callable $clientCallable)
							 | 
						|
								    {
							 | 
						|
								        $firstCallable = $lastCallable = $clientCallable;
							 | 
						|
								
							 | 
						|
								        /*
							 | 
						|
								         * Inject debug plugins between each plugin.
							 | 
						|
								         */
							 | 
						|
								        $pluginListWithDebug = $this->options['debug_plugins'];
							 | 
						|
								        foreach ($pluginList as $plugin) {
							 | 
						|
								            $pluginListWithDebug[] = $plugin;
							 | 
						|
								            $pluginListWithDebug = array_merge($pluginListWithDebug, $this->options['debug_plugins']);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        while ($plugin = array_pop($pluginListWithDebug)) {
							 | 
						|
								            $lastCallable = function (RequestInterface $request) use ($plugin, $lastCallable, &$firstCallable) {
							 | 
						|
								                return $plugin->handleRequest($request, $lastCallable, $firstCallable);
							 | 
						|
								            };
							 | 
						|
								
							 | 
						|
								            $firstCallable = $lastCallable;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $firstCalls = 0;
							 | 
						|
								        $firstCallable = function (RequestInterface $request) use ($lastCallable, &$firstCalls) {
							 | 
						|
								            if ($firstCalls > $this->options['max_restarts']) {
							 | 
						|
								                throw new LoopException('Too many restarts in plugin client', $request);
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            ++$firstCalls;
							 | 
						|
								
							 | 
						|
								            return $lastCallable($request);
							 | 
						|
								        };
							 | 
						|
								
							 | 
						|
								        return $firstCallable;
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 |