Completed
Pull Request — master (#8857)
by Robin
53:37 queued 34:27
created
apps/files_external/lib/Lib/Storage/Swift.php 1 patch
Indentation   +569 added lines, -569 removed lines patch added patch discarded remove patch
@@ -49,577 +49,577 @@
 block discarded – undo
49 49
 use OpenStack\ObjectStore\v1\Models\StorageObject;
50 50
 
51 51
 class Swift extends \OC\Files\Storage\Common {
52
-	/** @var SwiftFactory */
53
-	private $connectionFactory;
54
-	/**
55
-	 * @var \OpenStack\ObjectStore\v1\Models\Container
56
-	 */
57
-	private $container;
58
-	/**
59
-	 * @var string
60
-	 */
61
-	private $bucket;
62
-	/**
63
-	 * Connection parameters
64
-	 *
65
-	 * @var array
66
-	 */
67
-	private $params;
68
-
69
-	/** @var string */
70
-	private $id;
71
-
72
-	/** @var \OC\Files\ObjectStore\Swift */
73
-	private $objectStore;
74
-
75
-	/**
76
-	 * Key value cache mapping path to data object. Maps path to
77
-	 * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
78
-	 * paths and path to false for not existing paths.
79
-	 *
80
-	 * @var \OCP\ICache
81
-	 */
82
-	private $objectCache;
83
-
84
-	/**
85
-	 * @param string $path
86
-	 * @return mixed|string
87
-	 */
88
-	private function normalizePath(string $path) {
89
-		$path = trim($path, '/');
90
-
91
-		if (!$path) {
92
-			$path = '.';
93
-		}
94
-
95
-		$path = str_replace('#', '%23', $path);
96
-
97
-		return $path;
98
-	}
99
-
100
-	const SUBCONTAINER_FILE = '.subcontainers';
101
-
102
-	/**
103
-	 * translate directory path to container name
104
-	 *
105
-	 * @param string $path
106
-	 * @return string
107
-	 */
108
-
109
-	/**
110
-	 * Fetches an object from the API.
111
-	 * If the object is cached already or a
112
-	 * failed "doesn't exist" response was cached,
113
-	 * that one will be returned.
114
-	 *
115
-	 * @param string $path
116
-	 * @return StorageObject|bool object
117
-	 * or false if the object did not exist
118
-	 * @throws \OCP\Files\StorageAuthException
119
-	 * @throws \OCP\Files\StorageNotAvailableException
120
-	 */
121
-	private function fetchObject(string $path) {
122
-		if ($this->objectCache->hasKey($path)) {
123
-			// might be "false" if object did not exist from last check
124
-			return $this->objectCache->get($path);
125
-		}
126
-		try {
127
-			$object = $this->getContainer()->getObject($path);
128
-			$object->retrieve();
129
-			$this->objectCache->set($path, $object);
130
-			return $object;
131
-		} catch (BadResponseError $e) {
132
-			// Expected response is "404 Not Found", so only log if it isn't
133
-			if ($e->getResponse()->getStatusCode() !== 404) {
134
-				\OC::$server->getLogger()->logException($e, [
135
-					'level' => \OCP\Util::ERROR,
136
-					'app' => 'files_external',
137
-				]);
138
-			}
139
-			$this->objectCache->set($path, false);
140
-			return false;
141
-		}
142
-	}
143
-
144
-	/**
145
-	 * Returns whether the given path exists.
146
-	 *
147
-	 * @param string $path
148
-	 *
149
-	 * @return bool true if the object exist, false otherwise
150
-	 * @throws \OCP\Files\StorageAuthException
151
-	 * @throws \OCP\Files\StorageNotAvailableException
152
-	 */
153
-	private function doesObjectExist($path) {
154
-		return $this->fetchObject($path) !== false;
155
-	}
156
-
157
-	public function __construct($params) {
158
-		if ((empty($params['key']) and empty($params['password']))
159
-			or (empty($params['user']) && empty($params['userid'])) or empty($params['bucket'])
160
-			or empty($params['region'])
161
-		) {
162
-			throw new StorageBadConfigException("API Key or password, Username, Bucket and Region have to be configured.");
163
-		}
164
-
165
-		$user = $params['user'];
166
-		$this->id = 'swift::' . $user . md5($params['bucket']);
167
-
168
-		$bucketUrl = new Uri($params['bucket']);
169
-		if ($bucketUrl->getHost()) {
170
-			$params['bucket'] = basename($bucketUrl->getPath());
171
-			$params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
172
-		}
173
-
174
-		if (empty($params['url'])) {
175
-			$params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
176
-		}
177
-
178
-		if (empty($params['service_name'])) {
179
-			$params['service_name'] = 'cloudFiles';
180
-		}
181
-
182
-		$params['autocreate'] = true;
183
-
184
-		if (isset($params['domain'])) {
185
-			$params['user'] = [
186
-				'name' => $params['user'],
187
-				'password' => $params['password'],
188
-				'domain' => [
189
-					'name' => $params['domain'],
190
-				]
191
-			];
192
-		}
193
-
194
-		$this->params = $params;
195
-		// FIXME: private class...
196
-		$this->objectCache = new \OC\Cache\CappedMemoryCache();
197
-		$this->connectionFactory = new SwiftFactory(
198
-			\OC::$server->getMemCacheFactory()->createDistributed('swift/'),
199
-			$this->params,
200
-			\OC::$server->getLogger()
201
-		);
202
-		$this->objectStore = new \OC\Files\ObjectStore\Swift($this->params, $this->connectionFactory);
203
-		$this->bucket = $params['bucket'];
204
-	}
205
-
206
-	public function mkdir($path) {
207
-		$path = $this->normalizePath($path);
208
-
209
-		if ($this->is_dir($path)) {
210
-			return false;
211
-		}
212
-
213
-		if ($path !== '.') {
214
-			$path .= '/';
215
-		}
216
-
217
-		try {
218
-			$this->getContainer()->createObject([
219
-				'name' => $path,
220
-				'content' => '',
221
-				'headers' => ['content-type' => 'httpd/unix-directory']
222
-			]);
223
-			// invalidate so that the next access gets the real object
224
-			// with all properties
225
-			$this->objectCache->remove($path);
226
-		} catch (BadResponseError $e) {
227
-			\OC::$server->getLogger()->logException($e, [
228
-				'level' => \OCP\Util::ERROR,
229
-				'app' => 'files_external',
230
-			]);
231
-			return false;
232
-		}
233
-
234
-		return true;
235
-	}
236
-
237
-	public function file_exists($path) {
238
-		$path = $this->normalizePath($path);
239
-
240
-		if ($path !== '.' && $this->is_dir($path)) {
241
-			$path .= '/';
242
-		}
243
-
244
-		return $this->doesObjectExist($path);
245
-	}
246
-
247
-	public function rmdir($path) {
248
-		$path = $this->normalizePath($path);
249
-
250
-		if (!$this->is_dir($path) || !$this->isDeletable($path)) {
251
-			return false;
252
-		}
253
-
254
-		$dh = $this->opendir($path);
255
-		while ($file = readdir($dh)) {
256
-			if (\OC\Files\Filesystem::isIgnoredDir($file)) {
257
-				continue;
258
-			}
259
-
260
-			if ($this->is_dir($path . '/' . $file)) {
261
-				$this->rmdir($path . '/' . $file);
262
-			} else {
263
-				$this->unlink($path . '/' . $file);
264
-			}
265
-		}
266
-
267
-		try {
268
-			$this->objectStore->deleteObject($path . '/');
269
-			$this->objectCache->remove($path . '/');
270
-		} catch (BadResponseError $e) {
271
-			\OC::$server->getLogger()->logException($e, [
272
-				'level' => \OCP\Util::ERROR,
273
-				'app' => 'files_external',
274
-			]);
275
-			return false;
276
-		}
277
-
278
-		return true;
279
-	}
280
-
281
-	public function opendir($path) {
282
-		$path = $this->normalizePath($path);
283
-
284
-		if ($path === '.') {
285
-			$path = '';
286
-		} else {
287
-			$path .= '/';
288
-		}
52
+    /** @var SwiftFactory */
53
+    private $connectionFactory;
54
+    /**
55
+     * @var \OpenStack\ObjectStore\v1\Models\Container
56
+     */
57
+    private $container;
58
+    /**
59
+     * @var string
60
+     */
61
+    private $bucket;
62
+    /**
63
+     * Connection parameters
64
+     *
65
+     * @var array
66
+     */
67
+    private $params;
68
+
69
+    /** @var string */
70
+    private $id;
71
+
72
+    /** @var \OC\Files\ObjectStore\Swift */
73
+    private $objectStore;
74
+
75
+    /**
76
+     * Key value cache mapping path to data object. Maps path to
77
+     * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
78
+     * paths and path to false for not existing paths.
79
+     *
80
+     * @var \OCP\ICache
81
+     */
82
+    private $objectCache;
83
+
84
+    /**
85
+     * @param string $path
86
+     * @return mixed|string
87
+     */
88
+    private function normalizePath(string $path) {
89
+        $path = trim($path, '/');
90
+
91
+        if (!$path) {
92
+            $path = '.';
93
+        }
94
+
95
+        $path = str_replace('#', '%23', $path);
96
+
97
+        return $path;
98
+    }
99
+
100
+    const SUBCONTAINER_FILE = '.subcontainers';
101
+
102
+    /**
103
+     * translate directory path to container name
104
+     *
105
+     * @param string $path
106
+     * @return string
107
+     */
108
+
109
+    /**
110
+     * Fetches an object from the API.
111
+     * If the object is cached already or a
112
+     * failed "doesn't exist" response was cached,
113
+     * that one will be returned.
114
+     *
115
+     * @param string $path
116
+     * @return StorageObject|bool object
117
+     * or false if the object did not exist
118
+     * @throws \OCP\Files\StorageAuthException
119
+     * @throws \OCP\Files\StorageNotAvailableException
120
+     */
121
+    private function fetchObject(string $path) {
122
+        if ($this->objectCache->hasKey($path)) {
123
+            // might be "false" if object did not exist from last check
124
+            return $this->objectCache->get($path);
125
+        }
126
+        try {
127
+            $object = $this->getContainer()->getObject($path);
128
+            $object->retrieve();
129
+            $this->objectCache->set($path, $object);
130
+            return $object;
131
+        } catch (BadResponseError $e) {
132
+            // Expected response is "404 Not Found", so only log if it isn't
133
+            if ($e->getResponse()->getStatusCode() !== 404) {
134
+                \OC::$server->getLogger()->logException($e, [
135
+                    'level' => \OCP\Util::ERROR,
136
+                    'app' => 'files_external',
137
+                ]);
138
+            }
139
+            $this->objectCache->set($path, false);
140
+            return false;
141
+        }
142
+    }
143
+
144
+    /**
145
+     * Returns whether the given path exists.
146
+     *
147
+     * @param string $path
148
+     *
149
+     * @return bool true if the object exist, false otherwise
150
+     * @throws \OCP\Files\StorageAuthException
151
+     * @throws \OCP\Files\StorageNotAvailableException
152
+     */
153
+    private function doesObjectExist($path) {
154
+        return $this->fetchObject($path) !== false;
155
+    }
156
+
157
+    public function __construct($params) {
158
+        if ((empty($params['key']) and empty($params['password']))
159
+            or (empty($params['user']) && empty($params['userid'])) or empty($params['bucket'])
160
+            or empty($params['region'])
161
+        ) {
162
+            throw new StorageBadConfigException("API Key or password, Username, Bucket and Region have to be configured.");
163
+        }
164
+
165
+        $user = $params['user'];
166
+        $this->id = 'swift::' . $user . md5($params['bucket']);
167
+
168
+        $bucketUrl = new Uri($params['bucket']);
169
+        if ($bucketUrl->getHost()) {
170
+            $params['bucket'] = basename($bucketUrl->getPath());
171
+            $params['endpoint_url'] = (string)$bucketUrl->withPath(dirname($bucketUrl->getPath()));
172
+        }
173
+
174
+        if (empty($params['url'])) {
175
+            $params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
176
+        }
177
+
178
+        if (empty($params['service_name'])) {
179
+            $params['service_name'] = 'cloudFiles';
180
+        }
181
+
182
+        $params['autocreate'] = true;
183
+
184
+        if (isset($params['domain'])) {
185
+            $params['user'] = [
186
+                'name' => $params['user'],
187
+                'password' => $params['password'],
188
+                'domain' => [
189
+                    'name' => $params['domain'],
190
+                ]
191
+            ];
192
+        }
193
+
194
+        $this->params = $params;
195
+        // FIXME: private class...
196
+        $this->objectCache = new \OC\Cache\CappedMemoryCache();
197
+        $this->connectionFactory = new SwiftFactory(
198
+            \OC::$server->getMemCacheFactory()->createDistributed('swift/'),
199
+            $this->params,
200
+            \OC::$server->getLogger()
201
+        );
202
+        $this->objectStore = new \OC\Files\ObjectStore\Swift($this->params, $this->connectionFactory);
203
+        $this->bucket = $params['bucket'];
204
+    }
205
+
206
+    public function mkdir($path) {
207
+        $path = $this->normalizePath($path);
208
+
209
+        if ($this->is_dir($path)) {
210
+            return false;
211
+        }
212
+
213
+        if ($path !== '.') {
214
+            $path .= '/';
215
+        }
216
+
217
+        try {
218
+            $this->getContainer()->createObject([
219
+                'name' => $path,
220
+                'content' => '',
221
+                'headers' => ['content-type' => 'httpd/unix-directory']
222
+            ]);
223
+            // invalidate so that the next access gets the real object
224
+            // with all properties
225
+            $this->objectCache->remove($path);
226
+        } catch (BadResponseError $e) {
227
+            \OC::$server->getLogger()->logException($e, [
228
+                'level' => \OCP\Util::ERROR,
229
+                'app' => 'files_external',
230
+            ]);
231
+            return false;
232
+        }
233
+
234
+        return true;
235
+    }
236
+
237
+    public function file_exists($path) {
238
+        $path = $this->normalizePath($path);
239
+
240
+        if ($path !== '.' && $this->is_dir($path)) {
241
+            $path .= '/';
242
+        }
243
+
244
+        return $this->doesObjectExist($path);
245
+    }
246
+
247
+    public function rmdir($path) {
248
+        $path = $this->normalizePath($path);
249
+
250
+        if (!$this->is_dir($path) || !$this->isDeletable($path)) {
251
+            return false;
252
+        }
253
+
254
+        $dh = $this->opendir($path);
255
+        while ($file = readdir($dh)) {
256
+            if (\OC\Files\Filesystem::isIgnoredDir($file)) {
257
+                continue;
258
+            }
259
+
260
+            if ($this->is_dir($path . '/' . $file)) {
261
+                $this->rmdir($path . '/' . $file);
262
+            } else {
263
+                $this->unlink($path . '/' . $file);
264
+            }
265
+        }
266
+
267
+        try {
268
+            $this->objectStore->deleteObject($path . '/');
269
+            $this->objectCache->remove($path . '/');
270
+        } catch (BadResponseError $e) {
271
+            \OC::$server->getLogger()->logException($e, [
272
+                'level' => \OCP\Util::ERROR,
273
+                'app' => 'files_external',
274
+            ]);
275
+            return false;
276
+        }
277
+
278
+        return true;
279
+    }
280
+
281
+    public function opendir($path) {
282
+        $path = $this->normalizePath($path);
283
+
284
+        if ($path === '.') {
285
+            $path = '';
286
+        } else {
287
+            $path .= '/';
288
+        }
289 289
 
290 290
 //		$path = str_replace('%23', '#', $path); // the prefix is sent as a query param, so revert the encoding of #
291 291
 
292
-		try {
293
-			$files = [];
294
-			$objects = $this->getContainer()->listObjects([
295
-				'prefix' => $path,
296
-				'delimiter' => '/'
297
-			]);
298
-
299
-			/** @var StorageObject $object */
300
-			foreach ($objects as $object) {
301
-				$file = basename($object->name);
302
-				if ($file !== basename($path) && $file !== '.') {
303
-					$files[] = $file;
304
-				}
305
-			}
306
-
307
-			return IteratorDirectory::wrap($files);
308
-		} catch (\Exception $e) {
309
-			\OC::$server->getLogger()->logException($e, [
310
-				'level' => \OCP\Util::ERROR,
311
-				'app' => 'files_external',
312
-			]);
313
-			return false;
314
-		}
315
-
316
-	}
317
-
318
-	public function stat($path) {
319
-		$path = $this->normalizePath($path);
320
-
321
-		if ($path === '.') {
322
-			$path = '';
323
-		} else if ($this->is_dir($path)) {
324
-			$path .= '/';
325
-		}
326
-
327
-		try {
328
-			$object = $this->fetchObject($path);
329
-			if (!$object) {
330
-				return false;
331
-			}
332
-		} catch (BadResponseError $e) {
333
-			\OC::$server->getLogger()->logException($e, [
334
-				'level' => \OCP\Util::ERROR,
335
-				'app' => 'files_external',
336
-			]);
337
-			return false;
338
-		}
339
-
340
-		$dateTime = $object->lastModified ? \DateTime::createFromFormat(\DateTime::RFC1123, $object->lastModified) : false;
341
-		$mtime = $dateTime ? $dateTime->getTimestamp() : null;
342
-		$objectMetadata = $object->getMetadata();
343
-		if (isset($objectMetadata['timestamp'])) {
344
-			$mtime = $objectMetadata['timestamp'];
345
-		}
346
-
347
-		if (!empty($mtime)) {
348
-			$mtime = floor($mtime);
349
-		}
350
-
351
-		$stat = array();
352
-		$stat['size'] = (int)$object->contentLength;
353
-		$stat['mtime'] = $mtime;
354
-		$stat['atime'] = time();
355
-		return $stat;
356
-	}
357
-
358
-	public function filetype($path) {
359
-		$path = $this->normalizePath($path);
360
-
361
-		if ($path !== '.' && $this->doesObjectExist($path)) {
362
-			return 'file';
363
-		}
364
-
365
-		if ($path !== '.') {
366
-			$path .= '/';
367
-		}
368
-
369
-		if ($this->doesObjectExist($path)) {
370
-			return 'dir';
371
-		}
372
-	}
373
-
374
-	public function unlink($path) {
375
-		$path = $this->normalizePath($path);
376
-
377
-		if ($this->is_dir($path)) {
378
-			return $this->rmdir($path);
379
-		}
380
-
381
-		try {
382
-			$this->objectStore->deleteObject($path);
383
-			$this->objectCache->remove($path);
384
-			$this->objectCache->remove($path . '/');
385
-		} catch (BadResponseError $e) {
386
-			if ($e->getResponse()->getStatusCode() !== 404) {
387
-				\OC::$server->getLogger()->logException($e, [
388
-					'level' => \OCP\Util::ERROR,
389
-					'app' => 'files_external',
390
-				]);
391
-				throw $e;
392
-			}
393
-		}
394
-
395
-		return true;
396
-	}
397
-
398
-	public function fopen($path, $mode) {
399
-		$path = $this->normalizePath($path);
400
-
401
-		switch ($mode) {
402
-			case 'a':
403
-			case 'ab':
404
-			case 'a+':
405
-				return false;
406
-			case 'r':
407
-			case 'rb':
408
-				try {
409
-					return $this->objectStore->readObject($path);
410
-				} catch (BadResponseError $e) {
411
-					\OC::$server->getLogger()->logException($e, [
412
-						'level' => \OCP\Util::ERROR,
413
-						'app' => 'files_external',
414
-					]);
415
-					return false;
416
-				}
417
-			case 'w':
418
-			case 'wb':
419
-			case 'r+':
420
-			case 'w+':
421
-			case 'wb+':
422
-			case 'x':
423
-			case 'x+':
424
-			case 'c':
425
-			case 'c+':
426
-				if (strrpos($path, '.') !== false) {
427
-					$ext = substr($path, strrpos($path, '.'));
428
-				} else {
429
-					$ext = '';
430
-				}
431
-				$tmpFile = \OCP\Files::tmpFile($ext);
432
-				// Fetch existing file if required
433
-				if ($mode[0] !== 'w' && $this->file_exists($path)) {
434
-					if ($mode[0] === 'x') {
435
-						// File cannot already exist
436
-						return false;
437
-					}
438
-					$source = $this->fopen($path, 'r');
439
-					file_put_contents($tmpFile, $source);
440
-				}
441
-				$handle = fopen($tmpFile, $mode);
442
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
443
-					$this->writeBack($tmpFile, $path);
444
-				});
445
-		}
446
-	}
447
-
448
-	public function touch($path, $mtime = null) {
449
-		$path = $this->normalizePath($path);
450
-		if (is_null($mtime)) {
451
-			$mtime = time();
452
-		}
453
-		$metadata = ['timestamp' => $mtime];
454
-		if ($this->file_exists($path)) {
455
-			if ($this->is_dir($path) && $path !== '.') {
456
-				$path .= '/';
457
-			}
458
-
459
-			$object = $this->fetchObject($path);
460
-			if ($object->mergeMetadata($metadata)) {
461
-				// invalidate target object to force repopulation on fetch
462
-				$this->objectCache->remove($path);
463
-			}
464
-			return true;
465
-		} else {
466
-			$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
467
-			$this->getContainer()->createObject([
468
-				'name' => $path,
469
-				'content' => '',
470
-				'headers' => ['content-type' => 'httpd/unix-directory']
471
-			]);
472
-			// invalidate target object to force repopulation on fetch
473
-			$this->objectCache->remove($path);
474
-			return true;
475
-		}
476
-	}
477
-
478
-	public function copy($path1, $path2) {
479
-		$path1 = $this->normalizePath($path1);
480
-		$path2 = $this->normalizePath($path2);
481
-
482
-		$fileType = $this->filetype($path1);
483
-		if ($fileType) {
484
-			// make way
485
-			$this->unlink($path2);
486
-		}
487
-
488
-		if ($fileType === 'file') {
489
-			try {
490
-				$source = $this->fetchObject($path1);
491
-				$source->copy([
492
-					'destination' => $this->bucket . '/' . $path2
493
-				]);
494
-				// invalidate target object to force repopulation on fetch
495
-				$this->objectCache->remove($path2);
496
-				$this->objectCache->remove($path2 . '/');
497
-			} catch (BadResponseError $e) {
498
-				\OC::$server->getLogger()->logException($e, [
499
-					'level' => \OCP\Util::ERROR,
500
-					'app' => 'files_external',
501
-				]);
502
-				return false;
503
-			}
504
-
505
-		} else if ($fileType === 'dir') {
506
-			try {
507
-				$source = $this->fetchObject($path1 . '/');
508
-				$source->copy([
509
-					'destination' => $this->bucket . '/' . $path2 . '/'
510
-				]);
511
-				// invalidate target object to force repopulation on fetch
512
-				$this->objectCache->remove($path2);
513
-				$this->objectCache->remove($path2 . '/');
514
-			} catch (BadResponseError $e) {
515
-				\OC::$server->getLogger()->logException($e, [
516
-					'level' => \OCP\Util::ERROR,
517
-					'app' => 'files_external',
518
-				]);
519
-				return false;
520
-			}
521
-
522
-			$dh = $this->opendir($path1);
523
-			while ($file = readdir($dh)) {
524
-				if (\OC\Files\Filesystem::isIgnoredDir($file)) {
525
-					continue;
526
-				}
527
-
528
-				$source = $path1 . '/' . $file;
529
-				$target = $path2 . '/' . $file;
530
-				$this->copy($source, $target);
531
-			}
532
-
533
-		} else {
534
-			//file does not exist
535
-			return false;
536
-		}
537
-
538
-		return true;
539
-	}
540
-
541
-	public function rename($path1, $path2) {
542
-		$path1 = $this->normalizePath($path1);
543
-		$path2 = $this->normalizePath($path2);
544
-
545
-		$fileType = $this->filetype($path1);
546
-
547
-		if ($fileType === 'dir' || $fileType === 'file') {
548
-			// copy
549
-			if ($this->copy($path1, $path2) === false) {
550
-				return false;
551
-			}
552
-
553
-			// cleanup
554
-			if ($this->unlink($path1) === false) {
555
-				throw new \Exception('failed to remove original');
556
-				$this->unlink($path2);
557
-				return false;
558
-			}
559
-
560
-			return true;
561
-		}
562
-
563
-		return false;
564
-	}
565
-
566
-	public function getId() {
567
-		return $this->id;
568
-	}
569
-
570
-	/**
571
-	 * Returns the initialized object store container.
572
-	 *
573
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
574
-	 * @throws \OCP\Files\StorageAuthException
575
-	 * @throws \OCP\Files\StorageNotAvailableException
576
-	 */
577
-	public function getContainer() {
578
-		if (is_null($this->container)) {
579
-			$this->container = $this->connectionFactory->getContainer();
580
-
581
-			if (!$this->file_exists('.')) {
582
-				$this->mkdir('.');
583
-			}
584
-		}
585
-		return $this->container;
586
-	}
587
-
588
-	public function writeBack($tmpFile, $path) {
589
-		$fileData = fopen($tmpFile, 'r');
590
-		$this->objectStore->writeObject($path, $fileData);
591
-		// invalidate target object to force repopulation on fetch
592
-		$this->objectCache->remove($path);
593
-		unlink($tmpFile);
594
-	}
595
-
596
-	public function hasUpdated($path, $time) {
597
-		if ($this->is_file($path)) {
598
-			return parent::hasUpdated($path, $time);
599
-		}
600
-		$path = $this->normalizePath($path);
601
-		$dh = $this->opendir($path);
602
-		$content = array();
603
-		while (($file = readdir($dh)) !== false) {
604
-			$content[] = $file;
605
-		}
606
-		if ($path === '.') {
607
-			$path = '';
608
-		}
609
-		$cachedContent = $this->getCache()->getFolderContents($path);
610
-		$cachedNames = array_map(function ($content) {
611
-			return $content['name'];
612
-		}, $cachedContent);
613
-		sort($cachedNames);
614
-		sort($content);
615
-		return $cachedNames !== $content;
616
-	}
617
-
618
-	/**
619
-	 * check if curl is installed
620
-	 */
621
-	public static function checkDependencies() {
622
-		return true;
623
-	}
292
+        try {
293
+            $files = [];
294
+            $objects = $this->getContainer()->listObjects([
295
+                'prefix' => $path,
296
+                'delimiter' => '/'
297
+            ]);
298
+
299
+            /** @var StorageObject $object */
300
+            foreach ($objects as $object) {
301
+                $file = basename($object->name);
302
+                if ($file !== basename($path) && $file !== '.') {
303
+                    $files[] = $file;
304
+                }
305
+            }
306
+
307
+            return IteratorDirectory::wrap($files);
308
+        } catch (\Exception $e) {
309
+            \OC::$server->getLogger()->logException($e, [
310
+                'level' => \OCP\Util::ERROR,
311
+                'app' => 'files_external',
312
+            ]);
313
+            return false;
314
+        }
315
+
316
+    }
317
+
318
+    public function stat($path) {
319
+        $path = $this->normalizePath($path);
320
+
321
+        if ($path === '.') {
322
+            $path = '';
323
+        } else if ($this->is_dir($path)) {
324
+            $path .= '/';
325
+        }
326
+
327
+        try {
328
+            $object = $this->fetchObject($path);
329
+            if (!$object) {
330
+                return false;
331
+            }
332
+        } catch (BadResponseError $e) {
333
+            \OC::$server->getLogger()->logException($e, [
334
+                'level' => \OCP\Util::ERROR,
335
+                'app' => 'files_external',
336
+            ]);
337
+            return false;
338
+        }
339
+
340
+        $dateTime = $object->lastModified ? \DateTime::createFromFormat(\DateTime::RFC1123, $object->lastModified) : false;
341
+        $mtime = $dateTime ? $dateTime->getTimestamp() : null;
342
+        $objectMetadata = $object->getMetadata();
343
+        if (isset($objectMetadata['timestamp'])) {
344
+            $mtime = $objectMetadata['timestamp'];
345
+        }
346
+
347
+        if (!empty($mtime)) {
348
+            $mtime = floor($mtime);
349
+        }
350
+
351
+        $stat = array();
352
+        $stat['size'] = (int)$object->contentLength;
353
+        $stat['mtime'] = $mtime;
354
+        $stat['atime'] = time();
355
+        return $stat;
356
+    }
357
+
358
+    public function filetype($path) {
359
+        $path = $this->normalizePath($path);
360
+
361
+        if ($path !== '.' && $this->doesObjectExist($path)) {
362
+            return 'file';
363
+        }
364
+
365
+        if ($path !== '.') {
366
+            $path .= '/';
367
+        }
368
+
369
+        if ($this->doesObjectExist($path)) {
370
+            return 'dir';
371
+        }
372
+    }
373
+
374
+    public function unlink($path) {
375
+        $path = $this->normalizePath($path);
376
+
377
+        if ($this->is_dir($path)) {
378
+            return $this->rmdir($path);
379
+        }
380
+
381
+        try {
382
+            $this->objectStore->deleteObject($path);
383
+            $this->objectCache->remove($path);
384
+            $this->objectCache->remove($path . '/');
385
+        } catch (BadResponseError $e) {
386
+            if ($e->getResponse()->getStatusCode() !== 404) {
387
+                \OC::$server->getLogger()->logException($e, [
388
+                    'level' => \OCP\Util::ERROR,
389
+                    'app' => 'files_external',
390
+                ]);
391
+                throw $e;
392
+            }
393
+        }
394
+
395
+        return true;
396
+    }
397
+
398
+    public function fopen($path, $mode) {
399
+        $path = $this->normalizePath($path);
400
+
401
+        switch ($mode) {
402
+            case 'a':
403
+            case 'ab':
404
+            case 'a+':
405
+                return false;
406
+            case 'r':
407
+            case 'rb':
408
+                try {
409
+                    return $this->objectStore->readObject($path);
410
+                } catch (BadResponseError $e) {
411
+                    \OC::$server->getLogger()->logException($e, [
412
+                        'level' => \OCP\Util::ERROR,
413
+                        'app' => 'files_external',
414
+                    ]);
415
+                    return false;
416
+                }
417
+            case 'w':
418
+            case 'wb':
419
+            case 'r+':
420
+            case 'w+':
421
+            case 'wb+':
422
+            case 'x':
423
+            case 'x+':
424
+            case 'c':
425
+            case 'c+':
426
+                if (strrpos($path, '.') !== false) {
427
+                    $ext = substr($path, strrpos($path, '.'));
428
+                } else {
429
+                    $ext = '';
430
+                }
431
+                $tmpFile = \OCP\Files::tmpFile($ext);
432
+                // Fetch existing file if required
433
+                if ($mode[0] !== 'w' && $this->file_exists($path)) {
434
+                    if ($mode[0] === 'x') {
435
+                        // File cannot already exist
436
+                        return false;
437
+                    }
438
+                    $source = $this->fopen($path, 'r');
439
+                    file_put_contents($tmpFile, $source);
440
+                }
441
+                $handle = fopen($tmpFile, $mode);
442
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
443
+                    $this->writeBack($tmpFile, $path);
444
+                });
445
+        }
446
+    }
447
+
448
+    public function touch($path, $mtime = null) {
449
+        $path = $this->normalizePath($path);
450
+        if (is_null($mtime)) {
451
+            $mtime = time();
452
+        }
453
+        $metadata = ['timestamp' => $mtime];
454
+        if ($this->file_exists($path)) {
455
+            if ($this->is_dir($path) && $path !== '.') {
456
+                $path .= '/';
457
+            }
458
+
459
+            $object = $this->fetchObject($path);
460
+            if ($object->mergeMetadata($metadata)) {
461
+                // invalidate target object to force repopulation on fetch
462
+                $this->objectCache->remove($path);
463
+            }
464
+            return true;
465
+        } else {
466
+            $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
467
+            $this->getContainer()->createObject([
468
+                'name' => $path,
469
+                'content' => '',
470
+                'headers' => ['content-type' => 'httpd/unix-directory']
471
+            ]);
472
+            // invalidate target object to force repopulation on fetch
473
+            $this->objectCache->remove($path);
474
+            return true;
475
+        }
476
+    }
477
+
478
+    public function copy($path1, $path2) {
479
+        $path1 = $this->normalizePath($path1);
480
+        $path2 = $this->normalizePath($path2);
481
+
482
+        $fileType = $this->filetype($path1);
483
+        if ($fileType) {
484
+            // make way
485
+            $this->unlink($path2);
486
+        }
487
+
488
+        if ($fileType === 'file') {
489
+            try {
490
+                $source = $this->fetchObject($path1);
491
+                $source->copy([
492
+                    'destination' => $this->bucket . '/' . $path2
493
+                ]);
494
+                // invalidate target object to force repopulation on fetch
495
+                $this->objectCache->remove($path2);
496
+                $this->objectCache->remove($path2 . '/');
497
+            } catch (BadResponseError $e) {
498
+                \OC::$server->getLogger()->logException($e, [
499
+                    'level' => \OCP\Util::ERROR,
500
+                    'app' => 'files_external',
501
+                ]);
502
+                return false;
503
+            }
504
+
505
+        } else if ($fileType === 'dir') {
506
+            try {
507
+                $source = $this->fetchObject($path1 . '/');
508
+                $source->copy([
509
+                    'destination' => $this->bucket . '/' . $path2 . '/'
510
+                ]);
511
+                // invalidate target object to force repopulation on fetch
512
+                $this->objectCache->remove($path2);
513
+                $this->objectCache->remove($path2 . '/');
514
+            } catch (BadResponseError $e) {
515
+                \OC::$server->getLogger()->logException($e, [
516
+                    'level' => \OCP\Util::ERROR,
517
+                    'app' => 'files_external',
518
+                ]);
519
+                return false;
520
+            }
521
+
522
+            $dh = $this->opendir($path1);
523
+            while ($file = readdir($dh)) {
524
+                if (\OC\Files\Filesystem::isIgnoredDir($file)) {
525
+                    continue;
526
+                }
527
+
528
+                $source = $path1 . '/' . $file;
529
+                $target = $path2 . '/' . $file;
530
+                $this->copy($source, $target);
531
+            }
532
+
533
+        } else {
534
+            //file does not exist
535
+            return false;
536
+        }
537
+
538
+        return true;
539
+    }
540
+
541
+    public function rename($path1, $path2) {
542
+        $path1 = $this->normalizePath($path1);
543
+        $path2 = $this->normalizePath($path2);
544
+
545
+        $fileType = $this->filetype($path1);
546
+
547
+        if ($fileType === 'dir' || $fileType === 'file') {
548
+            // copy
549
+            if ($this->copy($path1, $path2) === false) {
550
+                return false;
551
+            }
552
+
553
+            // cleanup
554
+            if ($this->unlink($path1) === false) {
555
+                throw new \Exception('failed to remove original');
556
+                $this->unlink($path2);
557
+                return false;
558
+            }
559
+
560
+            return true;
561
+        }
562
+
563
+        return false;
564
+    }
565
+
566
+    public function getId() {
567
+        return $this->id;
568
+    }
569
+
570
+    /**
571
+     * Returns the initialized object store container.
572
+     *
573
+     * @return \OpenStack\ObjectStore\v1\Models\Container
574
+     * @throws \OCP\Files\StorageAuthException
575
+     * @throws \OCP\Files\StorageNotAvailableException
576
+     */
577
+    public function getContainer() {
578
+        if (is_null($this->container)) {
579
+            $this->container = $this->connectionFactory->getContainer();
580
+
581
+            if (!$this->file_exists('.')) {
582
+                $this->mkdir('.');
583
+            }
584
+        }
585
+        return $this->container;
586
+    }
587
+
588
+    public function writeBack($tmpFile, $path) {
589
+        $fileData = fopen($tmpFile, 'r');
590
+        $this->objectStore->writeObject($path, $fileData);
591
+        // invalidate target object to force repopulation on fetch
592
+        $this->objectCache->remove($path);
593
+        unlink($tmpFile);
594
+    }
595
+
596
+    public function hasUpdated($path, $time) {
597
+        if ($this->is_file($path)) {
598
+            return parent::hasUpdated($path, $time);
599
+        }
600
+        $path = $this->normalizePath($path);
601
+        $dh = $this->opendir($path);
602
+        $content = array();
603
+        while (($file = readdir($dh)) !== false) {
604
+            $content[] = $file;
605
+        }
606
+        if ($path === '.') {
607
+            $path = '';
608
+        }
609
+        $cachedContent = $this->getCache()->getFolderContents($path);
610
+        $cachedNames = array_map(function ($content) {
611
+            return $content['name'];
612
+        }, $cachedContent);
613
+        sort($cachedNames);
614
+        sort($content);
615
+        return $cachedNames !== $content;
616
+    }
617
+
618
+    /**
619
+     * check if curl is installed
620
+     */
621
+    public static function checkDependencies() {
622
+        return true;
623
+    }
624 624
 
