Skip to content

Commit 2071b8a

Browse files
committed
feat: allow object store configuration aliases for easier migrations
Signed-off-by: Robin Appelman <[email protected]>
1 parent 832c77a commit 2071b8a

File tree

5 files changed

+377
-23
lines changed

5 files changed

+377
-23
lines changed

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,6 +1644,7 @@
16441644
'OC\\Files\\ObjectStore\\AppdataPreviewObjectStoreStorage' => $baseDir . '/lib/private/Files/ObjectStore/AppdataPreviewObjectStoreStorage.php',
16451645
'OC\\Files\\ObjectStore\\Azure' => $baseDir . '/lib/private/Files/ObjectStore/Azure.php',
16461646
'OC\\Files\\ObjectStore\\HomeObjectStoreStorage' => $baseDir . '/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php',
1647+
'OC\\Files\\ObjectStore\\InvalidObjectStoreConfigurationException' => $baseDir . '/lib/private/Files/ObjectStore/InvalidObjectStoreConfigurationException.php',
16471648
'OC\\Files\\ObjectStore\\IObjectStoreMetaData' => $baseDir . '/lib/private/Files/ObjectStore/IObjectStoreMetaData.php',
16481649
'OC\\Files\\ObjectStore\\Mapper' => $baseDir . '/lib/private/Files/ObjectStore/Mapper.php',
16491650
'OC\\Files\\ObjectStore\\ObjectStoreScanner' => $baseDir . '/lib/private/Files/ObjectStore/ObjectStoreScanner.php',

lib/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1693,6 +1693,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
16931693
'OC\\Files\\ObjectStore\\AppdataPreviewObjectStoreStorage' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/AppdataPreviewObjectStoreStorage.php',
16941694
'OC\\Files\\ObjectStore\\Azure' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/Azure.php',
16951695
'OC\\Files\\ObjectStore\\HomeObjectStoreStorage' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php',
1696+
'OC\\Files\\ObjectStore\\InvalidObjectStoreConfigurationException' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/InvalidObjectStoreConfigurationException.php',
16961697
'OC\\Files\\ObjectStore\\IObjectStoreMetaData' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/IObjectStoreMetaData.php',
16971698
'OC\\Files\\ObjectStore\\Mapper' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/Mapper.php',
16981699
'OC\\Files\\ObjectStore\\ObjectStoreScanner' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/ObjectStoreScanner.php',
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2025 Robin Appelman <[email protected]>
6+
* SPDX-License-Identifier: AGPL-3.0-or-later
7+
*/
8+
9+
namespace OC\Files\ObjectStore;
10+
11+
class InvalidObjectStoreConfigurationException extends \Exception {
12+
13+
}

lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,11 @@ public function buildObjectStore(array $config): IObjectStore {
3434
* @return ?ObjectStoreConfig
3535
*/
3636
public function getObjectStoreConfigForRoot(): ?array {
37-
$configs = $this->getObjectStoreConfig();
38-
if (!$configs) {
37+
if (!$this->hasObjectStore()) {
3938
return null;
4039
}
4140

42-
$config = $configs['root'] ?? $configs['default'];
41+
$config = $this->getObjectStoreConfiguration('root');
4342

4443
if ($config['arguments']['multibucket']) {
4544
if (!isset($config['arguments']['bucket'])) {
@@ -56,17 +55,12 @@ public function getObjectStoreConfigForRoot(): ?array {
5655
* @return ?ObjectStoreConfig
5756
*/
5857
public function getObjectStoreConfigForUser(IUser $user): ?array {
59-
$configs = $this->getObjectStoreConfig();
60-
if (!$configs) {
58+
if (!$this->hasObjectStore()) {
6159
return null;
6260
}
6361

6462
$store = $this->getObjectStoreForUser($user);
65-
66-
if (!isset($configs[$store])) {
67-
throw new \Exception("Object store configuration for '{$store}' not found");
68-
}
69-
$config = $configs[$store];
63+
$config = $this->getObjectStoreConfiguration($store);
7064

7165
if ($config['arguments']['multibucket']) {
7266
$config['arguments']['bucket'] = $this->getBucketForUser($user, $config);
@@ -75,55 +69,106 @@ public function getObjectStoreConfigForUser(IUser $user): ?array {
7569
}
7670

7771
/**
78-
* @return ?array<string, ObjectStoreConfig>
72+
* @param string $name
73+
* @return ObjectStoreConfig
74+
*/
75+
public function getObjectStoreConfiguration(string $name): array {
76+
$configs = $this->getObjectStoreConfigs();
77+
$name = $this->resolveAlias($name);
78+
if (!isset($configs[$name])) {
79+
throw new \Exception("Object store configuration for '$name' not found");
80+
}
81+
if (is_string($configs[$name])) {
82+
throw new \Exception("Object store configuration for '{$configs[$name]}' not found");
83+
}
84+
return $configs[$name];
85+
}
86+
87+
public function resolveAlias(string $name): string {
88+
$configs = $this->getObjectStoreConfigs();
89+
90+
while (isset($configs[$name]) && is_string($configs[$name])) {
91+
$name = $configs[$name];
92+
}
93+
return $name;
94+
}
95+
96+
public function hasObjectStore(): bool {
97+
$objectStore = $this->config->getSystemValue('objectstore', null);
98+
$objectStoreMultiBucket = $this->config->getSystemValue('objectstore_multibucket', null);
99+
return $objectStore || $objectStoreMultiBucket;
100+
}
101+
102+
public function hasMultipleObjectStorages(): bool {
103+
$objectStore = $this->config->getSystemValue('objectstore', []);
104+
return isset($objectStore['default']);
105+
}
106+
107+
/**
108+
* @return ?array<string, ObjectStoreConfig|string>
109+
* @throws InvalidObjectStoreConfigurationException
79110
*/
80-
private function getObjectStoreConfig(): ?array {
111+
public function getObjectStoreConfigs(): ?array {
81112
$objectStore = $this->config->getSystemValue('objectstore', null);
82113
$objectStoreMultiBucket = $this->config->getSystemValue('objectstore_multibucket', null);
83114

84115
// new-style multibucket config uses the same 'objectstore' key but sets `'multibucket' => true`, transparently upgrade older style config
85116
if ($objectStoreMultiBucket) {
86117
$objectStoreMultiBucket['arguments']['multibucket'] = true;
87118
return [
88-
'default' => $this->validateObjectStoreConfig($objectStoreMultiBucket)
119+
'default' => 'server1',
120+
'server1' => $this->validateObjectStoreConfig($objectStoreMultiBucket),
121+
'root' => 'server1',
89122
];
90123
} elseif ($objectStore) {
91124
if (!isset($objectStore['default'])) {
92125
$objectStore = [
93-
'default' => $objectStore,
126+
'default' => 'server1',
127+
'root' => 'server1',
128+
'server1' => $objectStore,
94129
];
95130
}
131+
if (!isset($objectStore['root'])) {
132+
$objectStore['root'] = 'default';
133+
}
96134

135+
if (!is_string($objectStore['default'])) {
136+
throw new InvalidObjectStoreConfigurationException('The \'default\' object storage configuration is required to be a reference to another configuration.');
137+
}
97138
return array_map($this->validateObjectStoreConfig(...), $objectStore);
98139
} else {
99140
return null;
100141
}
101142
}
102143

103144
/**
104-
* @return ObjectStoreConfig
145+
* @param array|string $config
146+
* @return string|ObjectStoreConfig
105147
*/
106-
private function validateObjectStoreConfig(array $config) {
148+
private function validateObjectStoreConfig(array|string $config): array|string {
149+
if (is_string($config)) {
150+
return $config;
151+
}
107152
if (!isset($config['class'])) {
108-
throw new \Exception('No class configured for object store');
153+
throw new InvalidObjectStoreConfigurationException('No class configured for object store');
109154
}
110155
if (!isset($config['arguments'])) {
111156
$config['arguments'] = [];
112157
}
113158
$class = $config['class'];
114159
$arguments = $config['arguments'];
115160
if (!is_array($arguments)) {
116-
throw new \Exception('Configured object store arguments are not an array');
161+
throw new InvalidObjectStoreConfigurationException('Configured object store arguments are not an array');
117162
}
118163
if (!isset($arguments['multibucket'])) {
119164
$arguments['multibucket'] = false;
120165
}
121166
if (!is_bool($arguments['multibucket'])) {
122-
throw new \Exception('arguments.multibucket must be a boolean in object store configuration');
167+
throw new InvalidObjectStoreConfigurationException('arguments.multibucket must be a boolean in object store configuration');
123168
}
124169

125170
if (!is_string($class)) {
126-
throw new \Exception('Configured class for object store is not a string');
171+
throw new InvalidObjectStoreConfigurationException('Configured class for object store is not a string');
127172
}
128173

129174
if (str_starts_with($class, 'OCA\\') && substr_count($class, '\\') >= 2) {
@@ -132,7 +177,7 @@ private function validateObjectStoreConfig(array $config) {
132177
}
133178

134179
if (!is_a($class, IObjectStore::class, true)) {
135-
throw new \Exception('Configured class for object store is not an object store');
180+
throw new InvalidObjectStoreConfigurationException('Configured class for object store is not an object store');
136181
}
137182
return [
138183
'class' => $class,
@@ -152,7 +197,7 @@ public function getBucketForUser(IUser $user, array $config): string {
152197
$config['arguments']['bucket'] = '';
153198
}
154199
$mapper = new Mapper($user, $this->config);
155-
$numBuckets = isset($config['arguments']['num_buckets']) ? $config['arguments']['num_buckets'] : 64;
200+
$numBuckets = $config['arguments']['num_buckets'] ?? 64;
156201
$bucket = $config['arguments']['bucket'] . $mapper->getBucket($numBuckets);
157202

158203
$this->config->setUserValue($user->getUID(), 'homeobjectstore', 'bucket', $bucket);
@@ -166,6 +211,15 @@ public function getSetBucketForUser(IUser $user): ?string {
166211
}
167212

168213
public function getObjectStoreForUser(IUser $user): string {
169-
return $this->config->getUserValue($user->getUID(), 'homeobjectstore', 'objectstore', 'default');
214+
if ($this->hasMultipleObjectStorages()) {
215+
$value = $this->config->getUserValue($user->getUID(), 'homeobjectstore', 'objectstore', null);
216+
if ($value === null) {
217+
$value = $this->resolveAlias('default');
218+
$this->config->setUserValue($user->getUID(), 'homeobjectstore', 'objectstore', $value);
219+
}
220+
return $value;
221+
} else {
222+
return 'default';
223+
}
170224
}
171225
}

0 commit comments

Comments
 (0)