mirror of
https://github.com/maelgangloff/domain-watchdog.git
synced 2025-12-29 16:15:04 +00:00
feat: add stats endpoint
This commit is contained in:
74
src/Controller/StatisticsController.php
Normal file
74
src/Controller/StatisticsController.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Statistics;
|
||||
use App\Repository\DomainRepository;
|
||||
use App\Repository\WatchListRepository;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Psr\Cache\InvalidArgumentException;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
class StatisticsController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly CacheItemPoolInterface $pool,
|
||||
private readonly DomainRepository $domainRepository,
|
||||
private readonly WatchListRepository $watchListRepository,
|
||||
private readonly KernelInterface $kernel
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __invoke(): Statistics
|
||||
{
|
||||
$stats = new Statistics();
|
||||
|
||||
$stats
|
||||
->setRdapQueries($this->pool->getItem('stats.rdap_queries.count')->get() ?? 0)
|
||||
->setDomainPurchased($this->pool->getItem('stats.domain.purchased')->get() ?? 0)
|
||||
->setDomainPurchaseFailed($this->pool->getItem('stats.domain.purchase.failed')->get() ?? 0)
|
||||
->setAlertSent($this->pool->getItem('stats.alert.sent')->get() ?? 0)
|
||||
->setWatchlistCount(
|
||||
$this->getCachedItem('stats.watchlist.count', fn () => $this->watchListRepository->count()
|
||||
))
|
||||
->setDomainCount(
|
||||
$this->getCachedItem('stats.domain.count', fn () => $this->domainRepository->createQueryBuilder('d')
|
||||
->join('d.tld', 't')
|
||||
->select('t.tld tld')
|
||||
->addSelect('COUNT(d.ldhName) AS domain')
|
||||
->addGroupBy('t.tld')
|
||||
->orderBy('domain', 'DESC')
|
||||
->setMaxResults(5)
|
||||
->getQuery()->getArrayResult())
|
||||
)
|
||||
->setDomainCountTotal(
|
||||
$this->getCachedItem('stats.domain.total', fn () => $this->domainRepository->count()
|
||||
));
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function getCachedItem(string $key, callable $getItemFunction)
|
||||
{
|
||||
$item = $this->pool->getItem($key);
|
||||
|
||||
if (!$item->isHit() || $this->kernel->isDebug()) {
|
||||
$value = $getItemFunction();
|
||||
$item
|
||||
->set($value)
|
||||
->expiresAfter(24 * 60 * 60);
|
||||
$this->pool->save($item);
|
||||
|
||||
return $value;
|
||||
} else {
|
||||
return $item->get();
|
||||
}
|
||||
}
|
||||
}
|
||||
125
src/Entity/Statistics.php
Normal file
125
src/Entity/Statistics.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\Get;
|
||||
use App\Controller\StatisticsController;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new Get(
|
||||
uriTemplate: '/stats',
|
||||
controller: StatisticsController::class,
|
||||
shortName: 'Statistics',
|
||||
read: false,
|
||||
),
|
||||
]
|
||||
)]
|
||||
class Statistics
|
||||
{
|
||||
private ?int $rdapQueries = null;
|
||||
private ?int $alertSent = null;
|
||||
private ?int $domainPurchased = null;
|
||||
private ?int $domainPurchaseFailed = null;
|
||||
|
||||
private ?array $domainCount = null;
|
||||
private ?int $domainCountTotal = null;
|
||||
private ?int $watchlistCount = null;
|
||||
|
||||
public function getRdapQueries(): ?int
|
||||
{
|
||||
return $this->rdapQueries;
|
||||
}
|
||||
|
||||
public function setRdapQueries(?int $rdapQueries): static
|
||||
{
|
||||
$this->rdapQueries = $rdapQueries;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAlertSent(): ?int
|
||||
{
|
||||
return $this->alertSent;
|
||||
}
|
||||
|
||||
public function setAlertSent(?int $alertSent): static
|
||||
{
|
||||
$this->alertSent = $alertSent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDomainPurchased(): ?int
|
||||
{
|
||||
return $this->domainPurchased;
|
||||
}
|
||||
|
||||
public function setDomainPurchased(?int $domainPurchased): static
|
||||
{
|
||||
$this->domainPurchased = $domainPurchased;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDomainCount(): ?array
|
||||
{
|
||||
return $this->domainCount;
|
||||
}
|
||||
|
||||
public function setDomainCount(?array $domainCount): static
|
||||
{
|
||||
$this->domainCount = $domainCount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWatchlistCount(): ?int
|
||||
{
|
||||
return $this->watchlistCount;
|
||||
}
|
||||
|
||||
public function setWatchlistCount(?int $watchlistCount): static
|
||||
{
|
||||
$this->watchlistCount = $watchlistCount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDomainCountTotal(): ?int
|
||||
{
|
||||
return $this->domainCountTotal;
|
||||
}
|
||||
|
||||
public function setDomainCountTotal(?int $domainCountTotal): void
|
||||
{
|
||||
$this->domainCountTotal = $domainCountTotal;
|
||||
}
|
||||
|
||||
public function getDomainPurchaseFailed(): ?int
|
||||
{
|
||||
return $this->domainPurchaseFailed;
|
||||
}
|
||||
|
||||
public function setDomainPurchaseFailed(?int $domainPurchaseFailed): static
|
||||
{
|
||||
$this->domainPurchaseFailed = $domainPurchaseFailed;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public static function updateRDAPQueriesStat(CacheItemPoolInterface $pool, string $key): bool
|
||||
{
|
||||
try {
|
||||
$item = $pool->getItem($key);
|
||||
$item->set(($item->get() ?? 0) + 1);
|
||||
|
||||
return $pool->save($item);
|
||||
} catch (\Throwable) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use App\Config\TriggerAction;
|
||||
use App\Config\WebhookScheme;
|
||||
use App\Entity\Domain;
|
||||
use App\Entity\DomainEvent;
|
||||
use App\Entity\Statistics;
|
||||
use App\Entity\WatchList;
|
||||
use App\Entity\WatchListTrigger;
|
||||
use App\Message\ProcessDomainTrigger;
|
||||
@@ -15,6 +16,7 @@ use App\Notifier\DomainOrderNotification;
|
||||
use App\Notifier\DomainUpdateNotification;
|
||||
use App\Repository\DomainRepository;
|
||||
use App\Repository\WatchListRepository;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
||||
@@ -41,7 +43,7 @@ final readonly class ProcessDomainTriggerHandler
|
||||
private KernelInterface $kernel,
|
||||
private LoggerInterface $logger,
|
||||
private HttpClientInterface $client,
|
||||
private MailerInterface $mailer
|
||||
private MailerInterface $mailer, private CacheItemPoolInterface $cacheItemPool
|
||||
) {
|
||||
$this->sender = new Address($mailerSenderEmail, $mailerSenderName);
|
||||
}
|
||||
@@ -82,6 +84,8 @@ final readonly class ProcessDomainTriggerHandler
|
||||
$notification = (new DomainOrderNotification($this->sender, $domain, $connector));
|
||||
$this->mailer->send($notification->asEmailMessage(new Recipient($watchList->getUser()->getEmail()))->getMessage());
|
||||
$this->sendChatNotification($watchList, $notification);
|
||||
|
||||
Statistics::updateRDAPQueriesStat($this->cacheItemPool, 'stats.domain.purchased');
|
||||
} catch (\Throwable) {
|
||||
$this->logger->warning('Unable to complete purchase. An error message is sent to user {username}.', [
|
||||
'username' => $watchList->getUser()->getUserIdentifier(),
|
||||
@@ -90,6 +94,8 @@ final readonly class ProcessDomainTriggerHandler
|
||||
$notification = (new DomainOrderErrorNotification($this->sender, $domain));
|
||||
$this->mailer->send($notification->asEmailMessage(new Recipient($watchList->getUser()->getEmail()))->getMessage());
|
||||
$this->sendChatNotification($watchList, $notification);
|
||||
|
||||
Statistics::updateRDAPQueriesStat($this->cacheItemPool, 'stats.domain.purchase.failed');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +120,8 @@ final readonly class ProcessDomainTriggerHandler
|
||||
} elseif (TriggerAction::SendChat == $watchListTrigger->getAction()) {
|
||||
$this->sendChatNotification($watchList, $notification);
|
||||
}
|
||||
|
||||
Statistics::updateRDAPQueriesStat($this->cacheItemPool, 'stats.alert.sent');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use App\Entity\EntityEvent;
|
||||
use App\Entity\Nameserver;
|
||||
use App\Entity\NameserverEntity;
|
||||
use App\Entity\RdapServer;
|
||||
use App\Entity\Statistics;
|
||||
use App\Entity\Tld;
|
||||
use App\Repository\DomainEntityRepository;
|
||||
use App\Repository\DomainEventRepository;
|
||||
@@ -24,6 +25,7 @@ use App\Repository\RdapServerRepository;
|
||||
use App\Repository\TldRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Exception\ORMException;
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpClient\Exception\ClientException;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
@@ -87,7 +89,8 @@ readonly class RDAPService
|
||||
private RdapServerRepository $rdapServerRepository,
|
||||
private TldRepository $tldRepository,
|
||||
private EntityManagerInterface $em,
|
||||
private LoggerInterface $logger
|
||||
private LoggerInterface $logger,
|
||||
private CacheItemPoolInterface $pool
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -162,6 +165,8 @@ readonly class RDAPService
|
||||
]);
|
||||
|
||||
try {
|
||||
Statistics::updateRDAPQueriesStat($this->pool, 'stats.rdap_queries.count');
|
||||
|
||||
$res = $this->client->request(
|
||||
'GET', $rdapServerUrl.'domain/'.$idnDomain
|
||||
)->toArray();
|
||||
|
||||
Reference in New Issue
Block a user