625 625
 }
Please login to merge, or discard this patch.
lib/private/Files/ObjectStore/SwiftFactory.php 2 patches
Indentation   +168 added lines, -168 removed lines patch added patch discarded remove patch
@@ -41,172 +41,172 @@
 block discarded – undo
41 41
 use OpenStack\ObjectStore\v1\Models\Container;
42 42
 
43 43
 class SwiftFactory {
44
-	private $cache;
45
-	private $params;
46
-	/** @var Container|null */
47
-	private $container = null;
48
-	private $logger;
49
-
50
-	public function __construct(ICache $cache, array $params, ILogger $logger) {
51
-		$this->cache = $cache;
52
-		$this->params = $params;
53
-		$this->logger = $logger;
54
-	}
55
-
56
-	private function getCachedToken(string $cacheKey) {
57
-		$cachedTokenString = $this->cache->get($cacheKey . '/token');
58
-		if ($cachedTokenString) {
59
-			return json_decode($cachedTokenString);
60
-		} else {
61
-			return null;
62
-		}
63
-	}
64
-
65
-	private function cacheToken(Token $token, string $cacheKey) {
66
-		if ($token instanceof \OpenStack\Identity\v3\Models\Token) {
67
-			$value = json_encode($token->export());
68
-		} else {
69
-			$value = json_encode($token);
70
-		}
71
-		$this->cache->set($cacheKey . '/token', $value);
72
-	}
73
-
74
-	/**
75
-	 * @return OpenStack
76
-	 * @throws StorageAuthException
77
-	 */
78
-	private function getClient() {
79
-		if (isset($this->params['bucket'])) {
80
-			$this->params['container'] = $this->params['bucket'];
81
-		}
82
-		if (!isset($this->params['container'])) {
83
-			$this->params['container'] = 'nextcloud';
84
-		}
85
-		if (!isset($this->params['autocreate'])) {
86
-			// should only be true for tests
87
-			$this->params['autocreate'] = false;
88
-		}
89
-		if (isset($this->params['user']) && is_array($this->params['user'])) {
90
-			$userName = $this->params['user']['name'];
91
-		} else {
92
-			if (!isset($this->params['username']) && isset($this->params['user'])) {
93
-				$this->params['username'] = $this->params['user'];
94
-			}
95
-			$userName = $this->params['username'];
96
-		}
97
-		if (!isset($this->params['tenantName']) && isset($this->params['tenant'])) {
98
-			$this->params['tenantName'] = $this->params['tenant'];
99
-		}
100
-
101
-		$cacheKey = $userName . '@' . $this->params['url'] . '/' . $this->params['container'];
102
-		$token = $this->getCachedToken($cacheKey);
103
-		$this->params['cachedToken'] = $token;
104
-
105
-		$httpClient = new Client([
106
-			'base_uri' => TransportUtils::normalizeUrl($this->params['url']),
107
-			'handler' => HandlerStack::create()
108
-		]);
109
-
110
-		if (isset($this->params['user']) && isset($this->params['user']['name'])) {
111
-			return $this->auth(IdentityV3Service::factory($httpClient), $cacheKey);
112
-		} else {
113
-			return $this->auth(IdentityV2Service::factory($httpClient), $cacheKey);
114
-		}
115
-	}
116
-
117
-	/**
118
-	 * @param IdentityV2Service|IdentityV3Service $authService
119
-	 * @param string $cacheKey
120
-	 * @return OpenStack
121
-	 * @throws StorageAuthException
122
-	 */
123
-	private function auth($authService, string $cacheKey) {
124
-		$this->params['identityService'] = $authService;
125
-		$this->params['authUrl'] = $this->params['url'];
126
-		$client = new OpenStack($this->params);
127
-
128
-		$cachedToken = $this->params['cachedToken'];
129
-		$hasValidCachedToken = false;
130
-		if (is_array($cachedToken)) {
131
-			$token = $authService->generateTokenFromCache($cachedToken);
132
-			if (is_null($token->catalog)) {
133
-				$this->logger->warning('Invalid cached token for swift, no catalog set: ' . json_encode($cachedToken));
134
-			} else if ($token->hasExpired()) {
135
-				$this->logger->debug('Cached token for swift expired');
136
-			} else {
137
-				$hasValidCachedToken = true;
138
-			}
139
-		}
140
-
141
-		if (!$hasValidCachedToken) {
142
-			try {
143
-				$token = $authService->generateToken($this->params);
144
-				$this->cacheToken($token, $cacheKey);
145
-			} catch (ConnectException $e) {
146
-				throw new StorageAuthException('Failed to connect to keystone, verify the keystone url', $e);
147
-			} catch (ClientException $e) {
148
-				$statusCode = $e->getResponse()->getStatusCode();
149
-				if ($statusCode === 404) {
150
-					throw new StorageAuthException('Keystone not found, verify the keystone url', $e);
151
-				} else if ($statusCode === 412) {
152
-					throw new StorageAuthException('Precondition failed, verify the keystone url', $e);
153
-				} else if ($statusCode === 401) {
154
-					throw new StorageAuthException('Authentication failed, verify the username, password and possibly tenant', $e);
155
-				} else {
156
-					throw new StorageAuthException('Unknown error', $e);
157
-				}
158
-			} catch (RequestException $e) {
159
-				throw new StorageAuthException('Connection reset while connecting to keystone, verify the keystone url', $e);
160
-			}
161
-		}
162
-
163
-		return $client;
164
-	}
165
-
166
-	/**
167
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
168
-	 * @throws StorageAuthException
169
-	 * @throws StorageNotAvailableException
170
-	 */
171
-	public function getContainer() {
172
-		if (is_null($this->container)) {
173
-			$this->container = $this->createContainer();
174
-		}
175
-
176
-		return $this->container;
177
-	}
178
-
179
-	/**
180
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
181
-	 * @throws StorageAuthException
182
-	 * @throws StorageNotAvailableException
183
-	 */
184
-	private function createContainer() {
185
-		$client = $this->getClient();
186
-		$objectStoreService = $client->objectStoreV1();
187
-
188
-		$autoCreate = isset($this->params['autocreate']) && $this->params['autocreate'] === true;
189
-		try {
190
-			$container = $objectStoreService->getContainer($this->params['container']);
191
-			if ($autoCreate) {
192
-				$container->getMetadata();
193
-			}
194
-			return $container;
195
-		} catch (BadResponseError $ex) {
196
-			// if the container does not exist and autocreate is true try to create the container on the fly
197
-			if ($ex->getResponse()->getStatusCode() === 404 && $autoCreate) {
198
-				return $objectStoreService->createContainer([
199
-					'name' => $this->params['container']
200
-				]);
201
-			} else {
202
-				throw new StorageNotAvailableException('Invalid response while trying to get container info', StorageNotAvailableException::STATUS_ERROR, $e);
203
-			}
204
-		} catch (ConnectException $e) {
205
-			/** @var RequestInterface $request */
206
-			$request = $e->getRequest();
207
-			$host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort();
208
-			\OC::$server->getLogger()->error("Can't connect to object storage server at $host");
209
-			throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e);
210
-		}
211
-	}
44
+    private $cache;
45
+    private $params;
46
+    /** @var Container|null */
47
+    private $container = null;
48
+    private $logger;
49
+
50
+    public function __construct(ICache $cache, array $params, ILogger $logger) {
51
+        $this->cache = $cache;
52
+        $this->params = $params;
53
+        $this->logger = $logger;
54
+    }
55
+
56
+    private function getCachedToken(string $cacheKey) {
57
+        $cachedTokenString = $this->cache->get($cacheKey . '/token');
58
+        if ($cachedTokenString) {
59
+            return json_decode($cachedTokenString);
60
+        } else {
61
+            return null;
62
+        }
63
+    }
64
+
65
+    private function cacheToken(Token $token, string $cacheKey) {
66
+        if ($token instanceof \OpenStack\Identity\v3\Models\Token) {
67
+            $value = json_encode($token->export());
68
+        } else {
69
+            $value = json_encode($token);
70
+        }
71
+        $this->cache->set($cacheKey . '/token', $value);
72
+    }
73
+
74
+    /**
75
+     * @return OpenStack
76
+     * @throws StorageAuthException
77
+     */
78
+    private function getClient() {
79
+        if (isset($this->params['bucket'])) {
80
+            $this->params['container'] = $this->params['bucket'];
81
+        }
82
+        if (!isset($this->params['container'])) {
83
+            $this->params['container'] = 'nextcloud';
84
+        }
85
+        if (!isset($this->params['autocreate'])) {
86
+            // should only be true for tests
87
+            $this->params['autocreate'] = false;
88
+        }
89
+        if (isset($this->params['user']) && is_array($this->params['user'])) {
90
+            $userName = $this->params['user']['name'];
91
+        } else {
92
+            if (!isset($this->params['username']) && isset($this->params['user'])) {
93
+                $this->params['username'] = $this->params['user'];
94
+            }
95
+            $userName = $this->params['username'];
96
+        }
97
+        if (!isset($this->params['tenantName']) && isset($this->params['tenant'])) {
98
+            $this->params['tenantName'] = $this->params['tenant'];
99
+        }
100
+
101
+        $cacheKey = $userName . '@' . $this->params['url'] . '/' . $this->params['container'];
102
+        $token = $this->getCachedToken($cacheKey);
103
+        $this->params['cachedToken'] = $token;
104
+
105
+        $httpClient = new Client([
106
+            'base_uri' => TransportUtils::normalizeUrl($this->params['url']),
107
+            'handler' => HandlerStack::create()
108
+        ]);
109
+
110
+        if (isset($this->params['user']) && isset($this->params['user']['name'])) {
111
+            return $this->auth(IdentityV3Service::factory($httpClient), $cacheKey);
112
+        } else {
113
+            return $this->auth(IdentityV2Service::factory($httpClient), $cacheKey);
114
+        }
115
+    }
116
+
117
+    /**
118
+     * @param IdentityV2Service|IdentityV3Service $authService
119
+     * @param string $cacheKey
120
+     * @return OpenStack
121
+     * @throws StorageAuthException
122
+     */
123
+    private function auth($authService, string $cacheKey) {
124
+        $this->params['identityService'] = $authService;
125
+        $this->params['authUrl'] = $this->params['url'];
126
+        $client = new OpenStack($this->params);
127
+
128
+        $cachedToken = $this->params['cachedToken'];
129
+        $hasValidCachedToken = false;
130
+        if (is_array($cachedToken)) {
131
+            $token = $authService->generateTokenFromCache($cachedToken);
132
+            if (is_null($token->catalog)) {
133
+                $this->logger->warning('Invalid cached token for swift, no catalog set: ' . json_encode($cachedToken));
134
+            } else if ($token->hasExpired()) {
135
+                $this->logger->debug('Cached token for swift expired');
136
+            } else {
137
+                $hasValidCachedToken = true;
138
+            }
139
+        }
140
+
141
+        if (!$hasValidCachedToken) {
142
+            try {
143
+                $token = $authService->generateToken($this->params);
144
+                $this->cacheToken($token, $cacheKey);
145
+            } catch (ConnectException $e) {
146
+                throw new StorageAuthException('Failed to connect to keystone, verify the keystone url', $e);
147
+            } catch (ClientException $e) {
148
+                $statusCode = $e->getResponse()->getStatusCode();
149
+                if ($statusCode === 404) {
150
+                    throw new StorageAuthException('Keystone not found, verify the keystone url', $e);
151
+                } else if ($statusCode === 412) {
152
+                    throw new StorageAuthException('Precondition failed, verify the keystone url', $e);
153
+                } else if ($statusCode === 401) {
154
+                    throw new StorageAuthException('Authentication failed, verify the username, password and possibly tenant', $e);
155
+                } else {
156
+                    throw new StorageAuthException('Unknown error', $e);
157
+                }
158
+            } catch (RequestException $e) {
159
+                throw new StorageAuthException('Connection reset while connecting to keystone, verify the keystone url', $e);
160
+            }
161
+        }
162
+
163
+        return $client;
164
+    }
165
+
166
+    /**
167
+     * @return \OpenStack\ObjectStore\v1\Models\Container
168
+     * @throws StorageAuthException
169
+     * @throws StorageNotAvailableException
170
+     */
171
+    public function getContainer() {
172
+        if (is_null($this->container)) {
173
+            $this->container = $this->createContainer();
174
+        }
175
+
176
+        return $this->container;
177
+    }
178
+
179
+    /**
180
+     * @return \OpenStack\ObjectStore\v1\Models\Container
181
+     * @throws StorageAuthException
182
+     * @throws StorageNotAvailableException
183
+     */
184
+    private function createContainer() {
185
+        $client = $this->getClient();
186
+        $objectStoreService = $client->objectStoreV1();
187
+
188
+        $autoCreate = isset($this->params['autocreate']) && $this->params['autocreate'] === true;
189
+        try {
190
+            $container = $objectStoreService->getContainer($this->params['container']);
191
+            if ($autoCreate) {
192
+                $container->getMetadata();
193
+            }
194
+            return $container;
195
+        } catch (BadResponseError $ex) {
196
+            // if the container does not exist and autocreate is true try to create the container on the fly
197
+            if ($ex->getResponse()->getStatusCode() === 404 && $autoCreate) {
198
+                return $objectStoreService->createContainer([
199
+                    'name' => $this->params['container']
200
+                ]);
201
+            } else {
202
+                throw new StorageNotAvailableException('Invalid response while trying to get container info', StorageNotAvailableException::STATUS_ERROR, $e);
203
+            }
204
+        } catch (ConnectException $e) {
205
+            /** @var RequestInterface $request */
206
+            $request = $e->getRequest();
207
+            $host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort();
208
+            \OC::$server->getLogger()->error("Can't connect to object storage server at $host");
209
+            throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e);
210
+        }
211
+    }
212 212
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -1,5 +1,5 @@  discard block
 block discarded – undo
