acquia_search-3.0.1/src/Helper/Flood.php

src/Helper/Flood.php
<?php

namespace Drupal\acquia_search\Helper;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Flood\FloodInterface;
use Psr\Log\LoggerInterface;

/**
 * Class Flood.
 *
 * A mechanism to limit the outgoing number of requests to the Acquia Search
 * Solr backend using the Drupal Flood API.
 *
 * This complements the Solr traffic limits embedded into on the Acquia
 * platform.
 *
 * This class will look at the recent requests during a time window, and
 * return a boolean value on whether to block/allow those requests. The actual
 * blocking happens elsewhere.
 *
 * The values in code are named 'window' and 'limit.
 *   window: the amount of seconds in the "sliding window" time
 *   limit: the maximum amount of requests that can be done during that window.
 *
 * So, to check whether to carry out or block the current request, we use look
 * at the window between T-[window] seconds up to the present, and if more
 * than [limit] requests of the same [type] have happened, we will deny that
 * request.
 *
 * Example: for limit=10 [requests] and window=10 [seconds] allows at most
 *  10 requests in that time period.
 *
 * See the Drupal Flood API documentation for more:
 * https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Flood%21FloodInterface.php/interface/FloodInterface
 */
class Flood {

  const FLOOD_LIMIT_ARTICLE_URL = "https://support-acquia.force.com/s/article/1500008925761-The-Acquia-Search-flood-control-mechanism-has-blocked-a-Solr-query-due-to-API-usage-limits";

  /**
   * The core flood service.
   *
   * @var \Drupal\Core\Flood\FloodInterface
   */
  private $flood;

  /**
   * The config.
   *
   * @var \Drupal\Core\Config\ImmutableConfig
   */
  private $config;

  /**
   * The logger.
   *
   * @var \Psr\Log\LoggerInterface
   */
  private $logger;

  /**
   * Constructs a new Flood object.
   *
   * @param \Drupal\Core\Flood\FloodInterface $core_flood
   *   The core flood service.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The config factory.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger.
   */
  public function __construct(FloodInterface $core_flood, ConfigFactoryInterface $config_factory, LoggerInterface $logger) {
    $this->flood = $core_flood;
    $this->config = $config_factory->get('acquia_search.settings');
    $this->logger = $logger;
  }

  /**
   * List of values by each Solarium request type.
   */
  private static function getFloodDefaults() {
    return [
      'select' => ['window' => 10, 'limit' => 50],
      'update' => ['window' => 60, 'limit' => 600],
      'update/extract' => ['window' => 60, 'limit' => 600],
      'autocomplete' => ['window' => 10, 'limit' => 100],
      'test' => ['window' => 2, 'limit' => 1],
    ];
  }

  /**
   * Return the integer value for the specified type and option.
   *
   * @param string $request_type
   *   The incoming request type.
   * @param string $value_name
   *   The name of the type value.
   *
   * @return int
   *   Integer value for specified type and option.
   */
  private function getConfigValue(string $request_type, string $value_name) {
    $defaults = self::getFloodDefaults();
    $escaped_request_type = str_replace('/', '_', $request_type);
    $config_id = 'flood_limit.' . $escaped_request_type . '.' . $value_name;
    return $this->config->get($config_id) ?? $defaults[$request_type][$value_name];
  }

  /**
   * Check that the given ID is a valid string from a list of defined values.
   *
   * @param string $request_type
   *   The incoming request type.
   *
   * @return bool
   *   If the request type is controlled
   */
  private static function isControlled(string $request_type): bool {
    $defaults = self::getFloodDefaults();
    return isset($defaults[$request_type]);
  }

  /**
   * Determines if a request can be sent via the flood control mechanism.
   *
   * @param string $request_type
   *   The incoming request type.
   *
   * @return bool
   *   If the request is allowed
   */
  public function isAllowed(string $request_type): bool {
    // Allow all requests from types that aren't controlled.
    if (!self::isControlled($request_type)) {
      return TRUE;
    }

    $limit = $this->getConfigValue($request_type, 'limit');
    $window = $this->getConfigValue($request_type, 'window');

    // Use the Drupal Flood service to check if we can run this request.
    $is_allowed = $this->flood->isAllowed(
      'acquia_search',
      $limit,
      $window,
      $request_type
    );

    // If this request should be blocked, log if needed and return.
    if (!$is_allowed) {
      if ($this->config->get('flood_logging') === TRUE) {
        $this->logger->warning(
          'Flood protection has blocked request of type @id. See more at <a href="@url">The Acquia Search flood control mechanism has blocked a Solr query due to API usage limits</a>',
          [
            '@id' => $request_type,
            '@url' => self::FLOOD_LIMIT_ARTICLE_URL,
          ]
        );
      }
      return FALSE;
    }

    // Log the allowed request into the Flood service.
    $this->flood->register(
      'acquia_search',
      $window,
      $request_type
    );
    return TRUE;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc