Introduced new Data Transfer Objects (DTOs), exceptions, and jobs to enhance the translation service functionality. Updated namespaces for consistency and added rate limiting to the translation provider. Expanded the README with detailed usage instructions.
113 lines
3.3 KiB
PHP
113 lines
3.3 KiB
PHP
<?php declare(strict_types=1);
|
|
|
|
namespace KorElf\TranslateLaravel\Translate\Yandex;
|
|
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Carbon;
|
|
use Jose\Component\Core\AlgorithmManager;
|
|
use Jose\Component\KeyManagement\JWKFactory;
|
|
use Jose\Component\Signature\Algorithm\PS256;
|
|
use Jose\Component\Signature\JWSBuilder;
|
|
use Jose\Component\Signature\Serializer\CompactSerializer;
|
|
use KorElf\TranslateLaravel\Exceptions\TranslateException;
|
|
|
|
final class Connection
|
|
{
|
|
private string $path;
|
|
private string $folderId;
|
|
private string $privateKey;
|
|
private string $keyId;
|
|
private string $serviceAccountId;
|
|
|
|
public function __construct(string $path, string $folderId, string $privateKey, string $keyId, string $serviceAccountId)
|
|
{
|
|
$this->path = $path;
|
|
$this->folderId = $folderId;
|
|
|
|
// Need to remove header/metadata from private key
|
|
if (\strpos($privateKey, "PLEASE DO NOT REMOVE THIS LINE!") === 0) {
|
|
$privateKey = \substr($privateKey, \strpos($privateKey, "\n") + 1);
|
|
}
|
|
$this->privateKey = $privateKey;
|
|
|
|
$this->keyId = $keyId;
|
|
$this->serviceAccountId = $serviceAccountId;
|
|
}
|
|
|
|
public function post(string $path, array $post): array
|
|
{
|
|
$token = $this->getToken();
|
|
$path = $this->path . $path;
|
|
$post['folderId'] = $this->folderId;
|
|
|
|
$response = Http::withToken($token)
|
|
->timeout(30)
|
|
->post($path, $post);
|
|
|
|
$data = $response->json();
|
|
|
|
if ($data !== null && $response->status() === 200) {
|
|
return $data;
|
|
}
|
|
$message = $data['message'] ?? 'Error in request';
|
|
|
|
throw new TranslateException($message, $response->status());
|
|
}
|
|
|
|
private function getToken(): string
|
|
{
|
|
$cacheName = self::class . '_token';
|
|
$token = Cache::get($cacheName);
|
|
if ($token !== null) {
|
|
return $token;
|
|
}
|
|
|
|
$token = $this->createNewToken();
|
|
Cache::put($cacheName, $token['iamToken'], Carbon::createFromDate($token['expiresAt']));
|
|
|
|
return $token['iamToken'];
|
|
}
|
|
|
|
private function getJWTToken(): string
|
|
{
|
|
$jwk = JWKFactory::createFromKey(
|
|
$this->privateKey,
|
|
null,
|
|
[
|
|
'alg' => 'PS256',
|
|
'use' => 'sig',
|
|
'kid' => $this->keyId,
|
|
]
|
|
);
|
|
|
|
$algorithmManager = new AlgorithmManager([new PS256()]);
|
|
$jwsBuilder = new JWSBuilder($algorithmManager);
|
|
|
|
$payload = \json_encode([
|
|
'iss' => $this->serviceAccountId,
|
|
'aud' => "https://iam.api.cloud.yandex.net/iam/v1/tokens",
|
|
'iat' => time(),
|
|
'nbf' => time(),
|
|
'exp' => time() + 600,
|
|
]);
|
|
|
|
$jws = $jwsBuilder
|
|
->create()
|
|
->withPayload($payload)
|
|
->addSignature($jwk, ['alg' => 'PS256', 'typ'=>'JWT', 'kid' => $this->keyId])
|
|
->build();
|
|
|
|
$serializer = new CompactSerializer();
|
|
return $serializer->serialize($jws, 0);
|
|
}
|
|
|
|
private function createNewToken(): array
|
|
{
|
|
$jwtToken = $this->getJWTToken();
|
|
$token = Http::timeout(30)
|
|
->post('https://iam.api.cloud.yandex.net/iam/v1/tokens', ['jwt' => $jwtToken]);
|
|
|
|
return $token->json();
|
|
}
|
|
} |