1 1
 <?php
2
-declare(strict_types=1);
2
+declare(strict_types = 1);
3 3
 /**
4 4
  * @copyright Copyright (c) 2018 Robin Appelman <[email protected]>
5 5
  *
@@ -54,7 +54,7 @@  discard block
 block discarded – undo
54 54
 	}
55 55
 
56 56
 	private function getCachedToken(string $cacheKey) {
57
-		$cachedTokenString = $this->cache->get($cacheKey . '/token');
57
+		$cachedTokenString = $this->cache->get($cacheKey.'/token');
58 58
 		if ($cachedTokenString) {
59 59
 			return json_decode($cachedTokenString);
60 60
 		} else {
@@ -68,7 +68,7 @@  discard block
 block discarded – undo
68 68
 		} else {
69 69
 			$value = json_encode($token);
70 70
 		}
71
-		$this->cache->set($cacheKey . '/token', $value);
71
+		$this->cache->set($cacheKey.'/token', $value);
72 72
 	}
73 73
 
74 74
 	/**
@@ -98,7 +98,7 @@  discard block
 block discarded – undo
98 98
 			$this->params['tenantName'] = $this->params['tenant'];
99 99
 		}
100 100
 
101
-		$cacheKey = $userName . '@' . $this->params['url'] . '/' . $this->params['container'];
101
+		$cacheKey = $userName.'@'.$this->params['url'].'/'.$this->params['container'];
102 102
 		$token = $this->getCachedToken($cacheKey);
103 103
 		$this->params['cachedToken'] = $token;
104 104
 
@@ -130,7 +130,7 @@  discard block
 block discarded – undo
130 130
 		if (is_array($cachedToken)) {
131 131
 			$token = $authService->generateTokenFromCache($cachedToken);
132 132
 			if (is_null($token->catalog)) {
133
-				$this->logger->warning('Invalid cached token for swift, no catalog set: ' . json_encode($cachedToken));
133
+				$this->logger->warning('Invalid cached token for swift, no catalog set: '.json_encode($cachedToken));
134 134
 			} else if ($token->hasExpired()) {
135 135
 				$this->logger->debug('Cached token for swift expired');
136 136
 			} else {
@@ -204,7 +204,7 @@  discard block
 block discarded – undo
204 204
 		} catch (ConnectException $e) {
205 205
 			/** @var RequestInterface $request */
