AzuraCast/src/Entity/Repository/ListenerRepository.php

134 lines
4.2 KiB
PHP

<?php
namespace App\Entity\Repository;
use App\Doctrine\Repository;
use App\Entity;
use Carbon\CarbonImmutable;
use DateTimeInterface;
use NowPlaying\Result\Client;
class ListenerRepository extends Repository
{
/**
* Get the number of unique listeners for a station during a specified time period.
*
* @param Entity\Station $station
* @param DateTimeInterface|int $start
* @param DateTimeInterface|int $end
*/
public function getUniqueListeners(Entity\Station $station, $start, $end): int
{
if ($start instanceof DateTimeInterface) {
$start = $start->getTimestamp();
}
if ($end instanceof DateTimeInterface) {
$end = $end->getTimestamp();
}
return (int)$this->em->createQuery(
<<<'DQL'
SELECT COUNT(DISTINCT l.listener_hash)
FROM App\Entity\Listener l
WHERE l.station_id = :station_id
AND l.timestamp_start <= :time_end
AND l.timestamp_end >= :time_start
DQL
)->setParameter('station_id', $station->getId())
->setParameter('time_end', $end)
->setParameter('time_start', $start)
->getSingleScalarResult();
}
/**
* Update listener data for a station.
*
* @param Entity\Station $station
* @param Client[] $clients
*/
public function update(Entity\Station $station, $clients): void
{
$existingClientsRaw = $this->em->createQuery(
<<<'DQL'
SELECT l.id, l.listener_uid, l.listener_hash
FROM App\Entity\Listener l
WHERE l.station = :station
AND l.timestamp_end = 0
DQL
)->setParameter('station', $station)
->getArrayResult();
$existingClients = [];
foreach ($existingClientsRaw as $client) {
$identifier = $client['listener_uid'] . '_' . $client['listener_hash'];
$existingClients[$identifier] = $client['id'];
}
foreach ($clients as $client) {
$listenerHash = Entity\Listener::calculateListenerHash($client);
$identifier = $client->uid . '_' . $listenerHash;
// Check for an existing record for this client.
if (isset($existingClients[$identifier])) {
unset($existingClients[$identifier]);
} else {
// Create a new record.
$record = new Entity\Listener($station, $client);
if (!empty($client->mount)) {
[$mountType, $mountId] = explode('_', $client->mount, 2);
if ('local' === $mountType) {
$record->setMount($this->em->getReference(Entity\StationMount::class, (int)$mountId));
} elseif ('remote' === $mountType) {
$record->setRemote($this->em->getReference(Entity\StationRemote::class, (int)$mountId));
}
}
$this->em->persist($record);
}
}
$this->em->flush();
// Mark the end of all other clients on this station.
if (!empty($existingClients)) {
$this->em->createQuery(
<<<'DQL'
UPDATE App\Entity\Listener l
SET l.timestamp_end = :time
WHERE l.id IN (:ids)
DQL
)->setParameter('time', time())
->setParameter('ids', array_values($existingClients))
->execute();
}
}
public function clearAll(): void
{
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\Listener l
DQL
)->execute();
}
public function cleanup(int $daysToKeep): void
{
$threshold = CarbonImmutable::now()
->subDays($daysToKeep)
->getTimestamp();
$this->em->createQuery(
<<<'DQL'
DELETE FROM App\Entity\Listener sh
WHERE sh.timestamp_start != 0
AND sh.timestamp_start <= :threshold
DQL
)->setParameter('threshold', $threshold)
->execute();
}
}