Completed
Push — master ( 809bbe...f2de5c )
by
unknown
49:25 queued 20:26
created
lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php 2 patches
Indentation   +202 added lines, -202 removed lines patch added patch discarded remove patch
@@ -17,209 +17,209 @@
 block discarded – undo
17 17
  * @psalm-type ObjectStoreConfig array{class: class-string<IObjectStore>, arguments: array{multibucket: bool, ...}}
18 18
  */
19 19
 class PrimaryObjectStoreConfig {
20
-	public function __construct(
21
-		private readonly IConfig $config,
22
-		private readonly IAppManager $appManager,
23
-	) {
24
-	}
25
-
26
-	/**
27
-	 * @param ObjectStoreConfig $config
28
-	 */
29
-	public function buildObjectStore(array $config): IObjectStore {
30
-		return new $config['class']($config['arguments']);
31
-	}
32
-
33
-	/**
34
-	 * @return ?ObjectStoreConfig
35
-	 */
36
-	public function getObjectStoreConfigForRoot(): ?array {
37
-		if (!$this->hasObjectStore()) {
38
-			return null;
39
-		}
40
-
41
-		$config = $this->getObjectStoreConfiguration('root');
42
-
43
-		if ($config['arguments']['multibucket']) {
44
-			if (!isset($config['arguments']['bucket'])) {
45
-				$config['arguments']['bucket'] = '';
46
-			}
47
-
48
-			// put the root FS always in first bucket for multibucket configuration
49
-			$config['arguments']['bucket'] .= '0';
50
-		}
51
-		return $config;
52
-	}
53
-
54
-	/**
55
-	 * @return ?ObjectStoreConfig
56
-	 */
57
-	public function getObjectStoreConfigForUser(IUser $user): ?array {
58
-		if (!$this->hasObjectStore()) {
59
-			return null;
60
-		}
61
-
62
-		$store = $this->getObjectStoreForUser($user);
63
-		$config = $this->getObjectStoreConfiguration($store);
64
-
65
-		if ($config['arguments']['multibucket']) {
66
-			$config['arguments']['bucket'] = $this->getBucketForUser($user, $config);
67
-		}
68
-		return $config;
69
-	}
70
-
71
-	/**
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
110
-	 */
111
-	public function getObjectStoreConfigs(): ?array {
112
-		$objectStore = $this->config->getSystemValue('objectstore', null);
113
-		$objectStoreMultiBucket = $this->config->getSystemValue('objectstore_multibucket', null);
114
-
115
-		// new-style multibucket config uses the same 'objectstore' key but sets `'multibucket' => true`, transparently upgrade older style config
116
-		if ($objectStoreMultiBucket) {
117
-			$objectStoreMultiBucket['arguments']['multibucket'] = true;
118
-			return [
119
-				'default' => 'server1',
120
-				'server1' => $this->validateObjectStoreConfig($objectStoreMultiBucket),
121
-				'root' => 'server1',
122
-			];
123
-		} elseif ($objectStore) {
124
-			if (!isset($objectStore['default'])) {
125
-				$objectStore = [
126
-					'default' => 'server1',
127
-					'root' => 'server1',
128
-					'server1' => $objectStore,
129
-				];
130
-			}
131
-			if (!isset($objectStore['root'])) {
132
-				$objectStore['root'] = 'default';
133
-			}
134
-
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
-			}
138
-			return array_map($this->validateObjectStoreConfig(...), $objectStore);
139
-		} else {
140
-			return null;
141
-		}
142
-	}
143
-
144
-	/**
145
-	 * @param array|string $config
146
-	 * @return string|ObjectStoreConfig
147
-	 */
148
-	private function validateObjectStoreConfig(array|string $config): array|string {
149
-		if (is_string($config)) {
150
-			return $config;
151
-		}
152
-		if (!isset($config['class'])) {
153
-			throw new InvalidObjectStoreConfigurationException('No class configured for object store');
154
-		}
155
-		if (!isset($config['arguments'])) {
156
-			$config['arguments'] = [];
157
-		}
158
-		$class = $config['class'];
159
-		$arguments = $config['arguments'];
160
-		if (!is_array($arguments)) {
161
-			throw new InvalidObjectStoreConfigurationException('Configured object store arguments are not an array');
162
-		}
163
-		if (!isset($arguments['multibucket'])) {
164
-			$arguments['multibucket'] = false;
165
-		}
166
-		if (!is_bool($arguments['multibucket'])) {
167
-			throw new InvalidObjectStoreConfigurationException('arguments.multibucket must be a boolean in object store configuration');
168
-		}
169
-
170
-		if (!is_string($class)) {
171
-			throw new InvalidObjectStoreConfigurationException('Configured class for object store is not a string');
172
-		}
173
-
174
-		if (str_starts_with($class, 'OCA\\') && substr_count($class, '\\') >= 2) {
175
-			[$appId] = explode('\\', $class);
176
-			$this->appManager->loadApp(strtolower($appId));
177
-		}
178
-
179
-		if (!is_a($class, IObjectStore::class, true)) {
180
-			throw new InvalidObjectStoreConfigurationException('Configured class for object store is not an object store');
181
-		}
182
-		return [
183
-			'class' => $class,
184
-			'arguments' => $arguments,
185
-		];
186
-	}
187
-
188
-	public function getBucketForUser(IUser $user, array $config): string {
189
-		$bucket = $this->getSetBucketForUser($user);
190
-
191
-		if ($bucket === null) {
192
-			/*
20
+    public function __construct(
21
+        private readonly IConfig $config,
22
+        private readonly IAppManager $appManager,
23
+    ) {
24
+    }
25
+
26
+    /**
27
+     * @param ObjectStoreConfig $config
28
+     */
29
+    public function buildObjectStore(array $config): IObjectStore {
30
+        return new $config['class']($config['arguments']);
31
+    }
32
+
33
+    /**
34
+     * @return ?ObjectStoreConfig
35
+     */
36
+    public function getObjectStoreConfigForRoot(): ?array {
37
+        if (!$this->hasObjectStore()) {
38
+            return null;
39
+        }
40
+
41
+        $config = $this->getObjectStoreConfiguration('root');
42
+
43
+        if ($config['arguments']['multibucket']) {
44
+            if (!isset($config['arguments']['bucket'])) {
45
+                $config['arguments']['bucket'] = '';
46
+            }
47
+
48
+            // put the root FS always in first bucket for multibucket configuration
49
+            $config['arguments']['bucket'] .= '0';
50
+        }
51
+        return $config;
52
+    }
53
+
54
+    /**
55
+     * @return ?ObjectStoreConfig
56
+     */
57
+    public function getObjectStoreConfigForUser(IUser $user): ?array {
58
+        if (!$this->hasObjectStore()) {
59
+            return null;
60
+        }
61
+
62
+        $store = $this->getObjectStoreForUser($user);
63
+        $config = $this->getObjectStoreConfiguration($store);
64
+
65
+        if ($config['arguments']['multibucket']) {
66
+            $config['arguments']['bucket'] = $this->getBucketForUser($user, $config);
67
+        }
68
+        return $config;
69
+    }
70
+
71
+    /**
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
110
+     */
111
+    public function getObjectStoreConfigs(): ?array {
112
+        $objectStore = $this->config->getSystemValue('objectstore', null);
113
+        $objectStoreMultiBucket = $this->config->getSystemValue('objectstore_multibucket', null);
114
+
115
+        // new-style multibucket config uses the same 'objectstore' key but sets `'multibucket' => true`, transparently upgrade older style config
116
+        if ($objectStoreMultiBucket) {
117
+            $objectStoreMultiBucket['arguments']['multibucket'] = true;
118
+            return [
119
+                'default' => 'server1',
120
+                'server1' => $this->validateObjectStoreConfig($objectStoreMultiBucket),
121
+                'root' => 'server1',
122
+            ];
123
+        } elseif ($objectStore) {
124
+            if (!isset($objectStore['default'])) {
125
+                $objectStore = [
126
+                    'default' => 'server1',
127
+                    'root' => 'server1',
128
+                    'server1' => $objectStore,
129
+                ];
130
+            }
131
+            if (!isset($objectStore['root'])) {
132
+                $objectStore['root'] = 'default';
133
+            }
134
+
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
+            }
138
+            return array_map($this->validateObjectStoreConfig(...), $objectStore);
139
+        } else {
140
+            return null;
141
+        }
142
+    }
143
+
144
+    /**
145
+     * @param array|string $config
146
+     * @return string|ObjectStoreConfig
147
+     */
148
+    private function validateObjectStoreConfig(array|string $config): array|string {
149
+        if (is_string($config)) {
150
+            return $config;
151
+        }
152
+        if (!isset($config['class'])) {
153
+            throw new InvalidObjectStoreConfigurationException('No class configured for object store');
154
+        }
155
+        if (!isset($config['arguments'])) {
156
+            $config['arguments'] = [];
157
+        }
158
+        $class = $config['class'];
159
+        $arguments = $config['arguments'];
160
+        if (!is_array($arguments)) {
161
+            throw new InvalidObjectStoreConfigurationException('Configured object store arguments are not an array');
162
+        }
163
+        if (!isset($arguments['multibucket'])) {
164
+            $arguments['multibucket'] = false;
165
+        }
166
+        if (!is_bool($arguments['multibucket'])) {
167
+            throw new InvalidObjectStoreConfigurationException('arguments.multibucket must be a boolean in object store configuration');
168
+        }
169
+
170
+        if (!is_string($class)) {
171
+            throw new InvalidObjectStoreConfigurationException('Configured class for object store is not a string');
172
+        }
173
+
174
+        if (str_starts_with($class, 'OCA\\') && substr_count($class, '\\') >= 2) {
175
+            [$appId] = explode('\\', $class);
176
+            $this->appManager->loadApp(strtolower($appId));
177
+        }
178
+
179
+        if (!is_a($class, IObjectStore::class, true)) {
180
+            throw new InvalidObjectStoreConfigurationException('Configured class for object store is not an object store');
181
+        }
182
+        return [
183
+            'class' => $class,
184
+            'arguments' => $arguments,
185
+        ];
186
+    }
187
+
188
+    public function getBucketForUser(IUser $user, array $config): string {
189
+        $bucket = $this->getSetBucketForUser($user);
190
+
191
+        if ($bucket === null) {
192
+            /*
193 193
 			 * Use any provided bucket argument as prefix
194 194
 			 * and add the mapping from username => bucket
195 195
 			 */
196
-			if (!isset($config['arguments']['bucket'])) {
197
-				$config['arguments']['bucket'] = '';
198
-			}
199
-			$mapper = new Mapper($user, $config);
200
-			$numBuckets = $config['arguments']['num_buckets'] ?? 64;
201
-			$bucket = $config['arguments']['bucket'] . $mapper->getBucket($numBuckets);
202
-
203
-			$this->config->setUserValue($user->getUID(), 'homeobjectstore', 'bucket', $bucket);
204
-		}
205
-
206
-		return $bucket;
207
-	}
208
-
209
-	public function getSetBucketForUser(IUser $user): ?string {
210
-		return $this->config->getUserValue($user->getUID(), 'homeobjectstore', 'bucket', null);
211
-	}
212
-
213
-	public function getObjectStoreForUser(IUser $user): string {
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
-		}
224
-	}
196
+            if (!isset($config['arguments']['bucket'])) {
197
+                $config['arguments']['bucket'] = '';
198
+            }
199
+            $mapper = new Mapper($user, $config);
200
+            $numBuckets = $config['arguments']['num_buckets'] ?? 64;
201
+            $bucket = $config['arguments']['bucket'] . $mapper->getBucket($numBuckets);
202
+
203
+            $this->config->setUserValue($user->getUID(), 'homeobjectstore', 'bucket', $bucket);
204
+        }
205
+
206
+        return $bucket;
207
+    }
208
+
209
+    public function getSetBucketForUser(IUser $user): ?string {
210
+        return $this->config->getUserValue($user->getUID(), 'homeobjectstore', 'bucket', null);
211
+    }
212
+
213
+    public function getObjectStoreForUser(IUser $user): string {
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
+        }
224
+    }
225 225
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -145,7 +145,7 @@  discard block
 block discarded – undo
