-
Notifications
You must be signed in to change notification settings - Fork 2
/
FileSystemStorageManager.php
121 lines (96 loc) · 3.75 KB
/
FileSystemStorageManager.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<?php
declare(strict_types = 1);
namespace Nepada\FileUploadControl\Storage;
use Nepada\FileUploadControl\Storage\Metadata\MetadataJournalProvider;
use Nepada\FileUploadControl\Utils\DateTimeProvider;
use Nepada\FileUploadControl\Utils\FileSystem;
use Nepada\FileUploadControl\Utils\Finder;
use Nepada\FileUploadControl\Utils\RandomProvider;
use Nette;
final class FileSystemStorageManager implements StorageManager
{
use Nette\SmartObject;
public const DEFAULT_TTL = Nette\Utils\DateTime::DAY;
private const NAMESPACE_DIRECTORY_SUFFIX = '-files';
private MetadataJournalProvider $metadataJournalProvider;
private FileSystem $fileSystem;
private Finder $finder;
private DateTimeProvider $dateTimeProvider;
private RandomProvider $randomProvider;
private string $directory;
private int $namespaceTtl;
private bool $garbageCollected = false;
public function __construct(
MetadataJournalProvider $metadataJournalProvider,
FileSystem $fileSystem,
Finder $finder,
DateTimeProvider $dateTimeProvider,
RandomProvider $randomProvider,
string $directory,
int $namespaceTtl = self::DEFAULT_TTL
)
{
$this->metadataJournalProvider = $metadataJournalProvider;
$this->fileSystem = $fileSystem;
$this->finder = $finder;
$this->dateTimeProvider = $dateTimeProvider;
$this->randomProvider = $randomProvider;
$this->directory = $directory;
$this->namespaceTtl = $namespaceTtl;
}
public function createNewNamespace(): UploadNamespace
{
$this->collectGarbage();
$namespace = UploadNamespace::generate($this->randomProvider);
$directory = $this->getUploadNamespaceDirectory($namespace);
$this->fileSystem->createDirectory($directory);
return $namespace;
}
/**
* @param UploadNamespace $namespace
* @return Storage
* @throws StorageDoesNotExistException
*/
public function getStorage(UploadNamespace $namespace): Storage
{
$this->collectGarbage();
$directory = $this->getUploadNamespaceDirectory($namespace);
if (! $this->fileSystem->directoryExists($directory)) {
throw StorageDoesNotExistException::withNamespace($namespace);
}
$metadataJournal = $this->metadataJournalProvider->get($namespace);
return new FileSystemStorage($metadataJournal, $this->fileSystem, $directory);
}
private function collectGarbage(): void
{
if ($this->garbageCollected) {
return;
}
$this->garbageCollected = true;
if (! $this->fileSystem->directoryExists($this->directory)) {
return;
}
$expiredNamespaces = [];
$currentTimestamp = $this->dateTimeProvider->getNow()->getTimestamp();
/** @var \SplFileInfo $directory */
foreach ($this->finder->findDirectoriesInDirectory($this->directory, '*' . self::NAMESPACE_DIRECTORY_SUFFIX) as $directory) {
$age = $currentTimestamp - $directory->getMTime();
if ($age < $this->namespaceTtl) {
continue;
}
$expiredNamespaces[] = UploadNamespace::fromString($directory->getBasename(self::NAMESPACE_DIRECTORY_SUFFIX));
}
foreach ($expiredNamespaces as $expiredNamespace) {
try {
$storage = $this->getStorage($expiredNamespace);
$storage->destroy();
} catch (StorageDoesNotExistException $exception) {
// noop
}
}
}
private function getUploadNamespaceDirectory(UploadNamespace $namespace): string
{
return $this->directory . DIRECTORY_SEPARATOR . $namespace->toString() . self::NAMESPACE_DIRECTORY_SUFFIX;
}
}