rosetta_translation-1.0.0-alpha1/src/Service/RosettaVersionManager.php
src/Service/RosettaVersionManager.php
<?php
declare(strict_types=1);
namespace Drupal\rosetta_translation\Service;
use Drupal\Core\Cache\CacheBackendInterface;
use GuzzleHttp\ClientInterface;
use Psr\Log\LoggerInterface;
/**
* Fetches and provides Rosetta release tags from GitHub.
*/
final class RosettaVersionManager {
private const CACHE_ID = 'rosetta_translation:github_tags';
private const CACHE_TTL = 3600; // 1 hour.
public function __construct(
private readonly ClientInterface $httpClient,
private readonly CacheBackendInterface $cache,
private readonly LoggerInterface $logger,
) {}
/**
* Return releases (tags) sorted desc by semantic version if possible.
*
* @return string[]
* List of tag names, newest first.
*/
public function getTags(): array {
if ($cache = $this->cache->get(self::CACHE_ID)) {
return is_array($cache->data) ? $cache->data : [];
}
try {
$response = $this->httpClient->request('GET', 'https://api.github.com/repos/au5ton/rosetta/tags', [
'headers' => [
'Accept' => 'application/vnd.github+json',
'User-Agent' => 'rosetta-translation-module',
],
'timeout' => 5,
]);
$data = json_decode((string) $response->getBody(), TRUE) ?: [];
$tags = array_values(array_filter(array_map(static fn ($i) => $i['name'] ?? NULL, $data)));
// Sort semver-desc if possible.
usort($tags, static function (string $a, string $b): int {
$normalize = static fn (string $v) => array_map('intval', explode('.', ltrim($v, 'v')));
$aa = $normalize($a);
$bb = $normalize($b);
for ($i = 0; $i < 3; $i++) {
$ai = $aa[$i] ?? 0; $bi = $bb[$i] ?? 0;
if ($ai === $bi) { continue; }
return $bi <=> $ai;
}
return 0;
});
$this->cache->set(self::CACHE_ID, $tags, time() + self::CACHE_TTL);
return $tags;
}
catch (\Throwable $e) {
$this->logger->warning('Failed fetching Rosetta tags: @message', ['@message' => $e->getMessage()]);
return [];
}
}
/**
* Resolve a configured version to a concrete tag.
*/
public function resolveVersion(string $configured): ?string {
$configured = trim($configured);
if ($configured === '' || strtolower($configured) === 'latest') {
$tags = $this->getTags();
return $tags[0] ?? NULL;
}
return $configured;
}
/**
* Build a raw GitHub content URL for the dist file at a given tag.
*/
public function buildDistUrl(string $tag): string {
// Prefer jsDelivr GitHub CDN to ensure proper JS content-type and caching.
$tag = ltrim($tag, 'v');
return "https://cdn.jsdelivr.net/gh/au5ton/rosetta@{$tag}/dist/index.js";
}
}
