120 lines
4.5 KiB
PHP
120 lines
4.5 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Service\Remote;
|
|
|
|
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 float $retryWaitSeconds,
|
|
protected readonly int $retryCount) { }
|
|
|
|
public function generateQRCodeFromEntity(QRCode $entity): string
|
|
{
|
|
$edgeEntity = $this->codeEntityConverter->convert($entity);
|
|
|
|
$this->logger->debug("Sending request for QR code", [
|
|
"entity" => $entity,
|
|
"edgeEntity" => $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);
|
|
|
|
if ($statusCode != 200) {
|
|
$this->logger->error("qrcode request status code is not ok", [
|
|
"AUTHORIZE_API" => static::QRCODE_API,
|
|
"statusCode" => $statusCode,
|
|
"content" => $responseData,
|
|
]);
|
|
|
|
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");
|
|
}
|
|
|
|
return $this->parseBase64String($this->processQRCodeResponseEntity($responseData));
|
|
}
|
|
|
|
protected function parseBase64String(string $content): string {
|
|
$data = explode(';base64,', $content);
|
|
// check if response is image (we support png only now)
|
|
if ($data[0] === "image/png") {
|
|
throw new UsetrenoQRCodeException("Unsupported image type $data[0]");
|
|
}
|
|
|
|
return $data[1];
|
|
}
|
|
|
|
/**
|
|
* @param string $responseData
|
|
* @return string Bearer token
|
|
* @throws UsetrenoQRCodeException
|
|
*/
|
|
protected function processQRCodeResponseEntity(string $responseData): string {
|
|
$data = json_decode($responseData);
|
|
|
|
if (!is_object($data)) {
|
|
$this->logger->error("qrcode: received null response data", [
|
|
"responseData" => $responseData
|
|
]);
|
|
throw new UsetrenoQRCodeException("Can't decode json response");
|
|
}
|
|
|
|
if (!isset($data->data->base64Data)) {
|
|
$this->logger->error("qrcode: empty base64Data in response data", [
|
|
"responseData" => $responseData
|
|
]);
|
|
throw new UsetrenoQRCodeException("Got invalid json response");
|
|
}
|
|
|
|
return $data->data->base64Data;
|
|
}
|
|
|
|
public function getCacheKey(QRCode $entity): string
|
|
{
|
|
$edgeEntity = $this->codeEntityConverter->convert($entity);
|
|
$encodedEntity = json_encode($edgeEntity);
|
|
if ($encodedEntity === false) {
|
|
throw new \RuntimeException("Can't serialize edge entity");
|
|
}
|
|
return base64_encode($encodedEntity);
|
|
}
|
|
}
|