Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
23.64% covered (danger)
23.64%
13 / 55
20.00% covered (danger)
20.00%
1 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
InstallProgressStore
23.64% covered (danger)
23.64%
13 / 55
20.00% covered (danger)
20.00%
1 / 5
280.50
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get
23.53% covered (danger)
23.53%
4 / 17
0.00% covered (danger)
0.00%
0 / 1
36.62
 set
33.33% covered (danger)
33.33%
4 / 12
0.00% covered (danger)
0.00%
0 / 1
12.41
 remove
21.05% covered (danger)
21.05%
4 / 19
0.00% covered (danger)
0.00%
0 / 1
31.11
 getFallbackFile
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\Install;
10
11use OC\Memcache\NullCache;
12use OCA\Libresign\AppInfo\Application;
13use OCP\Files\NotFoundException;
14use OCP\Files\SimpleFS\ISimpleFile;
15use OCP\ICache;
16use OCP\ICacheFactory;
17use Psr\Log\LoggerInterface;
18
19class InstallProgressStore {
20    private ICache $cache;
21
22    public function __construct(
23        ICacheFactory $cacheFactory,
24        private DependencyStorage $dependencyStorage,
25        private LoggerInterface $logger,
26    ) {
27        $this->cache = $cacheFactory->createDistributed('libresign-setup');
28    }
29
30    public function get(InstallTarget $target, string $resource): array {
31        $key = $target->cacheKey($resource);
32        if (!$this->cache instanceof NullCache) {
33            $value = $this->cache->get(Application::APP_ID . '-asyncDownloadProgress-' . $key);
34            return is_array($value) ? $value : [];
35        }
36
37        $file = $this->getFallbackFile($target, false);
38        if ($file === null) {
39            return [];
40        }
41
42        try {
43            $content = $file->getContent();
44            $json = $content !== '' ? json_decode($content, true) : [];
45            $value = is_array($json) ? ($json[$key] ?? []) : [];
46            return is_array($value) ? $value : [];
47        } catch (\Exception $e) {
48            $this->logger->error('Could not read installer progress fallback', [
49                'app' => Application::APP_ID,
50                'exception' => $e,
51            ]);
52            return [];
53        }
54    }
55
56    public function set(InstallTarget $target, string $resource, array $value): void {
57        $key = $target->cacheKey($resource);
58        if (!$this->cache instanceof NullCache) {
59            $this->cache->set(Application::APP_ID . '-asyncDownloadProgress-' . $key, $value);
60            return;
61        }
62
63        $file = $this->getFallbackFile($target, true);
64        if ($file === null) {
65            return;
66        }
67        $content = $file->getContent();
68        $json = $content !== '' ? json_decode($content, true) : [];
69        $json = is_array($json) ? $json : [];
70        $json[$key] = $value;
71        $file->putContent(json_encode($json));
72    }
73
74    public function remove(InstallTarget $target, string $resource): void {
75        $key = $target->cacheKey($resource);
76        if (!$this->cache instanceof NullCache) {
77            $this->cache->remove(Application::APP_ID . '-asyncDownloadProgress-' . $key);
78            return;
79        }
80
81        $file = $this->getFallbackFile($target, false);
82        if ($file === null) {
83            return;
84        }
85
86        try {
87            $content = $file->getContent();
88            $json = $content !== '' ? json_decode($content, true) : [];
89            $json = is_array($json) ? $json : [];
90            unset($json[$key]);
91            if ($json === []) {
92                $file->delete();
93            } else {
94                $file->putContent(json_encode($json));
95            }
96        } catch (\Exception $e) {
97            $this->logger->warning('Could not update installer progress fallback', [
98                'app' => Application::APP_ID,
99                'exception' => $e,
100            ]);
101        }
102    }
103
104    private function getFallbackFile(InstallTarget $target, bool $create): ?ISimpleFile {
105        $folder = $this->dependencyStorage->resourceFolder($target);
106        try {
107            return $folder->getFile('setup-cache.json');
108        } catch (NotFoundException) {
109            if (!$create) {
110                return null;
111            }
112            return $folder->newFile('setup-cache.json', '[]');
113        }
114    }
115}