1
|
|
|
<?php |
2
|
|
|
namespace Tartana\Host; |
3
|
|
|
use GuzzleHttp\Promise\Promise; |
4
|
|
|
use Joomla\Registry\Registry; |
5
|
|
|
use League\Flysystem\Adapter\Local; |
6
|
|
|
use League\Flysystem\Filesystem; |
7
|
|
|
use League\Flysystem\MountManager; |
8
|
|
|
use Tartana\Domain\Command\SaveDownloads; |
9
|
|
|
use Tartana\Entity\Download; |
10
|
|
|
use Tartana\Mixins\CommandBusAwareTrait; |
11
|
|
|
use Tartana\Mixins\LoggerAwareTrait; |
12
|
|
|
use Tartana\Util; |
13
|
|
|
|
14
|
|
|
class Localhost implements HostInterface |
15
|
|
|
{ |
16
|
|
|
use LoggerAwareTrait; |
17
|
|
|
use CommandBusAwareTrait; |
18
|
|
|
|
19
|
|
|
private $configuration = null; |
20
|
|
|
|
21
|
|
|
private $manager = null; |
22
|
|
|
|
23
|
27 |
|
public function __construct (Registry $configuration = null, MountManager $manager = null) |
24
|
|
|
{ |
25
|
27 |
|
$this->configuration = $configuration; |
26
|
|
|
|
27
|
27 |
|
if (empty($manager)) |
28
|
|
|
{ |
29
|
16 |
|
$manager = new MountManager(); |
30
|
|
|
} |
31
|
27 |
|
$this->manager = $manager; |
32
|
27 |
|
} |
33
|
|
|
|
34
|
1 |
|
public function fetchLinkList ($link) |
35
|
|
|
{ |
36
|
|
|
return [ |
37
|
1 |
|
$link |
38
|
|
|
]; |
39
|
|
|
} |
40
|
|
|
|
41
|
3 |
|
public function fetchDownloadInfo (array $downloads) |
42
|
|
|
{ |
43
|
3 |
|
foreach ($downloads as $download) |
44
|
|
|
{ |
45
|
3 |
|
if ($download->getFileName()) |
46
|
|
|
{ |
47
|
1 |
|
continue; |
48
|
|
|
} |
49
|
|
|
|
50
|
2 |
|
$fs = $this->getSourceAdapter($download); |
51
|
2 |
|
if (! empty($fs)) |
52
|
|
|
{ |
53
|
1 |
|
$download->setFileName(basename($download->getLink())); |
54
|
|
|
|
55
|
1 |
|
if ($fs instanceof Local) |
56
|
|
|
{ |
57
|
1 |
|
$download->setHash(md5_file($download->getLink())); |
58
|
|
|
} |
59
|
|
|
} |
60
|
|
|
else |
61
|
|
|
{ |
62
|
1 |
|
$download->setMessage('TARTANA_DOWNLOAD_MESSAGE_INVALID_PATH'); |
63
|
2 |
|
$download->setState(Download::STATE_DOWNLOADING_ERROR); |
64
|
|
|
} |
65
|
|
|
} |
66
|
3 |
|
} |
67
|
|
|
|
68
|
22 |
|
public function download (array $downloads) |
69
|
|
|
{ |
70
|
22 |
|
$promises = []; |
71
|
22 |
|
foreach ($downloads as $download) |
72
|
|
|
{ |
73
|
21 |
|
$destination = Util::realPath($download->getDestination()); |
74
|
21 |
|
if (empty($destination)) |
|
|
|
|
75
|
|
|
{ |
76
|
1 |
|
$download->setMessage('TARTANA_DOWNLOAD_MESSAGE_INVALID_DESTINATION'); |
77
|
1 |
|
$download->setState(Download::STATE_DOWNLOADING_ERROR); |
78
|
1 |
|
$this->handleCommand(new SaveDownloads([ |
79
|
1 |
|
$download |
80
|
|
|
])); |
81
|
|
|
|
82
|
1 |
|
continue; |
83
|
|
|
} |
84
|
|
|
|
85
|
20 |
|
$src = $this->getSourceAdapter($download); |
86
|
20 |
|
if (empty($src)) |
|
|
|
|
87
|
|
|
{ |
88
|
4 |
|
$download->setMessage('TARTANA_DOWNLOAD_MESSAGE_INVALID_PATH'); |
89
|
4 |
|
$download->setState(Download::STATE_DOWNLOADING_ERROR); |
90
|
4 |
|
$this->handleCommand(new SaveDownloads([ |
91
|
4 |
|
$download |
92
|
|
|
])); |
93
|
4 |
|
continue; |
94
|
|
|
} |
95
|
|
|
|
96
|
17 |
|
$src = new Filesystem($src); |
97
|
17 |
|
$dest = new Filesystem(new Local($destination)); |
98
|
|
|
|
99
|
17 |
|
$manager = $this->manager; |
100
|
17 |
|
$manager->mountFilesystem('src-' . $download->getId(), $src); |
101
|
17 |
|
$manager->mountFilesystem('dst-' . $download->getId(), $dest); |
102
|
|
|
|
103
|
17 |
|
$promise = new Promise( |
104
|
17 |
|
function () use ( &$promise, $download, $manager) { |
105
|
17 |
|
$fileName = basename($download->getLink()); |
106
|
17 |
|
$destFileName = $download->getFileName() ? $download->getFileName() : $fileName; |
107
|
17 |
|
$id = $download->getId(); |
108
|
17 |
|
if (! @$manager->copy('src-' . $id . '://' . $fileName, 'dst-' . $id . '://' . $destFileName)) |
109
|
|
|
{ |
110
|
9 |
|
$download->setMessage('TARTANA_DOWNLOAD_MESSAGE_COPY_FAILED'); |
111
|
9 |
|
$download->setState(Download::STATE_DOWNLOADING_ERROR); |
112
|
|
|
} |
113
|
8 |
|
else if (! empty($download->getHash()) && $download->getHash() != md5_file( |
114
|
2 |
|
$manager->getFilesystem('dst-' . $id) |
115
|
2 |
|
->getAdapter() |
116
|
8 |
|
->applyPathPrefix($destFileName))) |
117
|
|
|
{ |
118
|
1 |
|
$download->setMessage('TARTANA_DOWNLOAD_MESSAGE_INVALID_HASH'); |
119
|
1 |
|
$download->setState(Download::STATE_DOWNLOADING_ERROR); |
120
|
|
|
|
121
|
1 |
|
if ($manager->has('dst-' . $id . '://' . $destFileName)) |
122
|
|
|
{ |
123
|
1 |
|
$manager->delete('dst-' . $id . '://' . $destFileName); |
124
|
|
|
} |
125
|
|
|
} |
126
|
|
|
else |
127
|
|
|
{ |
128
|
7 |
|
$download->setState(Download::STATE_DOWNLOADING_COMPLETED); |
129
|
|
|
} |
130
|
17 |
|
$download->setFinishedAt(new \DateTime()); |
131
|
|
|
|
132
|
17 |
|
$this->handleCommand(new SaveDownloads([ |
133
|
17 |
|
$download |
134
|
|
|
])); |
135
|
|
|
|
136
|
17 |
|
$promise->resolve(true); |
137
|
17 |
|
}); |
138
|
17 |
|
$promises[] = $promise; |
139
|
|
|
} |
140
|
|
|
|
141
|
22 |
|
return $promises; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Returns the source adapter to copy the download from. |
146
|
|
|
* If none can be created null is returned. |
147
|
|
|
* |
148
|
|
|
* @param Download $download |
149
|
|
|
* @return null|\League\Flysystem\AdapterInterface |
150
|
|
|
*/ |
151
|
12 |
|
protected function getSourceAdapter (Download $download) |
152
|
|
|
{ |
153
|
12 |
|
$uri = Util::parseUrl($download->getLink()); |
154
|
|
|
|
155
|
12 |
|
$path = Util::realPath($uri['path']); |
156
|
12 |
|
if (empty($path)) |
157
|
|
|
{ |
158
|
|
|
// Perhaps relative |
159
|
4 |
|
$path = Util::realPath(ltrim($uri['path'], '/')); |
160
|
4 |
|
if (empty($path)) |
161
|
|
|
{ |
162
|
3 |
|
return null; |
163
|
|
|
} |
164
|
|
|
} |
165
|
|
|
|
166
|
10 |
|
return new Local(dirname($path)); |
167
|
|
|
} |
168
|
|
|
|
169
|
6 |
|
protected function getConfiguration () |
170
|
|
|
{ |
171
|
6 |
|
return $this->configuration; |
172
|
|
|
} |
173
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.