diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index f1b063817c..3b7449ea00 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -120,12 +120,18 @@ public function checkAndEnableCODEServer() {
$appConfig->setAppValue('wopi_url', $new_wopi_url);
$appConfig->setAppValue('disable_certificate_verification', 'yes');
+ /** @var DiscoveryService $discoveryService */
$discoveryService = $this->getContainer()->get(DiscoveryService::class);
+ /** @var CapabilitiesService $capabilitiesService */
$capabilitiesService = $this->getContainer()->get(CapabilitiesService::class);
$discoveryService->resetCache();
$capabilitiesService->resetCache();
- $capabilitiesService->fetchFromRemote();
+ try {
+ $capabilitiesService->fetch();
+ $discoveryService->fetch();
+ } catch (\Exception $e) {
+ }
}
}
}
diff --git a/lib/Backgroundjobs/ObtainCapabilities.php b/lib/Backgroundjobs/ObtainCapabilities.php
index ff62e75183..3156d77b93 100644
--- a/lib/Backgroundjobs/ObtainCapabilities.php
+++ b/lib/Backgroundjobs/ObtainCapabilities.php
@@ -7,21 +7,34 @@
namespace OCA\Richdocuments\Backgroundjobs;
use OCA\Richdocuments\Service\CapabilitiesService;
+use OCA\Richdocuments\Service\DiscoveryService;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
+use Psr\Log\LoggerInterface;
class ObtainCapabilities extends TimedJob {
- /** @var CapabilitiesService */
- private $capabilitiesService;
-
- public function __construct(ITimeFactory $time, CapabilitiesService $capabilitiesService) {
+ public function __construct(
+ ITimeFactory $time,
+ private LoggerInterface $logger,
+ private CapabilitiesService $capabilitiesService,
+ private DiscoveryService $discoveryService,
+ ) {
parent::__construct($time);
- $this->capabilitiesService = $capabilitiesService;
$this->setInterval(60 * 60);
}
protected function run($argument) {
- $this->capabilitiesService->fetchFromRemote();
+ try {
+ $this->capabilitiesService->fetch();
+ } catch (\Exception $e) {
+ $this->logger->error('Failed to fetch capabilities: ' . $e->getMessage(), ['exception' => $e]);
+ }
+
+ try {
+ $this->discoveryService->fetch();
+ } catch (\Exception $e) {
+ $this->logger->error('Failed to fetch discovery: ' . $e->getMessage(), ['exception' => $e]);
+ }
}
}
diff --git a/lib/Service/CachedRequestService.php b/lib/Service/CachedRequestService.php
new file mode 100644
index 0000000000..87f616d9cf
--- /dev/null
+++ b/lib/Service/CachedRequestService.php
@@ -0,0 +1,163 @@
+cacheFactory->createDistributed('richdocuments');
+
+ if ($cached = $cache->get($this->cacheKey)) {
+ return $cached;
+ }
+
+ $folder = $this->getAppDataFolder();
+ if ($folder->fileExists($this->cacheKey)) {
+ $value = $folder->getFile($this->cacheKey)->getContent();
+ $cache->set($this->cacheKey, $value, 3600);
+ return $value;
+ }
+
+ return null;
+ }
+
+ public function getLastUpdate(): ?int {
+ $folder = $this->getAppDataFolder();
+ if (!$folder->fileExists($this->cacheKey)) {
+ return null;
+ }
+ return $folder->getFile($this->cacheKey)->getMTime();
+ }
+
+ /**
+ * Cached value will be kept if the request fails
+ *
+ * @return string
+ * @throws \Exception
+ */
+ final public function fetch(): string {
+ $cache = $this->cacheFactory->createDistributed('richdocuments');
+ $client = $this->clientService->newClient();
+
+ $startTime = microtime(true);
+ $response = $this->sendRequest($client);
+ $duration = round(((microtime(true) - $startTime)), 3);
+ $this->logger->info('Fetched remote endpoint from ' . $this->cacheKey . ' in ' . $duration . ' seconds');
+
+ $this->getAppDataFolder()->newFile($this->cacheKey, $response);
+ $cache->set($this->cacheKey, $response);
+ return $response;
+ }
+
+ public function resetCache(): void {
+ $cache = $this->cacheFactory->createDistributed('richdocuments');
+ $cache->remove($this->cacheKey);
+ $folder = $this->getAppDataFolder();
+ if ($folder->fileExists($this->cacheKey)) {
+ $folder->getFile($this->cacheKey)->delete();
+ }
+ }
+
+ protected function getDefaultRequestOptions(): array {
+ $options = [
+ 'timeout' => 5,
+ 'nextcloud' => [
+ 'allow_local_address' => true
+ ]
+ ];
+
+ if ($this->appConfig->getValueString('richdocuments', 'disable_certificate_verification') === 'yes') {
+ $options['verify'] = false;
+ }
+
+ if ($this->isProxyStarting()) {
+ $options['timeout'] = 180;
+ }
+
+ return $options;
+ }
+
+ private function getAppDataFolder(): ISimpleFolder {
+ $appData = $this->appDataFactory->get(Application::APPNAME);
+ try {
+ $folder = $appData->getFolder('remoteData');
+ } catch (NotFoundException $e) {
+ $folder = $appData->newFolder('remoteData');
+ }
+ return $folder;
+ }
+
+ /**
+ * @return boolean indicating if proxy.php is in initialize or false otherwise
+ */
+ private function isProxyStarting(): bool {
+ $url = $this->appConfig->getValueString('richdocuments', 'wopi_url', '');
+ $usesProxy = false;
+ $proxyPos = strrpos($url, 'proxy.php');
+ if ($proxyPos !== false) {
+ $usesProxy = true;
+ }
+
+ if ($usesProxy === true) {
+ $statusUrl = substr($url, 0, $proxyPos);
+ $statusUrl = $statusUrl . 'proxy.php?status';
+
+ $client = $this->clientService->newClient();
+ $options = ['timeout' => 5, 'nextcloud' => ['allow_local_address' => true]];
+
+ if ($this->appConfig->getValueString('richdocuments', 'disable_certificate_verification') === 'yes') {
+ $options['verify'] = false;
+ }
+
+ try {
+ $response = $client->get($statusUrl, $options);
+
+ if ($response->getStatusCode() === 200) {
+ $body = json_decode($response->getBody(), true);
+
+ if ($body['status'] === 'starting'
+ || $body['status'] === 'stopped'
+ || $body['status'] === 'restarting') {
+ return true;
+ }
+ }
+ } catch (\Exception $e) {
+ // ignore
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/lib/Service/CapabilitiesService.php b/lib/Service/CapabilitiesService.php
index 1bf4652733..f61cf0f0c4 100644
--- a/lib/Service/CapabilitiesService.php
+++ b/lib/Service/CapabilitiesService.php
@@ -8,52 +8,42 @@
use OCA\Richdocuments\AppInfo\Application;
use OCP\App\IAppManager;
+use OCP\Files\AppData\IAppDataFactory;
+use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
-use OCP\ICache;
+use OCP\IAppConfig;
use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\IL10N;
use Psr\Log\LoggerInterface;
-class CapabilitiesService {
- /** @var IConfig */
- private $config;
- /** @var IClientService */
- private $clientService;
- /** @var ICache */
- private $cache;
- /** @var IAppManager */
- private $appManager;
- /** @var IL10N */
- private $l10n;
- /** @var LoggerInterface */
- private $logger;
-
- /** @var array */
- private $capabilities;
-
-
- public function __construct(IConfig $config, IClientService $clientService, ICacheFactory $cacheFactory, IAppManager $appManager, IL10N $l10n, LoggerInterface $logger) {
- $this->config = $config;
- $this->clientService = $clientService;
- $this->cache = $cacheFactory->createDistributed('richdocuments');
- $this->appManager = $appManager;
- $this->l10n = $l10n;
- $this->logger = $logger;
+class CapabilitiesService extends CachedRequestService {
+
+ private ?array $capabilities = null;
+
+ public function __construct(
+ private IClientService $clientService,
+ private ICacheFactory $cacheFactory,
+ private IAppDataFactory $appDataFactory,
+ private IAppConfig $appConfig,
+ private LoggerInterface $logger,
+ private IConfig $config,
+ private IAppManager $appManager,
+ private IL10N $l10n,
+ ) {
+ parent::__construct(
+ $this->clientService,
+ $this->cacheFactory,
+ $this->appDataFactory,
+ $this->appConfig,
+ $this->logger,
+ 'capabilities',
+ );
}
public function getCapabilities() {
if (!$this->capabilities) {
- $this->capabilities = $this->cache->get('capabilities');
- }
-
- $isARM64 = php_uname('m') === 'aarch64';
- $CODEAppID = $isARM64 ? 'richdocumentscode_arm64' : 'richdocumentscode';
- $isCODEInstalled = $this->appManager->isEnabledForUser($CODEAppID);
- $isCODEEnabled = strpos($this->config->getAppValue('richdocuments', 'wopi_url'), 'proxy.php?req=') !== false;
- $shouldRecheckCODECapabilities = $isCODEInstalled && $isCODEEnabled && ($this->capabilities === null || count($this->capabilities) === 0);
- if ($this->capabilities === null || $shouldRecheckCODECapabilities) {
- $this->fetchFromRemote();
+ $this->capabilities = $this->getParsedCapabilities();
}
if (!is_array($this->capabilities)) {
@@ -119,10 +109,6 @@ public function hasOtherOOXMLApps(): bool {
return false;
}
- public function resetCache(): void {
- $this->cache->remove('capabilities');
- }
-
public function getCapabilitiesEndpoint(): ?string {
$remoteHost = $this->config->getAppValue('richdocuments', 'wopi_url');
if ($remoteHost === '') {
@@ -131,43 +117,13 @@ public function getCapabilitiesEndpoint(): ?string {
return rtrim($remoteHost, '/') . '/hosting/capabilities';
}
- public function fetchFromRemote($throw = false): void {
- if (!$this->getCapabilitiesEndpoint()) {
- return;
- }
-
- $client = $this->clientService->newClient();
- $options = ['timeout' => 45, 'nextcloud' => ['allow_local_address' => true]];
-
- if ($this->config->getAppValue('richdocuments', 'disable_certificate_verification') === 'yes') {
- $options['verify'] = false;
- }
-
- try {
- $startTime = microtime(true);
- $response = $client->get($this->getCapabilitiesEndpoint(), $options);
- $duration = round(((microtime(true) - $startTime)), 3);
- $this->logger->info('Fetched capabilities endpoint from ' . $this->getCapabilitiesEndpoint(). ' in ' . $duration . ' seconds');
- $responseBody = $response->getBody();
- $capabilities = \json_decode($responseBody, true);
-
- if (!is_array($capabilities)) {
- $capabilities = [];
- }
- } catch (\Exception $e) {
- $this->logger->error('Failed to fetch the Collabora capabilities endpoint: ' . $e->getMessage(), [ 'exception' => $e ]);
- if ($throw) {
- throw $e;
- }
- $capabilities = [];
- }
-
- $this->capabilities = $capabilities;
- $ttl = 3600;
- if (count($capabilities) === 0) {
- $ttl = 60;
- }
+ protected function sendRequest(IClient $client): string {
+ $response = $client->get($this->getCapabilitiesEndpoint(), $this->getDefaultRequestOptions());
+ return (string)$response->getBody();
+ }
- $this->cache->set('capabilities', $capabilities, $ttl);
+ private function getParsedCapabilities() {
+ $response = $this->get();
+ return json_decode($response, true);
}
}
diff --git a/lib/Service/ConnectivityService.php b/lib/Service/ConnectivityService.php
index 8e687593fe..113c7dfff6 100644
--- a/lib/Service/ConnectivityService.php
+++ b/lib/Service/ConnectivityService.php
@@ -25,7 +25,7 @@ public function __construct(
*/
public function testDiscovery(OutputInterface $output): void {
$this->discoveryService->resetCache();
- $this->discoveryService->fetchFromRemote();
+ $this->discoveryService->fetch();
$output->writeln('✓ Fetched /hosting/discovery endpoint');
$this->parser->getUrlSrcValue('application/vnd.openxmlformats-officedocument.wordprocessingml.document');
@@ -38,7 +38,7 @@ public function testDiscovery(OutputInterface $output): void {
public function testCapabilities(OutputInterface $output): void {
$this->capabilitiesService->resetCache();
- $this->capabilitiesService->fetchFromRemote(true);
+ $this->capabilitiesService->fetch(true);
$output->writeln('✓ Fetched /hosting/capabilities endpoint');
if ($this->capabilitiesService->getCapabilities() === []) {
diff --git a/lib/Service/DiscoveryService.php b/lib/Service/DiscoveryService.php
index 3d85055ecf..7cd10be775 100644
--- a/lib/Service/DiscoveryService.php
+++ b/lib/Service/DiscoveryService.php
@@ -28,120 +28,41 @@
namespace OCA\Richdocuments\Service;
+use OCP\Files\AppData\IAppDataFactory;
+use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
-use OCP\Http\Client\IResponse;
-use OCP\ICache;
+use OCP\IAppConfig;
use OCP\ICacheFactory;
use OCP\IConfig;
use Psr\Log\LoggerInterface;
-class DiscoveryService {
- private IClientService $clientService;
- private ICache $cache;
- private IConfig $config;
- private LoggerInterface $logger;
-
- private ?string $discovery = null;
-
+class DiscoveryService extends CachedRequestService {
public function __construct(
- IClientService $clientService,
- ICacheFactory $cacheFactory,
- IConfig $config,
- LoggerInterface $logger
+ private IClientService $clientService,
+ private ICacheFactory $cacheFactory,
+ private IAppDataFactory $appDataFactory,
+ private IAppConfig $appConfig,
+ private LoggerInterface $logger,
+ private IConfig $config,
) {
- $this->clientService = $clientService;
- $this->cache = $cacheFactory->createDistributed('richdocuments');
- $this->config = $config;
- $this->logger = $logger;
+ parent::__construct(
+ $this->clientService,
+ $this->cacheFactory,
+ $this->appDataFactory,
+ $this->appConfig,
+ $this->logger,
+ 'discovery',
+ );
}
- public function get(): ?string {
- if ($this->discovery) {
- return $this->discovery;
- }
-
- $this->discovery = $this->cache->get('discovery');
- if (!$this->discovery) {
- $response = $this->fetchFromRemote();
- $responseBody = $response->getBody();
- $this->discovery = $responseBody;
- $this->cache->set('discovery', $this->discovery, 3600);
- }
-
- return $this->discovery;
+ protected function sendRequest(IClient $client): string {
+ $response = $client->get($this->getDiscoveryEndpoint(), $this->getDefaultRequestOptions());
+ return (string)$response->getBody();
}
- /**
- * @throws \Exception if a network error occurs
- */
- public function fetchFromRemote(): IResponse {
+ private function getDiscoveryEndpoint(): string {
$remoteHost = $this->config->getAppValue('richdocuments', 'wopi_url');
- $wopiDiscovery = rtrim($remoteHost, '/') . '/hosting/discovery';
-
- $client = $this->clientService->newClient();
- $options = ['timeout' => 45, 'nextcloud' => ['allow_local_address' => true]];
-
- if ($this->config->getAppValue('richdocuments', 'disable_certificate_verification') === 'yes') {
- $options['verify'] = false;
- }
-
- if ($this->isProxyStarting($wopiDiscovery)) {
- $options['timeout'] = 180;
- }
-
- $startTime = microtime(true);
- $response = $client->get($wopiDiscovery, $options);
- $duration = round(((microtime(true) - $startTime)), 3);
- $this->logger->info('Fetched discovery endpoint from ' . $wopiDiscovery . ' in ' . $duration . ' seconds');
-
- return $response;
- }
-
- public function resetCache(): void {
- $this->cache->remove('discovery');
- $this->discovery = null;
- }
-
- /**
- * @return boolean indicating if proxy.php is in initialize or false otherwise
- */
- private function isProxyStarting(string $url): bool {
- $usesProxy = false;
- $proxyPos = strrpos($url, 'proxy.php');
- if ($proxyPos === false) {
- $usesProxy = false;
- } else {
- $usesProxy = true;
- }
-
- if ($usesProxy === true) {
- $statusUrl = substr($url, 0, $proxyPos);
- $statusUrl = $statusUrl . 'proxy.php?status';
-
- $client = $this->clientService->newClient();
- $options = ['timeout' => 5, 'nextcloud' => ['allow_local_address' => true]];
-
- if ($this->config->getAppValue('richdocuments', 'disable_certificate_verification') === 'yes') {
- $options['verify'] = false;
- }
-
- try {
- $response = $client->get($statusUrl, $options);
-
- if ($response->getStatusCode() === 200) {
- $body = json_decode($response->getBody(), true);
-
- if ($body['status'] === 'starting'
- || $body['status'] === 'stopped'
- || $body['status'] === 'restarting') {
- return true;
- }
- }
- } catch (\Exception $e) {
- // ignore
- }
- }
+ return rtrim($remoteHost, '/') . '/hosting/discovery';
- return false;
}
}