diff --git a/.env b/.env
index 3a0cfeb..24c54a5 100644
--- a/.env
+++ b/.env
@@ -50,3 +50,9 @@ UDS_AUTH_USERNAME="natiqindel"
UDS_AUTH_PASSWORD="correct horse battery staple"
UDS_URL=https://localhost:8087/uds/rest/
###< UDS ###
+
+###> symfony/mercure-bundle ###
+MERCURE_URL=http://ogcore-mercure:3000/.well-known/mercure
+MERCURE_PUBLIC_URL=http://ogcore-mercure:3000/.well-known/mercure
+MERCURE_JWT_SECRET="!ChangeThisMercureHubJWTSecretKey!"
+###< symfony/mercure-bundle ###
diff --git a/compose.override.yaml b/compose.override.yaml
index c5612b0..013f7da 100644
--- a/compose.override.yaml
+++ b/compose.override.yaml
@@ -5,3 +5,9 @@ services:
ports:
- "5432"
###< doctrine/doctrine-bundle ###
+
+###> symfony/mercure-bundle ###
+ mercure:
+ ports:
+ - "80"
+###< symfony/mercure-bundle ###
diff --git a/composer.json b/composer.json
index 9d05bf0..63cc9fa 100644
--- a/composer.json
+++ b/composer.json
@@ -27,6 +27,7 @@
"symfony/flex": "^2",
"symfony/framework-bundle": "6.4.*",
"symfony/http-client": "6.4.*",
+ "symfony/mercure-bundle": "^0.3.9",
"symfony/monolog-bundle": "^3.10",
"symfony/property-access": "6.4.*",
"symfony/property-info": "6.4.*",
diff --git a/composer.lock b/composer.lock
index 958dc40..4a369dc 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "2df97d4a1797242acadb47d83b3fbe98",
+ "content-hash": "ac4764e765324b86e616d7eb47a55e63",
"packages": [
{
"name": "api-platform/core",
@@ -4981,6 +4981,173 @@
],
"time": "2024-11-27T12:49:36+00:00"
},
+ {
+ "name": "symfony/mercure",
+ "version": "v0.6.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/mercure.git",
+ "reference": "304cf84609ef645d63adc65fc6250292909a461b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/mercure/zipball/304cf84609ef645d63adc65fc6250292909a461b",
+ "reference": "304cf84609ef645d63adc65fc6250292909a461b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.3",
+ "symfony/deprecation-contracts": "^2.0|^3.0|^4.0",
+ "symfony/http-client": "^4.4|^5.0|^6.0|^7.0",
+ "symfony/http-foundation": "^4.4|^5.0|^6.0|^7.0",
+ "symfony/polyfill-php80": "^1.22",
+ "symfony/web-link": "^4.4|^5.0|^6.0|^7.0"
+ },
+ "require-dev": {
+ "lcobucci/jwt": "^3.4|^4.0|^5.0",
+ "symfony/event-dispatcher": "^4.4|^5.0|^6.0|^7.0",
+ "symfony/http-kernel": "^4.4|^5.0|^6.0|^7.0",
+ "symfony/phpunit-bridge": "^5.2|^6.0|^7.0",
+ "symfony/stopwatch": "^4.4|^5.0|^6.0|^7.0",
+ "twig/twig": "^2.0|^3.0|^4.0"
+ },
+ "suggest": {
+ "symfony/stopwatch": "Integration with the profiler performances"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/dunglas/mercure",
+ "name": "dunglas/mercure"
+ },
+ "branch-alias": {
+ "dev-main": "0.6.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Mercure\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Kévin Dunglas",
+ "email": "dunglas@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Mercure Component",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "mercure",
+ "push",
+ "sse",
+ "updates"
+ ],
+ "support": {
+ "issues": "https://github.com/symfony/mercure/issues",
+ "source": "https://github.com/symfony/mercure/tree/v0.6.5"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/dunglas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/mercure",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-04-08T12:51:34+00:00"
+ },
+ {
+ "name": "symfony/mercure-bundle",
+ "version": "v0.3.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/mercure-bundle.git",
+ "reference": "77435d740b228e9f5f3f065b6db564f85f2cdb64"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/mercure-bundle/zipball/77435d740b228e9f5f3f065b6db564f85f2cdb64",
+ "reference": "77435d740b228e9f5f3f065b6db564f85f2cdb64",
+ "shasum": ""
+ },
+ "require": {
+ "lcobucci/jwt": "^3.4|^4.0|^5.0",
+ "php": ">=7.1.3",
+ "symfony/config": "^4.4|^5.0|^6.0|^7.0",
+ "symfony/dependency-injection": "^4.4|^5.4|^6.0|^7.0",
+ "symfony/http-kernel": "^4.4|^5.0|^6.0|^7.0",
+ "symfony/mercure": "^0.6.1",
+ "symfony/web-link": "^4.4|^5.0|^6.0|^7.0"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "^4.3.7|^5.0|^6.0|^7.0",
+ "symfony/stopwatch": "^4.3.7|^5.0|^6.0|^7.0",
+ "symfony/ux-turbo": "*",
+ "symfony/var-dumper": "^4.3.7|^5.0|^6.0|^7.0"
+ },
+ "suggest": {
+ "symfony/messenger": "To use the Messenger integration"
+ },
+ "type": "symfony-bundle",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "0.3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Bundle\\MercureBundle\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Kévin Dunglas",
+ "email": "dunglas@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony MercureBundle",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "mercure",
+ "push",
+ "sse",
+ "updates"
+ ],
+ "support": {
+ "issues": "https://github.com/symfony/mercure-bundle/issues",
+ "source": "https://github.com/symfony/mercure-bundle/tree/v0.3.9"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/dunglas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/mercure-bundle",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-05-31T09:07:18+00:00"
+ },
{
"name": "symfony/monolog-bridge",
"version": "v6.4.13",
diff --git a/config/api_platform/Client.yaml b/config/api_platform/Client.yaml
index f2322f6..a4c48f5 100644
--- a/config/api_platform/Client.yaml
+++ b/config/api_platform/Client.yaml
@@ -7,6 +7,7 @@ resources:
groups: ['default', 'client:read']
denormalizationContext:
groups: ['client:write']
+
operations:
ApiPlatform\Metadata\GetCollection:
provider: App\State\Provider\ClientProvider
diff --git a/config/bundles.php b/config/bundles.php
index f1a3820..15fa539 100644
--- a/config/bundles.php
+++ b/config/bundles.php
@@ -17,4 +17,5 @@ return [
Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true],
DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
+ Symfony\Bundle\MercureBundle\MercureBundle::class => ['all' => true],
];
diff --git a/config/packages/api_platform.yaml b/config/packages/api_platform.yaml
index 7adc4f3..b957e6a 100644
--- a/config/packages/api_platform.yaml
+++ b/config/packages/api_platform.yaml
@@ -5,6 +5,9 @@ api_platform:
path_segment_name_generator: api_platform.path_segment_name_generator.dash
defaults:
pagination_client_items_per_page: true
+ mercure:
+ enabled: true
+
collection:
pagination:
items_per_page_parameter_name: 'itemsPerPage'
diff --git a/config/packages/mercure.yaml b/config/packages/mercure.yaml
new file mode 100644
index 0000000..f2a7395
--- /dev/null
+++ b/config/packages/mercure.yaml
@@ -0,0 +1,8 @@
+mercure:
+ hubs:
+ default:
+ url: '%env(MERCURE_URL)%'
+ public_url: '%env(MERCURE_PUBLIC_URL)%'
+ jwt:
+ secret: '%env(MERCURE_JWT_SECRET)%'
+ publish: '*'
diff --git a/config/packages/monolog.yaml b/config/packages/monolog.yaml
index 4dfd5a8..d0608d0 100644
--- a/config/packages/monolog.yaml
+++ b/config/packages/monolog.yaml
@@ -20,11 +20,10 @@ when@test:
monolog:
handlers:
main:
- type: fingers_crossed
- action_level: error
- handler: nested
- excluded_http_codes: [404, 405]
- channels: ["!event"]
+ type: stream
+ path: "%kernel.logs_dir%/%kernel.environment%.log"
+ level: error
+
nested:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
diff --git a/docker-compose.yaml b/docker-compose.yaml
index b6c7909..c15177a 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -42,7 +42,31 @@ services:
networks:
- ogcore-network
+
+ mercure:
+ image: dunglas/mercure
+ restart: unless-stopped
+ container_name: ogcore-mercure
+ environment:
+ # Uncomment the following line to disable HTTPS,
+ SERVER_NAME: ':3000'
+ MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
+ MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
+ MERCURE_EXTRA_DIRECTIVES: |
+ cors_origins *
+ # Comment the following line to disable the development mode
+ command: /usr/bin/caddy run --config /etc/caddy/dev.Caddyfile
+ ports:
+ - "3000:3000"
+ volumes:
+ - mercure_data:/data
+ - mercure_config:/config
+ networks:
+ - ogcore-network
+
volumes:
+ mercure_data:
+ mercure_config:
database_data:
networks:
diff --git a/docker/default.conf b/docker/default.conf
index 0cb5a45..c67e1ef 100644
--- a/docker/default.conf
+++ b/docker/default.conf
@@ -15,6 +15,17 @@ server {
ssl_certificate /etc/nginx/certs/ogcore.uds-test.net.crt.pem;
ssl_certificate_key /etc/nginx/certs/ogcore.uds-test.net.key.pem;
+ location /.well-known/mercure {
+ proxy_pass https://mercure:3000/.well-known/mercure;
+ proxy_read_timeout 24h;
+ proxy_http_version 1.1;
+ proxy_set_header Connection "";
+
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+
location /opengnsys/rest/ous// {
rewrite ^/opengnsys/rest/ous//([0-9]+)/images /opengnsys/rest/ous/$1/images;
rewrite ^/opengnsys/rest/ous//([0-9]+)/labs /opengnsys/rest/ous/$1/labs;
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index f6da34e..7b99837 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -15,6 +15,7 @@
+
diff --git a/src/Command/TestCommand.php b/src/Command/TestCommand.php
new file mode 100644
index 0000000..fa8306b
--- /dev/null
+++ b/src/Command/TestCommand.php
@@ -0,0 +1,44 @@
+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/DeployImageAction.php b/src/Controller/OgAgent/DeployImageAction.php
index 65a5de9..1c5b1c9 100644
--- a/src/Controller/OgAgent/DeployImageAction.php
+++ b/src/Controller/OgAgent/DeployImageAction.php
@@ -47,8 +47,6 @@ class DeployImageAction extends AbstractController
throw new ValidatorException('IP is required');
}
- $partitionInfo = json_decode($image->getPartitionInfo(), true);
-
$method = match ($input->method) {
DeployMethodTypes::MULTICAST_UFTP_DIRECT, DeployMethodTypes::MULTICAST_UDPCAST_DIRECT, => 'multicast-direct',
DeployMethodTypes::MULTICAST, DeployMethodTypes::MULTICAST_UFTP, DeployMethodTypes::MULTICAST_UDPCAST => 'multicast',
diff --git a/src/Controller/OgAgent/PowerOffAction.php b/src/Controller/OgAgent/PowerOffAction.php
index 2f5f0b1..4817ca5 100644
--- a/src/Controller/OgAgent/PowerOffAction.php
+++ b/src/Controller/OgAgent/PowerOffAction.php
@@ -41,12 +41,17 @@ class PowerOffAction extends AbstractController
public function __invoke(MultipleClientsInput $input): JsonResponse
{
foreach ($input->clients as $clientEntity) {
+ /** @var Client $client */
$client = $clientEntity->getEntity();
if (!$client->getIp()) {
throw new ValidatorException('IP is required');
}
+ if ($client->getStatus() === ClientStatus::OFF) {
+ continue;
+ }
+
$data = [
'nfn' => 'Apagar',
'ids' => '0'
@@ -70,7 +75,7 @@ class PowerOffAction extends AbstractController
$jobId = json_decode($response->getContent(), true)['job_id'];
- $client->setStatus(ClientStatus::OFF);
+ $client->setStatus(ClientStatus::TURNING_OFF);
$this->entityManager->persist($client);
$this->entityManager->flush();
diff --git a/src/Controller/OgAgent/Webhook/ClientsController.php b/src/Controller/OgAgent/Webhook/ClientsController.php
index c6c9573..b5970e3 100644
--- a/src/Controller/OgAgent/Webhook/ClientsController.php
+++ b/src/Controller/OgAgent/Webhook/ClientsController.php
@@ -34,6 +34,11 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class ClientsController extends AbstractController
{
+ const string CREATE_IMAGE = 'RESPUESTA_CrearImagen';
+ const string RESTORE_IMAGE = 'RESPUESTA_RestaurarImagen';
+ const string CONFIGURE_IMAGE = 'RESPUESTA_Configurar';
+
+
public function __construct(
protected readonly EntityManagerInterface $entityManager,
public readonly CreateAuxFilesAction $createAuxFilesAction,
@@ -54,7 +59,7 @@ class ClientsController extends AbstractController
public function index(Request $request): JsonResponse
{
$data = $request->toArray();
- $requiredFields = ['nfn', 'res', 'der', 'job_id'];
+ $requiredFields = ['job_id'];
foreach ($requiredFields as $field) {
if (!isset($data[$field])) {
@@ -64,7 +69,16 @@ class ClientsController extends AbstractController
$this->logger->info('Webhook data received', $data);
- if ($data['nfn'] === 'RESPUESTA_CrearImagen') {
+ if (isset($data['progress'])){
+ $trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
+ if ($trace){
+ $trace->setProgress($data['progress'] * 1000);
+ $this->entityManager->persist($trace);
+ $this->entityManager->flush();
+ }
+ }
+
+ if (isset($data['nfn']) && $data['nfn'] === self::CREATE_IMAGE) {
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
/** @var ImageImageRepository $imageImageRepository */
$imageImageRepository = $this->entityManager->getRepository(ImageImageRepository::class)->findOneBy(['uuid' => $data['idi']]);
@@ -82,10 +96,8 @@ class ClientsController extends AbstractController
if ($data['res'] === 1) {
$trace->setStatus(TraceStatus::SUCCESS);
$trace->setFinishedAt(new \DateTime());
-
$imageImageRepository->setStatus(ImageStatus::AUX_FILES_PENDING);
$imageImageRepository->setCreated(true);
-
$this->entityManager->persist($imageImageRepository);
$this->logger->info('Start partition creation. ', ['image' => (string) $imageImageRepository->getUuid()]);
@@ -95,11 +107,13 @@ class ClientsController extends AbstractController
$this->logger->info('Starting software profile creation. ', ['image' => (string) $imageImageRepository->getUuid()]);
$this->createSoftwareProfile($data['inv_sft'], $imageImageRepository);
$this->logger->info('Start aux files ogrepo API ', ['image' => (string) $imageImageRepository->getUuid()]);
+
try {
$this->createAuxFilesAction->__invoke($imageImageRepository);
} catch (\Exception $e) {
$this->logger->error('Error creating aux files', ['image' => (string) $imageImageRepository->getUuid(), 'error' => $e->getMessage()]);
}
+
$this->logger->info('End aux files ogrepo API ', ['image' => (string) $imageImageRepository->getUuid()]);
} else {
$trace->setStatus(TraceStatus::FAILED);
@@ -119,9 +133,8 @@ class ClientsController extends AbstractController
$this->logger->info('Image updated. Success.', ['image' => (string) $imageImageRepository->getUuid()]);
}
- if ($data['nfn'] === 'RESPUESTA_RestaurarImagen'|| $data['nfn'] === 'RESPUESTA_Configurar') {
+ if (isset($data['nfn']) && ($data['nfn'] === self::RESTORE_IMAGE || $data['nfn'] === self::CONFIGURE_IMAGE)) {
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
-
$client = $trace->getClient();
if ($data['res'] === 1) {
diff --git a/src/Controller/OgRepository/Image/CreateAuxFilesAction.php b/src/Controller/OgRepository/Image/CreateAuxFilesAction.php
index 2f927a1..7a28bc2 100644
--- a/src/Controller/OgRepository/Image/CreateAuxFilesAction.php
+++ b/src/Controller/OgRepository/Image/CreateAuxFilesAction.php
@@ -45,7 +45,7 @@ class CreateAuxFilesAction extends AbstractOgRepositoryController
$this->logger->info('Creating aux files', ['image' => $image->getName()]);
- $repository = $image->getClient()->getRepository();
+ $repository = $data->getRepository();
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/torrentsum', $params);
diff --git a/src/Controller/OgRepository/Image/DeleteTrashAction.php b/src/Controller/OgRepository/Image/DeleteTrashAction.php
index 4a370af..8ff17d7 100644
--- a/src/Controller/OgRepository/Image/DeleteTrashAction.php
+++ b/src/Controller/OgRepository/Image/DeleteTrashAction.php
@@ -37,8 +37,6 @@ class DeleteTrashAction extends AbstractOgRepositoryController
$this->logger->info('Deleting image', ['image' => $image->getName()]);
- $repository = $image->getClient()->getRepository();
-
$content = $this->createRequest('DELETE', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/'.$imageImageRepository->getImageFullsum().'?method=trash');
$this->logger->info('Image deleted', ['image' => $image->getName()]);
diff --git a/src/Controller/OgRepository/Image/RecoverAction.php b/src/Controller/OgRepository/Image/RecoverAction.php
index 123aa65..1b9e4bf 100644
--- a/src/Controller/OgRepository/Image/RecoverAction.php
+++ b/src/Controller/OgRepository/Image/RecoverAction.php
@@ -44,7 +44,7 @@ class RecoverAction extends AbstractOgRepositoryController
$this->logger->info('Recovering image', ['image' => $image->getName()]);
- $repository = $image->getClient()->getRepository();
+ $repository = $data->getRepository();
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/trash/images', $params);
diff --git a/src/Dto/Output/TraceOutput.php b/src/Dto/Output/TraceOutput.php
index bc3f35e..14ea96b 100644
--- a/src/Dto/Output/TraceOutput.php
+++ b/src/Dto/Output/TraceOutput.php
@@ -35,7 +35,7 @@ final class TraceOutput extends AbstractOutput
public ?\DateTimeInterface $finishedAt = null;
#[Groups(['trace:read'])]
- public ?int $progress = null;
+ public ?float $progress = null;
#[Groups(['trace:read'])]
public \DateTime $createdAt;
@@ -59,7 +59,7 @@ final class TraceOutput extends AbstractOutput
$this->output = $trace->getOutput();
$this->input = $trace->getInput();
$this->finishedAt = $trace->getFinishedAt();
- $this->progress = $trace->getProgress();
+ $this->progress = $trace->getProgress() / 100;
$this->createdAt = $trace->getCreatedAt();
$this->createdBy = $trace->getCreatedBy();
}
diff --git a/src/Entity/Client.php b/src/Entity/Client.php
index b49aacd..6f210ba 100644
--- a/src/Entity/Client.php
+++ b/src/Entity/Client.php
@@ -2,6 +2,7 @@
namespace App\Entity;
+use ApiPlatform\Metadata\ApiResource;
use App\Repository\ClientRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
@@ -152,6 +153,7 @@ class Client extends AbstractEntity
return $this->status;
}
+ #[ORM\PostPersist]
public function setStatus(?string $status): static
{
$this->status = $status;
diff --git a/src/EventListener/ClientStatusNotifier.php b/src/EventListener/ClientStatusNotifier.php
new file mode 100644
index 0000000..e16e5b5
--- /dev/null
+++ b/src/EventListener/ClientStatusNotifier.php
@@ -0,0 +1,39 @@
+logger = $logger;
+ }
+
+ public function postUpdate(Client $client, PostUpdateEventArgs $event): void
+ {
+ $update = new Update(
+ 'clients',
+ json_encode(['@id' => '/clients/'.$client->getUuid(), 'status' => $client->getStatus()])
+ );
+ $this->hub->publish($update);
+
+ $this->logger->info('Evento Mercure disparado. Cambio en el estado de un cliente: ', [
+ 'client' => $client->getUuid(),
+ 'status' => $client->getStatus(),
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/src/EventListener/TraceStatusProgressNotifier.php b/src/EventListener/TraceStatusProgressNotifier.php
new file mode 100644
index 0000000..29b2cc1
--- /dev/null
+++ b/src/EventListener/TraceStatusProgressNotifier.php
@@ -0,0 +1,41 @@
+logger = $logger;
+ }
+
+ public function postUpdate(Trace $trace, PostUpdateEventArgs $event): void
+ {
+ $update = new Update(
+ 'traces',
+ json_encode(['@id' => '/traces/'.$trace->getUuid(), 'status' => $trace->getStatus(), 'progress' => $trace->getProgress() / 100])
+ );
+ $this->hub->publish($update);
+
+ $this->logger->info('Evento Mercure disparado. Cambio en el estado de una traza/log: ', [
+ 'client' => $trace->getUuid(),
+ 'status' => $trace->getStatus(),
+ 'progress' => $trace->getProgress(),
+ ]);
+ }
+}
\ No newline at end of file
diff --git a/src/EventSubscriber/MercureSubscriber.php b/src/EventSubscriber/MercureSubscriber.php
new file mode 100644
index 0000000..6b6a843
--- /dev/null
+++ b/src/EventSubscriber/MercureSubscriber.php
@@ -0,0 +1,66 @@
+logger = $logger;
+ }
+
+ public static function getSubscribedEvents(): array
+ {
+ return [
+ KernelEvents::VIEW => ['onKernelView', EventPriorities::POST_WRITE],
+ ];
+ }
+
+ public function onKernelView(ViewEvent $event): void
+ {
+ $request = $event->getRequest();
+ $method = $request->getMethod();
+
+ $clientOutput = $event->getControllerResult();
+
+ if (!in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'])) {
+ return;
+ }
+
+ $method = $event->getRequest()->getMethod();
+
+ if (!$clientOutput instanceof ClientOutput || (Request::METHOD_POST !== $method && Request::METHOD_PUT !== $method && Request::METHOD_PATCH !== $method)) {
+ return;
+ }
+
+ /** @var Client $client */
+ $client = $clientOutput->getEntity();
+
+ $update = new Update(
+ 'clients',
+ json_encode(['@id' => '/clients/'.$client->getUuid(), 'status' => $client->getStatus()])
+ );
+ $this->hub->publish($update);
+
+ $this->logger->info('Evento Mercure disparado', [
+ 'method' => $method,
+ 'path' => $request->getPathInfo()
+ ]);
+ }
+}
diff --git a/src/Model/ClientStatus.php b/src/Model/ClientStatus.php
index 88f2fe2..c9882bb 100644
--- a/src/Model/ClientStatus.php
+++ b/src/Model/ClientStatus.php
@@ -5,27 +5,20 @@ namespace App\Model;
final class ClientStatus
{
public const string OFF = 'off';
-
public const string INITIALIZING = 'initializing';
-
+ public const string TURNING_OFF = 'turning-off';
public const string OG_LIVE = 'og-live';
-
public const string BUSY = 'busy';
-
public const string LINUX = 'linux';
-
public const string LINUX_SESSION = 'linux-session';
-
public const string MACOS = 'macos';
-
public const string MACOS_SESSION = 'macos-session';
-
public const string WINDOWS = 'windows';
-
public const string WINDOWS_SESSION = 'windows-session';
private const array CLIENT_STATUSES = [
self::OFF => 'Apagado',
+ self::TURNING_OFF => 'Apagando',
self::INITIALIZING => 'Inicializando',
self::OG_LIVE => 'OG Live',
self::BUSY => 'Ocupado',
diff --git a/symfony.lock b/symfony.lock
index db1b578..03e0eb7 100644
--- a/symfony.lock
+++ b/symfony.lock
@@ -13,6 +13,18 @@
"src/ApiResource/.gitignore"
]
},
+ "dama/doctrine-test-bundle": {
+ "version": "8.2",
+ "recipe": {
+ "repo": "github.com/symfony/recipes-contrib",
+ "branch": "main",
+ "version": "7.2",
+ "ref": "896306d79d4ee143af9eadf9b09fd34a8c391b70"
+ },
+ "files": [
+ "config/packages/dama_doctrine_test_bundle.yaml"
+ ]
+ },
"doctrine/doctrine-bundle": {
"version": "2.13",
"recipe": {
@@ -27,6 +39,18 @@
"src/Repository/.gitignore"
]
},
+ "doctrine/doctrine-fixtures-bundle": {
+ "version": "3.7",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "main",
+ "version": "3.0",
+ "ref": "1f5514cfa15b947298df4d771e694e578d4c204d"
+ },
+ "files": [
+ "src/DataFixtures/AppFixtures.php"
+ ]
+ },
"doctrine/doctrine-migrations-bundle": {
"version": "3.3",
"recipe": {
@@ -78,6 +102,20 @@
"config/packages/nelmio_cors.yaml"
]
},
+ "phpunit/phpunit": {
+ "version": "9.6",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "main",
+ "version": "9.6",
+ "ref": "7364a21d87e658eb363c5020c072ecfdc12e2326"
+ },
+ "files": [
+ ".env.test",
+ "phpunit.xml.dist",
+ "tests/bootstrap.php"
+ ]
+ },
"ramsey/uuid-doctrine": {
"version": "2.1",
"recipe": {
@@ -143,6 +181,27 @@
"src/Kernel.php"
]
},
+ "symfony/maker-bundle": {
+ "version": "1.61",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "main",
+ "version": "1.0",
+ "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
+ }
+ },
+ "symfony/mercure-bundle": {
+ "version": "0.3",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "main",
+ "version": "0.3",
+ "ref": "528285147494380298f8f991ee8c47abebaf79db"
+ },
+ "files": [
+ "config/packages/mercure.yaml"
+ ]
+ },
"symfony/monolog-bundle": {
"version": "3.10",
"recipe": {
@@ -155,6 +214,21 @@
"config/packages/monolog.yaml"
]
},
+ "symfony/phpunit-bridge": {
+ "version": "7.2",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "main",
+ "version": "6.3",
+ "ref": "a411a0480041243d97382cac7984f7dce7813c08"
+ },
+ "files": [
+ ".env.test",
+ "bin/phpunit",
+ "phpunit.xml.dist",
+ "tests/bootstrap.php"
+ ]
+ },
"symfony/routing": {
"version": "6.4",
"recipe": {
@@ -218,5 +292,30 @@
"files": [
"config/packages/validator.yaml"
]
+ },
+ "symfony/web-profiler-bundle": {
+ "version": "6.4",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "main",
+ "version": "6.1",
+ "ref": "e42b3f0177df239add25373083a564e5ead4e13a"
+ },
+ "files": [
+ "config/packages/web_profiler.yaml",
+ "config/routes/web_profiler.yaml"
+ ]
+ },
+ "zenstruck/foundry": {
+ "version": "1.38",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "main",
+ "version": "1.10",
+ "ref": "37c2f894cc098ab4c08874b80cccc8e2f8de7976"
+ },
+ "files": [
+ "config/packages/zenstruck_foundry.yaml"
+ ]
}
}