diff --git a/migrations/Version20250407154425.php b/migrations/Version20250407154425.php new file mode 100644 index 0000000..c472a1d --- /dev/null +++ b/migrations/Version20250407154425.php @@ -0,0 +1,33 @@ +addSql('CREATE INDEX IDX_STATUS ON client (status)'); + $this->addSql('CREATE INDEX IDX_UPDATED_AT ON client (updated_at)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP INDEX IDX_STATUS ON client'); + $this->addSql('DROP INDEX IDX_UPDATED_AT ON client'); + } +} diff --git a/migrations/Version20250407154620.php b/migrations/Version20250407154620.php new file mode 100644 index 0000000..5a2b12d --- /dev/null +++ b/migrations/Version20250407154620.php @@ -0,0 +1,31 @@ +addSql('CREATE INDEX IDX_STATUS_UPDATED_AT ON client (status, updated_at)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP INDEX IDX_STATUS_UPDATED_AT ON client'); + } +} diff --git a/src/Command/CheckClientAvailability.php b/src/Command/CheckClientAvailability.php new file mode 100644 index 0000000..bf7419e --- /dev/null +++ b/src/Command/CheckClientAvailability.php @@ -0,0 +1,98 @@ +modify(' - '.self::THRESHOLD_MINUTES . ' minutes'); + + $startQueryTime = microtime(true); + + $query = $this->entityManager->createQuery( + 'UPDATE App\Entity\Client c + SET c.status = :status + WHERE c.status = :currentStatus AND c.updatedAt < :threshold' + ); + $query->setParameter('status', ClientStatus::DISCONNECTED); + $query->setParameter('currentStatus', ClientStatus::OG_LIVE); + $query->setParameter('threshold', $threshold); + $updatedCount = $query->execute(); + + $queryTime = microtime(true) - $startQueryTime; + + $startMercureTime = microtime(true); + + $clients = $this->entityManager->createQueryBuilder() + ->select('c') + ->from(Client::class, 'c') + ->where('c.status = :status') + ->andWhere('c.updatedAt < :threshold') + ->setParameter('status', ClientStatus::DISCONNECTED) + ->setParameter('threshold', $threshold) + ->getQuery() + ->getResult(); + + $this->dispatchMercureEvent($clients); + + $mercureTime = microtime(true) - $startMercureTime; + + $io->success("Updated $updatedCount clients to DISCONNECTED status."); + $io->note("Query time: " . round($queryTime, 3) . "s"); + $io->note("Mercure dispatch time: " . round($mercureTime, 3) . "s"); + + return Command::SUCCESS; + } + + private function dispatchMercureEvent(array $clients, int $chunkSize = 10000): void + { + $chunks = array_chunk($clients, $chunkSize); + + foreach ($chunks as $chunk) { + $data = []; + + foreach ($chunk as $client) { + $data[] = [ + '@id' => '/clients/' . $client->getUuid(), + 'status' => $client->getStatus(), + ]; + } + + $update = new Update( + 'clients', + json_encode($data) + ); + + $this->hub->publish($update); + } + } + +} diff --git a/src/Command/TestCommand.php b/src/Command/TestCommand.php deleted file mode 100644 index fa8306b..0000000 --- a/src/Command/TestCommand.php +++ /dev/null @@ -1,44 +0,0 @@ -entityManager->getRepository(Trace::class)->find(7236); - - $trace->setStatus(TraceStatus::SUCCESS); - $trace->setProgress(1000); - - $this->entityManager->persist($trace); - $this->entityManager->flush(); - - return Command::SUCCESS; - } -} diff --git a/src/Controller/OgAgent/Webhook/StatusController.php b/src/Controller/OgAgent/Webhook/StatusController.php index 7973748..6871f1a 100644 --- a/src/Controller/OgAgent/Webhook/StatusController.php +++ b/src/Controller/OgAgent/Webhook/StatusController.php @@ -3,6 +3,7 @@ namespace App\Controller\OgAgent\Webhook; use App\Controller\OgRepository\Image\CreateAuxFilesAction; +use App\Entity\Client; use App\Entity\Image; use App\Entity\ImageImageRepository; use App\Entity\OperativeSystem; @@ -59,16 +60,24 @@ class StatusController extends AbstractController public function index(Request $request): JsonResponse { $data = $request->toArray(); - $requiredFields = ['job_id']; - - foreach ($requiredFields as $field) { - if (!isset($data[$field])) { - return new JsonResponse(['message' => "Missing parameter: $field"], Response::HTTP_BAD_REQUEST); - } - } $this->logger->info('Webhook data received', $data); + // Esta parte del codigo nos indica si el cliente se encuentra activo + if (isset($data['iph']) && isset($data['timestamp'])) { + $client = $this->entityManager->getRepository(Client::class)->findOneBy(['ip' => $data['iph']]); + if (!$client) { + $this->logger->error('Client not found', $data); + return new JsonResponse(['message' => 'Client not found'], Response::HTTP_NOT_FOUND); + } + + $updateAt = (new \DateTime())->setTimestamp((int)$data['timestamp']); + + $client->setUpdatedAt($updateAt); + $this->entityManager->persist($client); + $this->entityManager->flush(); + } + if (isset($data['progress'])){ $trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]); if ($trace){ diff --git a/src/Entity/Client.php b/src/Entity/Client.php index d550907..a3930ca 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -14,6 +14,9 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; #[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_MAC', fields: ['mac'])] #[UniqueEntity(fields: ['ip'], message: 'This IP address is already in use.')] #[UniqueEntity(fields: ['mac'], message: 'This MAC address is already in use.')] +#[ORM\Index(fields: ['status'], name: 'IDX_STATUS')] +#[ORM\Index(fields: ['updatedAt'], name: 'IDX_UPDATED_AT')] +#[ORM\Index(fields: ['status', 'updatedAt'], name: 'IDX_STATUS_UPDATED_AT')] class Client extends AbstractEntity { use NameableTrait; diff --git a/src/EventSubscriber/MercureSubscriber.php b/src/EventSubscriber/MercureSubscriber.php index 4f225ef..aaf1b3d 100644 --- a/src/EventSubscriber/MercureSubscriber.php +++ b/src/EventSubscriber/MercureSubscriber.php @@ -58,9 +58,14 @@ class MercureSubscriber implements EventSubscriberInterface /** @var Client $client */ $client = $clientOutput->getEntity(); + $data[] = [ + '@id' => '/clients/' . $client->getUuid(), + 'status' => $client->getStatus(), + ]; + $update = new Update( 'clients', - json_encode(['@id' => '/clients/'.$client->getUuid(), 'status' => $client->getStatus()]) + json_encode($data) ); $this->hub->publish($update); diff --git a/src/Model/ClientStatus.php b/src/Model/ClientStatus.php index c9882bb..01d88fb 100644 --- a/src/Model/ClientStatus.php +++ b/src/Model/ClientStatus.php @@ -6,6 +6,7 @@ final class ClientStatus { public const string OFF = 'off'; public const string INITIALIZING = 'initializing'; + public const string DISCONNECTED = 'disconnected'; public const string TURNING_OFF = 'turning-off'; public const string OG_LIVE = 'og-live'; public const string BUSY = 'busy'; @@ -20,6 +21,7 @@ final class ClientStatus self::OFF => 'Apagado', self::TURNING_OFF => 'Apagando', self::INITIALIZING => 'Inicializando', + self::DISCONNECTED => 'Conexión perdida', self::OG_LIVE => 'OG Live', self::BUSY => 'Ocupado', self::LINUX => 'Linux',