[#FER-19] Ajouter le healthCheck du pont bascule (!58)
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
| Numéro du ticket | Titre du ticket | |------------------|-----------------| | | | ## Description de la PR ## Modification du .env ## Check list - [x] Pas de régression - [x] TU/TI/TF rédigée - [x] TU/TI/TF OK - [x] CHANGELOG modifié Reviewed-on: #58 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #58.
This commit is contained in:
46
src/ApiResource/PontBasculeHealthCheck.php
Normal file
46
src/ApiResource/PontBasculeHealthCheck.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\ApiResource;
|
||||
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\Get;
|
||||
use ApiPlatform\OpenApi\Model\Operation as OpenApiOperation;
|
||||
use App\State\PontBasculeHealthProvider;
|
||||
use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new Get(
|
||||
uriTemplate: '/pont_bascule/health',
|
||||
openapi: new OpenApiOperation(
|
||||
summary: 'Pont-bascule health check',
|
||||
description: 'Returns the connection state of the pont-bascule. Always 200, even when unreachable.',
|
||||
),
|
||||
normalizationContext: ['groups' => ['pont_bascule:health:read']],
|
||||
security: "is_granted('ROLE_USER')",
|
||||
provider: PontBasculeHealthProvider::class,
|
||||
),
|
||||
],
|
||||
)]
|
||||
final class PontBasculeHealthCheck
|
||||
{
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
public bool $healthy = false;
|
||||
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
public bool $ok = false;
|
||||
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
public bool $busy = false;
|
||||
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
public bool $portConnected = false;
|
||||
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
public ?string $portError = null;
|
||||
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
public ?string $hostname = null;
|
||||
}
|
||||
60
src/Dto/PontBasculeHealth.php
Normal file
60
src/Dto/PontBasculeHealth.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
final readonly class PontBasculeHealth
|
||||
{
|
||||
public function __construct(
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
private bool $healthy,
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
private bool $ok = false,
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
private bool $busy = false,
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
private bool $portConnected = false,
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
private ?string $portError = null,
|
||||
#[Groups(['pont_bascule:health:read'])]
|
||||
private ?string $hostname = null,
|
||||
) {}
|
||||
|
||||
public static function unhealthy(): self
|
||||
{
|
||||
return new self(false);
|
||||
}
|
||||
|
||||
public function isHealthy(): bool
|
||||
{
|
||||
return $this->healthy;
|
||||
}
|
||||
|
||||
public function isOk(): bool
|
||||
{
|
||||
return $this->ok;
|
||||
}
|
||||
|
||||
public function isBusy(): bool
|
||||
{
|
||||
return $this->busy;
|
||||
}
|
||||
|
||||
public function isPortConnected(): bool
|
||||
{
|
||||
return $this->portConnected;
|
||||
}
|
||||
|
||||
public function getPortError(): ?string
|
||||
{
|
||||
return $this->portError;
|
||||
}
|
||||
|
||||
public function getHostname(): ?string
|
||||
{
|
||||
return $this->hostname;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Dto\PontBasculeHealth;
|
||||
use App\Dto\PontBasculeReading;
|
||||
use App\Exception\PontBasculeException;
|
||||
use DateTimeImmutable;
|
||||
@@ -15,7 +16,7 @@ final class PontBasculeService
|
||||
public function __construct(
|
||||
private readonly HttpClientInterface $httpClient,
|
||||
private readonly PontBasculePayloadDecoder $payloadDecoder,
|
||||
private readonly string $endpoint,
|
||||
private readonly string $baseUrl,
|
||||
private readonly bool $bypass,
|
||||
) {}
|
||||
|
||||
@@ -28,7 +29,7 @@ final class PontBasculeService
|
||||
$body = $this->getBypassPayload();
|
||||
} else {
|
||||
try {
|
||||
$response = $this->httpClient->request('POST', $this->endpoint);
|
||||
$response = $this->httpClient->request('POST', $this->buildUrl('/send/dsd'));
|
||||
$body = $response->getContent(false);
|
||||
} catch (TransportExceptionInterface $exception) {
|
||||
throw PontBasculeException::transportFailure($exception->getMessage());
|
||||
@@ -44,6 +45,54 @@ final class PontBasculeService
|
||||
);
|
||||
}
|
||||
|
||||
public function checkHealth(): PontBasculeHealth
|
||||
{
|
||||
if ($this->bypass) {
|
||||
return new PontBasculeHealth(
|
||||
healthy: true,
|
||||
ok: true,
|
||||
busy: false,
|
||||
portConnected: true,
|
||||
portError: null,
|
||||
hostname: 'bypass',
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request('GET', $this->buildUrl('/health'));
|
||||
$body = $response->getContent(false);
|
||||
} catch (TransportExceptionInterface) {
|
||||
return PontBasculeHealth::unhealthy();
|
||||
}
|
||||
|
||||
$payload = json_decode($body, true);
|
||||
if (!is_array($payload)) {
|
||||
return PontBasculeHealth::unhealthy();
|
||||
}
|
||||
|
||||
$ok = true === ($payload['ok'] ?? null);
|
||||
$busy = true === ($payload['busy'] ?? null);
|
||||
$portConnected = true === ($payload['port_connected'] ?? null);
|
||||
$portError = $payload['port_error'] ?? null;
|
||||
$hostname = $payload['hostname'] ?? null;
|
||||
|
||||
$healthy = $ok && $portConnected && !$busy && null === $portError;
|
||||
|
||||
return new PontBasculeHealth(
|
||||
healthy: $healthy,
|
||||
ok: $ok,
|
||||
busy: $busy,
|
||||
portConnected: $portConnected,
|
||||
portError: is_string($portError) ? $portError : null,
|
||||
hostname: is_string($hostname) ? $hostname : null,
|
||||
);
|
||||
}
|
||||
|
||||
private function buildUrl(string $path): string
|
||||
{
|
||||
return rtrim($this->baseUrl, '/').$path;
|
||||
}
|
||||
|
||||
private function getBypassPayload(): string
|
||||
{
|
||||
return '{"ok":true,"busy":false,"mode":"serial","port":"/dev/ttyUSB0","baudrate":9600,"request_hex":"01 10 39 39 4D 0D 0A","response_hex":"01 02 30 34 30 32 30 30 02 30 31 30 30 31 34 32 30 2E 6B 67 20 02 30 32 30 30 30 30 30 30 2E 6B 67 20 02 30 33 30 30 31 34 32 30 2E 6B 67 20 02 39 39 30 30 31 32 31 0D 0A","response_ascii":"\u0001\u0002040200\u000201001420.kg \u000202000000.kg \u000203001420.kg \u00029900121"}';
|
||||
|
||||
32
src/State/PontBasculeHealthProvider.php
Normal file
32
src/State/PontBasculeHealthProvider.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\State;
|
||||
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\ApiResource\PontBasculeHealthCheck;
|
||||
use App\Service\PontBasculeService;
|
||||
|
||||
final readonly class PontBasculeHealthProvider implements ProviderInterface
|
||||
{
|
||||
public function __construct(
|
||||
private PontBasculeService $pontBasculeService,
|
||||
) {}
|
||||
|
||||
public function provide(Operation $operation, array $uriVariables = [], array $context = []): PontBasculeHealthCheck
|
||||
{
|
||||
$health = $this->pontBasculeService->checkHealth();
|
||||
|
||||
$resource = new PontBasculeHealthCheck();
|
||||
$resource->healthy = $health->isHealthy();
|
||||
$resource->ok = $health->isOk();
|
||||
$resource->busy = $health->isBusy();
|
||||
$resource->portConnected = $health->isPortConnected();
|
||||
$resource->portError = $health->getPortError();
|
||||
$resource->hostname = $health->getHostname();
|
||||
|
||||
return $resource;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user