nextcloud/apps/files_external/3rdparty/aws-sdk-php/Aws/Common/Waiter/ConfigResourceWaiter.php

226 lines
7.4 KiB
PHP

<?php
/**
* Copyright 2010-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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.
*/
namespace Aws\Common\Waiter;
use Aws\Common\Exception\InvalidArgumentException;
use Aws\Common\Exception\RuntimeException;
use Aws\Common\Exception\ServiceResponseException;
use Guzzle\Service\Resource\Model;
use Guzzle\Service\Exception\ValidationException;
/**
* Resource waiter driven by configuration options
*/
class ConfigResourceWaiter extends AbstractResourceWaiter
{
/**
* @var WaiterConfig Waiter configuration
*/
protected $waiterConfig;
/**
* @param WaiterConfig $waiterConfig Waiter configuration
*/
public function __construct(WaiterConfig $waiterConfig)
{
$this->waiterConfig = $waiterConfig;
$this->setInterval($waiterConfig->get(WaiterConfig::INTERVAL));
$this->setMaxAttempts($waiterConfig->get(WaiterConfig::MAX_ATTEMPTS));
}
/**
* {@inheritdoc}
*/
public function setConfig(array $config)
{
foreach ($config as $key => $value) {
if (substr($key, 0, 7) == 'waiter.') {
$this->waiterConfig->set(substr($key, 7), $value);
}
}
if (!isset($config[self::INTERVAL])) {
$config[self::INTERVAL] = $this->waiterConfig->get(WaiterConfig::INTERVAL);
}
if (!isset($config[self::MAX_ATTEMPTS])) {
$config[self::MAX_ATTEMPTS] = $this->waiterConfig->get(WaiterConfig::MAX_ATTEMPTS);
}
return parent::setConfig($config);
}
/**
* Get the waiter's configuration data
*
* @return WaiterConfig
*/
public function getWaiterConfig()
{
return $this->waiterConfig;
}
/**
* {@inheritdoc}
*/
protected function doWait()
{
$params = $this->config;
// remove waiter settings from the operation's input
foreach (array_keys($params) as $key) {
if (substr($key, 0, 7) == 'waiter.') {
unset($params[$key]);
}
}
$operation = $this->client->getCommand($this->waiterConfig->get(WaiterConfig::OPERATION), $params);
try {
return $this->checkResult($this->client->execute($operation));
} catch (ValidationException $e) {
throw new InvalidArgumentException(
$this->waiterConfig->get(WaiterConfig::WAITER_NAME) . ' waiter validation failed: ' . $e->getMessage(),
$e->getCode(),
$e
);
} catch (ServiceResponseException $e) {
// Check if this exception satisfies a success or failure acceptor
$transition = $this->checkErrorAcceptor($e);
if (null !== $transition) {
return $transition;
}
// Check if this exception should be ignored
foreach ((array) $this->waiterConfig->get(WaiterConfig::IGNORE_ERRORS) as $ignore) {
if ($e->getExceptionCode() == $ignore) {
// This exception is ignored, so it counts as a failed attempt rather than a fast-fail
return false;
}
}
// Allow non-ignore exceptions to bubble through
throw $e;
}
}
/**
* Check if an exception satisfies a success or failure acceptor
*
* @param ServiceResponseException $e
*
* @return bool|null Returns true for success, false for failure, and null for no transition
*/
protected function checkErrorAcceptor(ServiceResponseException $e)
{
if ($this->waiterConfig->get(WaiterConfig::SUCCESS_TYPE) == 'error') {
if ($e->getExceptionCode() == $this->waiterConfig->get(WaiterConfig::SUCCESS_VALUE)) {
// Mark as a success
return true;
}
}
// Mark as an attempt
return null;
}
/**
* Check to see if the response model satisfies a success or failure state
*
* @param Model $result Result model
*
* @return bool
* @throws RuntimeException
*/
protected function checkResult(Model $result)
{
// Check if the result evaluates to true based on the path and output model
if ($this->waiterConfig->get(WaiterConfig::SUCCESS_TYPE) == 'output' &&
$this->checkPath(
$result,
$this->waiterConfig->get(WaiterConfig::SUCCESS_PATH),
$this->waiterConfig->get(WaiterConfig::SUCCESS_VALUE)
)
) {
return true;
}
// It did not finish waiting yet. Determine if we need to fail-fast based on the failure acceptor.
if ($this->waiterConfig->get(WaiterConfig::FAILURE_TYPE) == 'output') {
$failureValue = $this->waiterConfig->get(WaiterConfig::FAILURE_VALUE);
if ($failureValue) {
$key = $this->waiterConfig->get(WaiterConfig::FAILURE_PATH);
if ($this->checkPath($result, $key, $failureValue, false)) {
// Determine which of the results triggered the failure
$triggered = array_intersect(
(array) $this->waiterConfig->get(WaiterConfig::FAILURE_VALUE),
array_unique((array) $result->getPath($key))
);
// fast fail because the failure case was satisfied
throw new RuntimeException(
'A resource entered into an invalid state of "'
. implode(', ', $triggered) . '" while waiting with the "'
. $this->waiterConfig->get(WaiterConfig::WAITER_NAME) . '" waiter.'
);
}
}
}
return false;
}
/**
* Check to see if the path of the output key is satisfied by the value
*
* @param Model $model Result model
* @param string $key Key to check
* @param string $checkValue Compare the key to the value
* @param bool $all Set to true to ensure all value match or false to only match one
*
* @return bool
*/
protected function checkPath(Model $model, $key = null, $checkValue = array(), $all = true)
{
// If no key is set, then just assume true because the request succeeded
if (!$key) {
return true;
}
if (!($result = $model->getPath($key))) {
return false;
}
$total = $matches = 0;
foreach ((array) $result as $value) {
$total++;
foreach ((array) $checkValue as $check) {
if ($value == $check) {
$matches++;
break;
}
}
}
// When matching all values, ensure that the match count matches the total count
if ($all && $total != $matches) {
return false;
}
return $matches > 0;
}
}