diff --git a/config/services.yaml b/config/services.yaml index 3118bb2..f04a8e2 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -39,6 +39,13 @@ services: arguments: $username: '%app.usetreno.username%' $password: '%app.usetreno.password%' + $retryCount: 2 + $retryWaitSeconds: 0.5 + + App\Service\Remote\UsetrenoQRCodeProvider: + arguments: + $retryCount: 2 + $retryWaitSeconds: 0.5 App\Service\CachedQRCodeGenerator: arguments: diff --git a/src/Entity/Remote/Usetreno/AuthRequest.php b/src/Entity/Remote/Usetreno/AuthRequest.php index 2d475d5..a13779e 100644 --- a/src/Entity/Remote/Usetreno/AuthRequest.php +++ b/src/Entity/Remote/Usetreno/AuthRequest.php @@ -1,4 +1,5 @@ static::AUTHORIZE_API ]); - $rq = $this->innerClient->request( - "POST", - static::AUTHORIZE_API, - [ - 'json' => new AuthRequest($this->username, $this->password), - ] - ); + $responseData = $this->retryingFailRequest($this->retryCount, $this->retryWaitSeconds, + [AuthorizeException::class, TransportException::class], $this->logger, function() { + $rq = $this->innerClient->request( + "POST", + static::AUTHORIZE_API, + [ + 'json' => new AuthRequest($this->username, $this->password), + ] + ); - $statusCode = $rq->getStatusCode(); - $responseData = $rq->getContent(false); + $statusCode = $rq->getStatusCode(); + $responseData = $rq->getContent(false); - if ($statusCode != 200) { - $this->logger->error("authorization request status code is not ok", [ - "AUTHORIZE_API" => static::AUTHORIZE_API, - "statusCode" => $statusCode, - "content" => $responseData, - "username" => $this->username - ]); + if ($statusCode != 200) { + $this->logger->error("authorization request status code is not ok", [ + "AUTHORIZE_API" => static::AUTHORIZE_API, + "statusCode" => $statusCode, + "content" => $responseData, + "username" => $this->username + ]); - throw new AuthorizeException("Return code is not 200 OK (got: code: $statusCode)"); + throw new AuthorizeException("Return code is not 200 OK (got: code: $statusCode)"); + } + + return $responseData; + }); + + if (!is_string($responseData)) { + throw new ThisShouldNeverHappenException("responseData is not a string"); } $this->authorizationToken = $this->processAuthorizeResponse($responseData); diff --git a/src/Service/Remote/UsetrenoQRCodeProvider.php b/src/Service/Remote/UsetrenoQRCodeProvider.php index fe3d6bf..c824e32 100644 --- a/src/Service/Remote/UsetrenoQRCodeProvider.php +++ b/src/Service/Remote/UsetrenoQRCodeProvider.php @@ -7,16 +7,23 @@ use App\Entity\DTO\QRCode\QRCode; use App\Service\CacheableQRCodeGeneratorInterface; use App\Service\Remote\Edge\QRCodeEntityConverter; use App\Service\Remote\Exception\UsetrenoQRCodeException; +use App\Service\Remote\Exception\UsetrenoQRCodeRemoteServerErrorException; +use Nubium\Exception\ThisShouldNeverHappenException; use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Exception\TransportException; class UsetrenoQRCodeProvider implements CacheableQRCodeGeneratorInterface { + use RetryingFailClientTrait; + const QRCODE_API = 'https://topapi.top-test.cz/chameleon/api/v1/qr-code/create-for-bank-account-payment'; const QRCODE_METHOD = 'POST'; public function __construct(protected readonly LoggerInterface $logger, protected readonly UsetrenoHttpClient $client, - protected readonly QRCodeEntityConverter $codeEntityConverter) { } + protected readonly QRCodeEntityConverter $codeEntityConverter, + protected readonly float $retryWaitSeconds, + protected readonly int $retryCount) { } public function generateQRCodeFromEntity(QRCode $entity): string { @@ -27,27 +34,41 @@ class UsetrenoQRCodeProvider implements CacheableQRCodeGeneratorInterface "edgeEntity" => $edgeEntity ]); - $response = $this->client->request(static::QRCODE_METHOD, static::QRCODE_API, [ - 'json' => $edgeEntity, - ]); + $responseData = $this->retryingFailRequest($this->retryCount, $this->retryWaitSeconds, + [TransportException::class, UsetrenoQRCodeRemoteServerErrorException::class], $this->logger, + function() use ($edgeEntity) { + $response = $this->client->request(static::QRCODE_METHOD, static::QRCODE_API, [ + 'json' => $edgeEntity, + ]); - $statusCode = $response->getStatusCode(); - $responseData = $response->getContent(false); + $statusCode = $response->getStatusCode(); + $responseData = $response->getContent(false); - if ($statusCode != 200) { - $this->logger->error("qrcode request status code is not ok", [ - "AUTHORIZE_API" => static::QRCODE_API, - "statusCode" => $statusCode, - "content" => $responseData, - ]); + if ($statusCode != 200) { + $this->logger->error("qrcode request status code is not ok", [ + "AUTHORIZE_API" => static::QRCODE_API, + "statusCode" => $statusCode, + "content" => $responseData, + ]); - throw new UsetrenoQRCodeException("Return code is not 200 OK (got: code: $statusCode)"); + if ($statusCode > 500) { + throw new UsetrenoQRCodeRemoteServerErrorException("Return code is not 200 OK (got: code: $statusCode)"); + } + + throw new UsetrenoQRCodeException("Return code is not 200 OK (got: code: $statusCode)"); + } + + $this->logger->debug("QRCode generation success", [ + "responseContent" => $responseData, + ]); + + return $responseData; + }); + + if (!is_string($responseData)) { + throw new ThisShouldNeverHappenException("responseData is not a string"); } - - $this->logger->debug("QRCode generation success", [ - "responseContent" => $responseData, - ]); - + return $this->parseBase64String($this->processQRCodeResponseEntity($responseData)); } diff --git a/tests/Service/Remote/UsetrenoHttpClientTest.php b/tests/Service/Remote/UsetrenoHttpClientTest.php index 92d7ef8..af7845d 100644 --- a/tests/Service/Remote/UsetrenoHttpClientTest.php +++ b/tests/Service/Remote/UsetrenoHttpClientTest.php @@ -24,7 +24,7 @@ class UsetrenoHttpClientTest extends TestCase ]); $authorizedRequestResponse = clone $authMockResponse; $mockedClient = new MockHttpClient([$authMockResponse, $authorizedRequestResponse]); - $client = new UsetrenoHttpClient($mockedClient, $this->getLogger(), "foo", "bar"); + $client = new UsetrenoHttpClient($mockedClient, $this->getLogger(), "foo", "bar", 0, 0); $client->request("POST", "https://www.root.cz/"); $this->assertEquals("https://topapi.top-test.cz/chameleon/api/v1/token", $authMockResponse->getRequestUrl()); $headers = $authorizedRequestResponse->getRequestOptions()['headers']; @@ -48,7 +48,7 @@ class UsetrenoHttpClientTest extends TestCase $authorizedRequestResponse = clone $authMockResponse; $mockedClient = new MockHttpClient([$authMockResponse, $authorizedRequestResponse]); - $client = new UsetrenoHttpClient($mockedClient, $this->getLogger(), "foo", "bar"); + $client = new UsetrenoHttpClient($mockedClient, $this->getLogger(), "foo", "bar", 0, 0); $client->request("POST", "https://www.root.cz/"); } } diff --git a/tests/Service/Remote/UsetrenoQRCodeProviderTest.php b/tests/Service/Remote/UsetrenoQRCodeProviderTest.php index dd7e602..d5d7e12 100644 --- a/tests/Service/Remote/UsetrenoQRCodeProviderTest.php +++ b/tests/Service/Remote/UsetrenoQRCodeProviderTest.php @@ -75,7 +75,7 @@ class UsetrenoQRCodeProviderTest extends TestCase ->method('convert') ->will($this->returnValue($edgeEntity)); - return new UsetrenoQRCodeProvider($this->getLogger(), $mock, $converterMock); + return new UsetrenoQRCodeProvider($this->getLogger(), $mock, $converterMock, 0, 0); } protected function createQRCodeEntityPair() {