From af1caafafc14e465c2b3280dec9eb3a49251a0a9 Mon Sep 17 00:00:00 2001 From: Benjamin Klotz Date: Tue, 30 Dec 2025 16:49:25 +0100 Subject: [PATCH 1/2] #697 Setup check for the HaRP container's version Signed-off-by: Benjamin Klotz --- lib/AppInfo/Application.php | 3 + lib/Service/HarpService.php | 28 ++++++++ lib/SetupChecks/HarpVersionCheck.php | 103 +++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 lib/SetupChecks/HarpVersionCheck.php diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 8782c2ca..570dc302 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -24,6 +24,7 @@ use OCA\AppAPI\Notifications\ExAppNotifier; use OCA\AppAPI\PublicCapabilities; use OCA\AppAPI\SetupChecks\DaemonCheck; +use OCA\AppAPI\SetupChecks\HarpVersionCheck; use OCA\DAV\Events\SabrePluginAddEvent; use OCA\DAV\Events\SabrePluginAuthInitEvent; use OCA\Files\Event\LoadAdditionalScriptsEvent; @@ -42,6 +43,7 @@ class Application extends App implements IBootstrap { public const APP_ID = 'app_api'; public const TEST_DEPLOY_APPID = 'test-deploy'; public const TEST_DEPLOY_INFO_XML = 'https://raw.githubusercontent.com/nextcloud/test-deploy/main/appinfo/info.xml'; + public const MINIMUM_HARP_VERSION = '0.3'; public function __construct(array $urlParams = []) { parent::__construct(self::APP_ID, $urlParams); @@ -69,6 +71,7 @@ public function register(IRegistrationContext $context): void { $context->registerEventListener(DeclarativeSettingsSetValueEvent::class, SetValueListener::class); $context->registerSetupCheck(DaemonCheck::class); + $context->registerSetupCheck(HarpVersionCheck::class); } public function boot(IBootContext $context): void { diff --git a/lib/Service/HarpService.php b/lib/Service/HarpService.php index 1e5fc753..a282ff7b 100644 --- a/lib/Service/HarpService.php +++ b/lib/Service/HarpService.php @@ -157,4 +157,32 @@ public function harpExAppUpdate(DaemonConfig $daemonConfig, ExApp $exApp, bool $ $this->logger->error("HarpService: harpExAppUpdate ($addedStr) failed: " . $e->getMessage()); } } + + public function getHarpVersion(DaemonConfig $daemonConfig): ?string { + if (!self::isHarp($daemonConfig->getDeployConfig())) { + return null; + } + $this->initGuzzleClient($daemonConfig); + $url = $this->buildHarpUrl($daemonConfig, '/info'); + $this->logger->info("HarpService: getHarpVersion: " . $url); + + try { + $response = $this->guzzleClient->get($url); + $data = json_decode($response->getBody()->getContents(), true); + if (isset($data['version'])) { + if (gettype($data['version']) === 'double') { + // Locale-independent float to string conversion + return rtrim(number_format($data['version'], 10, '.', ''), '0'); + } + return (string) $data['version']; + } + return null; + } catch (ClientException $e) { + $this->logger->error("HarpService: getHarpVersion failed: " . $e->getMessage()); + return null; + } catch (\Exception $e) { + $this->logger->error("HarpService: getHarpVersion failed: " . $e->getMessage()); + return null; + } + } } diff --git a/lib/SetupChecks/HarpVersionCheck.php b/lib/SetupChecks/HarpVersionCheck.php new file mode 100644 index 00000000..c8fb29d5 --- /dev/null +++ b/lib/SetupChecks/HarpVersionCheck.php @@ -0,0 +1,103 @@ +isAvailable()) { + $this->cache = $cacheFactory->createDistributed(Application::APP_ID . '/harp_version_check'); + } + } + + public function getName(): string { + return $this->l10n->t('AppAPI HaRP version check'); + } + + public function getCategory(): string { + return 'system'; + } + + /** + * @return DaemonConfig[] + */ + public function getHaRPDaemonConfigs(): array { + $allDaemons = $this->daemonConfigService->getRegisteredDaemonConfigs(); + return array_filter($allDaemons, function (DaemonConfig $daemon) { + return HarpService::isHarp($daemon->getDeployConfig()); + }); + } + + public function run(): SetupResult { + $harpDaemons = $this->getHaRPDaemonConfigs(); + + if (empty($harpDaemons)) { + return SetupResult::success(); + } + + $issues = []; + foreach ($harpDaemons as $daemonConfig) { + try { + $versionString = $this->getHarpVersion($daemonConfig); + if ($versionString === null) { + $issues[] = $this->l10n->t('Could not retrieve HaRP version from daemon "%s"', [$daemonConfig->getName()]); + continue; + } + if (!$this->fulfillsMinimumVersionRequirement($versionString)) { + $issues[] = $this->l10n->t('HaRP version for daemon "%s" is "%s", which is too old. The minimum required version is "%s". Please update the daemon to the latest version. ', [$daemonConfig->getName(), $versionString, Application::MINIMUM_HARP_VERSION]); + } + } catch (\Exception $e) { + $this->logger->error('Failed to check HaRP version for daemon ' . $daemonConfig->getName() . ': ' . $e->getMessage(), ['exception' => $e]); + $issues[] = $this->l10n->t('Failed to check HaRP version for daemon "%s": %s', [$daemonConfig->getName(), $e->getMessage()]); + } + } + + if (!empty($issues)) { + return SetupResult::warning( + implode("\n", $issues), + "https://github.com/nextcloud/HaRP/", + ); + } + + return SetupResult::success(); + } + + private function fulfillsMinimumVersionRequirement(string $version): bool { + return version_compare($version, Application::MINIMUM_HARP_VERSION, ">="); + } + + private function getHarpVersion(DaemonConfig $daemonConfig): ?string { + $cacheKey = $daemonConfig->getName() . "_" . crc32(json_encode($daemonConfig)); + $version = $this->cache->get($cacheKey); + if ($version === null) { + $version = $this->harpService->getHarpVersion($daemonConfig); + $oneWeek = 60 * 60 * 24 * 7; + $this->cache->set($cacheKey, $version, $oneWeek); + } + return $version; + } +} From ab1224793b3e4b9f60eddc892110634a7b03ecee Mon Sep 17 00:00:00 2001 From: Benjamin Klotz Date: Tue, 30 Dec 2025 23:49:01 +0100 Subject: [PATCH 2/2] #697 Fix psalm errors Signed-off-by: Benjamin Klotz --- lib/Service/HarpService.php | 3 --- lib/SetupChecks/HarpVersionCheck.php | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/Service/HarpService.php b/lib/Service/HarpService.php index a282ff7b..2627e1a7 100644 --- a/lib/Service/HarpService.php +++ b/lib/Service/HarpService.php @@ -177,9 +177,6 @@ public function getHarpVersion(DaemonConfig $daemonConfig): ?string { return (string) $data['version']; } return null; - } catch (ClientException $e) { - $this->logger->error("HarpService: getHarpVersion failed: " . $e->getMessage()); - return null; } catch (\Exception $e) { $this->logger->error("HarpService: getHarpVersion failed: " . $e->getMessage()); return null; diff --git a/lib/SetupChecks/HarpVersionCheck.php b/lib/SetupChecks/HarpVersionCheck.php index c8fb29d5..95c0e4a7 100644 --- a/lib/SetupChecks/HarpVersionCheck.php +++ b/lib/SetupChecks/HarpVersionCheck.php @@ -91,7 +91,7 @@ private function fulfillsMinimumVersionRequirement(string $version): bool { } private function getHarpVersion(DaemonConfig $daemonConfig): ?string { - $cacheKey = $daemonConfig->getName() . "_" . crc32(json_encode($daemonConfig)); + $cacheKey = $daemonConfig->getName() . "_" . (string)crc32(json_encode($daemonConfig)); $version = $this->cache->get($cacheKey); if ($version === null) { $version = $this->harpService->getHarpVersion($daemonConfig);