<?php
namespace App\EventSubscriber;
use App\Repository\Lead\LeadRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class ScraperThrottleSubscriber implements EventSubscriberInterface
{
private LeadRepository $leadRepository;
private EntityManagerInterface $entityManager;
public function __construct(EntityManagerInterface $entityManager, LeadRepository $leadRepository)
{
$this->entityManager = $entityManager;
$this->leadRepository = $leadRepository;
}
public function onKernelRequest(RequestEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}
// Don't throttle local IPs
if (!filter_var($event->getRequest()->getClientIp(), FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return;
}
$throttleLeadsGeneratedLimit = 5;
if ($this->entityManager->getFilters()->isEnabled('softdeleteable')) {
$this->entityManager->getFilters()->disable('softdeleteable');
}
$date = new \DateTime();
$leadCountByIp = $this->leadRepository->countSpamLeadByIp(
$event->getRequest()->getClientIp(),
$date->sub(new \DateInterval('PT6H'))
);
$this->entityManager->getFilters()->enable('softdeleteable');
if ($leadCountByIp >= $throttleLeadsGeneratedLimit) {
$sleepRatio = $throttleLeadsGeneratedLimit / max($leadCountByIp, 1);
$sleepTime = round($leadCountByIp * $sleepRatio, 0);
sleep(min($sleepTime, 55));
$event->setResponse(new Response('Unprocessable Entity', Response::HTTP_TOO_MANY_REQUESTS));
}
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => 'onKernelRequest',
];
}
}