206 206
 			$request = $e->getRequest();
207
-			$host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort();
207
+			$host = $request->getUri()->getHost().':'.$request->getUri()->getPort();
208 208
 			\OC::$server->getLogger()->error("Can't connect to object storage server at $host");
209 209
 			throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e);
210 210
 		}
Please login to merge, or discard this patch.
lib/private/Files/ObjectStore/Swift.php 1 patch
Indentation   +85 added lines, -85 removed lines patch added patch discarded remove patch
@@ -31,90 +31,90 @@
 block discarded – undo
31 31
 use OCP\Files\StorageAuthException;
32 32
 
33 33
 class Swift implements IObjectStore {
34
-	/**
35
-	 * @var array
36
-	 */
37
-	private $params;
38
-
39
-	/** @var SwiftFactory */
40
-	private $swiftFactory;
41
-
42
-	public function __construct($params, SwiftFactory $connectionFactory = null) {
43
-		$this->swiftFactory = $connectionFactory ?: new SwiftFactory(
44
-			\OC::$server->getMemCacheFactory()->createDistributed('swift::'),
45
-			$params,
46
-			\OC::$server->getLogger()
47
-		);
48
-		$this->params = $params;
49
-	}
50
-
51
-	/**
52
-	 * @return \OpenStack\ObjectStore\v1\Models\Container
53
-	 * @throws StorageAuthException
54
-	 * @throws \OCP\Files\StorageNotAvailableException
55
-	 */
56
-	private function getContainer() {
57
-		return $this->swiftFactory->getContainer();
58
-	}
59
-
60
-	/**
61
-	 * @return string the container name where objects are stored
62
-	 */
63
-	public function getStorageId() {
64
-		if (isset($this->params['bucket'])) {
65
-			return $this->params['bucket'];
66
-		}
67
-
68
-		return $this->params['container'];
69
-	}
70
-
71
-	/**
72
-	 * @param string $urn the unified resource name used to identify the object
73
-	 * @param resource $stream stream with the data to write
74
-	 * @throws \Exception from openstack lib when something goes wrong
75
-	 */
76
-	public function writeObject($urn, $stream) {
77
-		$this->getContainer()->createObject([
78
-			'name' => $urn,
79
-			'stream' => stream_for($stream)
80
-		]);
81
-	}
82
-
83
-	/**
84
-	 * @param string $urn the unified resource name used to identify the object
85
-	 * @return resource stream with the read data
86
-	 * @throws \Exception from openstack lib when something goes wrong
87
-	 */
88
-	public function readObject($urn) {
89
-		$object = $this->getContainer()->getObject($urn);
90
-
91
-		// we need to keep a reference to objectContent or
92
-		// the stream will be closed before we can do anything with it
93
-		$objectContent = $object->download();
94
-		$objectContent->rewind();
95
-
96
-		$stream = $objectContent->detach();
97
-		// save the object content in the context of the stream to prevent it being gc'd until the stream is closed
98
-		stream_context_set_option($stream, 'swift', 'content', $objectContent);
99
-
100
-		return RetryWrapper::wrap($stream);
101
-	}
102
-
103
-	/**
104
-	 * @param string $urn Unified Resource Name
105
-	 * @return void
106
-	 * @throws \Exception from openstack lib when something goes wrong
107
-	 */
108
-	public function deleteObject($urn) {
109
-		$this->getContainer()->getObject($urn)->delete();
110
-	}
111
-
112
-	/**
113
-	 * @return void
114
-	 * @throws \Exception from openstack lib when something goes wrong
115
-	 */
116
-	public function deleteContainer() {
117
-		$this->getContainer()->delete();
118
-	}
34
+    /**
35
+     * @var array
36
+     */
37
+    private $params;
38
+
39
+    /** @var SwiftFactory */
40
+    private $swiftFactory;
41
+
42
+    public function __construct($params, SwiftFactory $connectionFactory = null) {
43
+        $this->swiftFactory = $connectionFactory ?: new SwiftFactory(
44
+            \OC::$server->getMemCacheFactory()->createDistributed('swift::'),
45
+            $params,
46
+            \OC::$server->getLogger()
47
+        );
48
+        $this->params = $params;
49
+    }
50
+
51
+    /**
52
+     * @return \OpenStack\ObjectStore\v1\Models\Container
53
+     * @throws StorageAuthException
54
+     * @throws \OCP\Files\StorageNotAvailableException
55
+     */
56
+    private function getContainer() {
57
+        return $this->swiftFactory->getContainer();
58
+    }
59
+
60
+    /**
61
+     * @return string the container name where objects are stored
62
+     */
63
+    public function getStorageId() {
64
+        if (isset($this->params['bucket'])) {
65
+            return $this->params['bucket'];
66
+        }
67
+
68
+        return $this->params['container'];
69
+    }
70
+
71
+    /**
72
+     * @param string $urn the unified resource name used to identify the object
73
+     * @param resource $stream stream with the data to write
74
+     * @throws \Exception from openstack lib when something goes wrong
75
+     */
76
+    public function writeObject($urn, $stream) {
77
+        $this->getContainer()->createObject([
78
+            'name' => $urn,
79
+            'stream' => stream_for($stream)
80
+        ]);
81
+    }
82
+
83
+    /**
84
+     * @param string $urn the unified resource name used to identify the object
85
+     * @return resource stream with the read data
86
+     * @throws \Exception from openstack lib when something goes wrong
87
+     */
88
+    public function readObject($urn) {
89
+        $object = $this->getContainer()->getObject($urn);
90
+
91
+        // we need to keep a reference to objectContent or
92
+        // the stream will be closed before we can do anything with it
93
+        $objectContent = $object->download();
94
+        $objectContent->rewind();
95
+
96
+        $stream = $objectContent->detach();
97
+        // save the object content in the context of the stream to prevent it being gc'd until the stream is closed
98
+        stream_context_set_option($stream, 'swift', 'content', $objectContent);
99
+
100
+        return RetryWrapper::wrap($stream);
101
+    }
102
+
103
+    /**
104
+     * @param string $urn Unified Resource Name
105
+     * @return void
106
+     * @throws \Exception from openstack lib when something goes wrong
107
+     */
108
+    public function deleteObject($urn) {
109
+        $this->getContainer()->getObject($urn)->delete();
110
+    }
111
+
112
+    /**
113
+     * @return void
114
+     * @throws \Exception from openstack lib when something goes wrong
115
+     */
116
+    public function deleteContainer() {
117
+        $this->getContainer()->delete();
118
+    }
119 119
 
120 120
 }
Please login to merge, or discard this patch.