145 145
 	 * @param array|string $config
146 146
 	 * @return string|ObjectStoreConfig
147 147
 	 */
148
-	private function validateObjectStoreConfig(array|string $config): array|string {
148
+	private function validateObjectStoreConfig(array | string $config): array | string {
149 149
 		if (is_string($config)) {
150 150
 			return $config;
151 151
 		}
@@ -198,7 +198,7 @@  discard block
 block discarded – undo
198 198
 			}
199 199
 			$mapper = new Mapper($user, $config);
200 200
 			$numBuckets = $config['arguments']['num_buckets'] ?? 64;
201
-			$bucket = $config['arguments']['bucket'] . $mapper->getBucket($numBuckets);
201
+			$bucket = $config['arguments']['bucket'].$mapper->getBucket($numBuckets);
202 202
 
203 203
 			$this->config->setUserValue($user->getUID(), 'homeobjectstore', 'bucket', $bucket);
204 204
 		}
Please login to merge, or discard this patch.
lib/private/Files/ObjectStore/Mapper.php 2 patches
Indentation   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -17,21 +17,21 @@
 block discarded – undo
17 17
  * Map a user to a bucket.
18 18
  */
19 19
 class Mapper {
20
-	public function __construct(
21
-		private readonly IUser $user,
22
-		private readonly array $config,
23
-	) {
24
-	}
20
+    public function __construct(
21
+        private readonly IUser $user,
22
+        private readonly array $config,
23
+    ) {
24
+    }
25 25
 
26
-	public function getBucket(int $numBuckets = 64): string {
27
-		// Get the bucket config and shift if provided.
28
-		// Allow us to prevent writing in old filled buckets
29
-		$minBucket = isset($this->config['arguments']['min_bucket'])
30
-			? (int)$this->config['arguments']['min_bucket']
31
-			: 0;
26
+    public function getBucket(int $numBuckets = 64): string {
27
+        // Get the bucket config and shift if provided.
28
+        // Allow us to prevent writing in old filled buckets
29
+        $minBucket = isset($this->config['arguments']['min_bucket'])
30
+            ? (int)$this->config['arguments']['min_bucket']
31
+            : 0;
32 32
 
33
-		$hash = md5($this->user->getUID());
34
-		$num = hexdec(substr($hash, 0, 4));
35
-		return (string)(($num % ($numBuckets - $minBucket)) + $minBucket);
36
-	}
33
+        $hash = md5($this->user->getUID());
34
+        $num = hexdec(substr($hash, 0, 4));
35
+        return (string)(($num % ($numBuckets - $minBucket)) + $minBucket);
36
+    }
37 37
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -27,11 +27,11 @@
 block discarded – undo
27 27
 		// Get the bucket config and shift if provided.
28 28
 		// Allow us to prevent writing in old filled buckets
29 29
 		$minBucket = isset($this->config['arguments']['min_bucket'])
30
-			? (int)$this->config['arguments']['min_bucket']
30
+			? (int) $this->config['arguments']['min_bucket']
31 31
 			: 0;
32 32
 
33 33
 		$hash = md5($this->user->getUID());
34 34
 		$num = hexdec(substr($hash, 0, 4));
35
-		return (string)(($num % ($numBuckets - $minBucket)) + $minBucket);
35
+		return (string) (($num % ($numBuckets - $minBucket)) + $minBucket);
36 36
 	}
