| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 | <?phpnamespace Aws;use Aws\Endpoint\PartitionEndpointProvider;use Aws\Endpoint\PartitionInterface;use Aws\EndpointV2\EndpointProviderV2;use Aws\EndpointV2\EndpointDefinitionProvider;class MultiRegionClient implements AwsClientInterface{    use AwsClientTrait;    /** @var AwsClientInterface[] A pool of clients keyed by region. */    private $clientPool = [];    /** @var callable */    private $factory;    /** @var PartitionInterface */    private $partition;    /** @var array */    private $args;    /** @var array */    private $config;    /** @var HandlerList */    private $handlerList;    /** @var array */    private $aliases;    /** @var callable */    private $customHandler;    public static function getArguments()    {        $args = array_intersect_key(            ClientResolver::getDefaultArguments(),            ['service' => true, 'region' => true]        );        $args['region']['required'] = false;        unset($args['region']['fn']);        unset($args['region']['default']);        return $args + [                'client_factory' => [                    'type' => 'config',                    'valid' => ['callable'],                    'doc' => 'A callable that takes an array of client'                        . ' configuration arguments and returns a regionalized'                        . ' client.',                    'required' => true,                    'internal' => true,                    'default' => function (array $args) {                        $namespace = manifest($args['service'])['namespace'];                        $klass = "Aws\\{$namespace}\\{$namespace}Client";                        $region = isset($args['region']) ? $args['region'] : null;                        return function (array $args) use ($klass, $region) {                            if ($region && empty($args['region'])) {                                $args['region'] = $region;                            }                            return new $klass($args);                        };                    },                ],                'partition' => [                    'type'    => 'config',                    'valid'   => ['string', PartitionInterface::class],                    'doc'     => 'AWS partition to connect to. Valid partitions'                        . ' include "aws," "aws-cn," and "aws-us-gov." Used to'                        . ' restrict the scope of the mapRegions method.',                    'default' => function (array $args) {                        $region = isset($args['region']) ? $args['region'] : '';                        return PartitionEndpointProvider::defaultProvider()                            ->getPartition($region, $args['service']);                    },                    'fn'      => function ($value, array &$args) {                        if (is_string($value)) {                            $value = PartitionEndpointProvider::defaultProvider()                                ->getPartitionByName($value);                        }                        if (!$value instanceof PartitionInterface) {                            throw new \InvalidArgumentException('No valid partition'                                . ' was provided. Provide a concrete partition or'                                . ' the name of a partition (e.g., "aws," "aws-cn,"'                                . ' or "aws-us-gov").'                            );                        }                        $ruleset = EndpointDefinitionProvider::getEndpointRuleset(                            $args['service'],                            isset($args['version']) ? $args['version'] : 'latest'                        );                        $partitions = EndpointDefinitionProvider::getPartitions();                        $args['endpoint_provider'] = new EndpointProviderV2($ruleset, $partitions);                    }                ],            ];    }    /**     * The multi-region client constructor accepts the following options:     *     * - client_factory: (callable) An optional callable that takes an array of     *   client configuration arguments and returns a regionalized client.     * - partition: (Aws\Endpoint\Partition|string) AWS partition to connect to.     *   Valid partitions include "aws," "aws-cn," and "aws-us-gov." Used to     *   restrict the scope of the mapRegions method.     * - region: (string) Region to connect to when no override is provided.     *   Used to create the default client factory and determine the appropriate     *   AWS partition when present.     *     * @param array $args Client configuration arguments.     */    public function __construct(array $args = [])    {        if (!isset($args['service'])) {            $args['service'] = $this->parseClass();        }        $this->handlerList = new HandlerList(function (            CommandInterface $command        ) {            list($region, $args) = $this->getRegionFromArgs($command->toArray());            $command = $this->getClientFromPool($region)                ->getCommand($command->getName(), $args);            if ($this->isUseCustomHandler()) {                $command->getHandlerList()->setHandler($this->customHandler);            }            return $this->executeAsync($command);        });        $argDefinitions = static::getArguments();        $resolver = new ClientResolver($argDefinitions);        $args = $resolver->resolve($args, $this->handlerList);        $this->config = $args['config'];        $this->factory = $args['client_factory'];        $this->partition = $args['partition'];        $this->args = array_diff_key($args, $args['config']);    }    /**     * Get the region to which the client is configured to send requests by     * default.     *     * @return string     */    public function getRegion()    {        return $this->getClientFromPool()->getRegion();    }    /**     * Create a command for an operation name.     *     * Special keys may be set on the command to control how it behaves,     * including:     *     * - @http: Associative array of transfer specific options to apply to the     *   request that is serialized for this command. Available keys include     *   "proxy", "verify", "timeout", "connect_timeout", "debug", "delay", and     *   "headers".     * - @region: The region to which the command should be sent.     *     * @param string $name Name of the operation to use in the command     * @param array  $args Arguments to pass to the command     *     * @return CommandInterface     * @throws \InvalidArgumentException if no command can be found by name     */    public function getCommand($name, array $args = [])    {        return new Command($name, $args, clone $this->getHandlerList());    }    public function getConfig($option = null)    {        if (null === $option) {            return $this->config;        }        if (isset($this->config[$option])) {            return $this->config[$option];        }        return $this->getClientFromPool()->getConfig($option);    }    public function getCredentials()    {        return $this->getClientFromPool()->getCredentials();    }    public function getHandlerList()    {        return $this->handlerList;    }    public function getApi()    {        return $this->getClientFromPool()->getApi();    }    public function getEndpoint()    {        return $this->getClientFromPool()->getEndpoint();    }    public function useCustomHandler(callable $handler)    {        $this->customHandler = $handler;    }    private function isUseCustomHandler()    {        return isset($this->customHandler);    }    /**     * @param string $region    Omit this argument or pass in an empty string to     *                          allow the configured client factory to apply the     *                          region.     *     * @return AwsClientInterface     */    protected function getClientFromPool($region = '')    {        if (empty($this->clientPool[$region])) {            $factory = $this->factory;            $this->clientPool[$region] = $factory(                array_replace($this->args, array_filter(['region' => $region]))            );        }        return $this->clientPool[$region];    }    /**     * Parse the class name and return the "service" name of the client.     *     * @return string     */    private function parseClass()    {        $klass = get_class($this);        if ($klass === __CLASS__) {            return '';        }        return strtolower(substr($klass, strrpos($klass, '\\') + 1, -17));    }    private function getRegionFromArgs(array $args)    {        $region = isset($args['@region'])            ? $args['@region']            : $this->getRegion();        unset($args['@region']);        return [$region, $args];    }}
 |