37 37
 }
Please login to merge, or discard this patch.
tests/lib/Files/ObjectStore/MapperTest.php 1 patch
Indentation   +36 added lines, -36 removed lines patch added patch discarded remove patch
@@ -12,40 +12,40 @@
 block discarded – undo
12 12
 use OCP\IUser;
13 13
 
14 14
 class MapperTest extends \Test\TestCase {
15
-	/** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
16
-	private $user;
17
-
18
-	protected function setUp(): void {
19
-		parent::setUp();
20
-
21
-		$this->user = $this->createMock(IUser::class);
22
-	}
23
-
24
-	public static function dataGetBucket(): array {
25
-		return [
26
-			['user', 64, 0, '17'],
27
-			['USER', 64, 0, '0'],
28
-			['bc0e8b52-a66c-1035-90c6-d9663bda9e3f', 64, 0, '56'],
29
-			['user', 8, 0, '1'],
30
-			['user', 2, 0, '1'],
31
-			['USER', 2, 0, '0'],
32
-			['user', 128, 64, '81'],
33
-		];
34
-	}
35
-
36
-	/**
37
-	 * @param string $username
38
-	 * @param int $numBuckets
39
-	 * @param string $expectedBucket
40
-	 */
41
-	#[\PHPUnit\Framework\Attributes\DataProvider('dataGetBucket')]
42
-	public function testGetBucket($username, $numBuckets, $bucketShift, $expectedBucket): void {
43
-		$mapper = new Mapper($this->user, ['arguments' => ['min_bucket' => $bucketShift]]);
44
-		$this->user->expects($this->once())
45
-			->method('getUID')
46
-			->willReturn($username);
47
-
48
-		$result = $mapper->getBucket($numBuckets);
49
-		$this->assertEquals($expectedBucket, $result);
50
-	}
15
+    /** @var IUser|\PHPUnit\Framework\MockObject\MockObject */
16
+    private $user;
17
+
18
+    protected function setUp(): void {
19
+        parent::setUp();
20
+
21
+        $this->user = $this->createMock(IUser::class);
22
+    }
23
+
24
+    public static function dataGetBucket(): array {
25
+        return [
26
+            ['user', 64, 0, '17'],
27
+            ['USER', 64, 0, '0'],
28
+            ['bc0e8b52-a66c-1035-90c6-d9663bda9e3f', 64, 0, '56'],
29
+            ['user', 8, 0, '1'],
30
+            ['user', 2, 0, '1'],
31
+            ['USER', 2, 0, '0'],
32
+            ['user', 128, 64, '81'],
33
+        ];
34
+    }
35
+
36
+    /**
37
+     * @param string $username
38
+     * @param int $numBuckets
39
+     * @param string $expectedBucket
40
+     */
41
+    #[\PHPUnit\Framework\Attributes\DataProvider('dataGetBucket')]
42
+    public function testGetBucket($username, $numBuckets, $bucketShift, $expectedBucket): void {
43
+        $mapper = new Mapper($this->user, ['arguments' => ['min_bucket' => $bucketShift]]);
44
+        $this->user->expects($this->once())
45
+            ->method('getUID')
46
+            ->willReturn($username);
47
+
48
+        $result = $mapper->getBucket($numBuckets);
49
+        $this->assertEquals($expectedBucket, $result);
50
+    }
51 51
 }
Please login to merge, or discard this patch.