Skip to content

Commit eb8148f

Browse files
committed
external folder download parts
1 parent a9d25e8 commit eb8148f

File tree

7 files changed

+188
-91
lines changed

7 files changed

+188
-91
lines changed

appinfo/routes.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
['name' => 'Remote#listRestoringPoint', 'url' => '/rp', 'verb' => 'GET'],
1717
['name' => 'Remote#getRestoringPoint', 'url' => '/rp/{pointId}', 'verb' => 'GET'],
1818
['name' => 'Remote#healthRestoringPoint', 'url' => '/rp/{pointId}/health', 'verb' => 'GET'],
19-
['name' => 'Remote#downloadRestoringPoint', 'url' => '/rp/{pointId}/download', 'verb' => 'GET'],
19+
['name' => 'Remote#downloadRestoringPoint', 'url' => '/rp/{pointId}/{chunkName}download', 'verb' => 'GET'],
2020
['name' => 'Remote#createRestoringPoint', 'url' => '/rp', 'verb' => 'PUT'],
2121
['name' => 'Remote#updateRestoringPoint', 'url' => '/rp/{pointId}', 'verb' => 'PUT'],
2222
// ['name' => 'Remote#uploadRestoringChunk', 'url' => '/rp/{pointId}', 'verb' => 'POST']

lib/Command/PointDownload.php

Lines changed: 130 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,30 @@
3636
use ArtificialOwl\MySmallPhpTools\Exceptions\SignatureException;
3737
use OC\Core\Command\Base;
3838
use OCA\Backup\Db\PointRequest;
39+
use OCA\Backup\Exceptions\ExternalFolderNotFoundException;
3940
use OCA\Backup\Exceptions\RemoteInstanceException;
4041
use OCA\Backup\Exceptions\RemoteInstanceNotFoundException;
4142
use OCA\Backup\Exceptions\RemoteResourceNotFoundException;
4243
use OCA\Backup\Exceptions\RestoringChunkNotFoundException;
44+
use OCA\Backup\Exceptions\RestoringChunkPartNotFoundException;
45+
use OCA\Backup\Exceptions\RestoringPointException;
4346
use OCA\Backup\Exceptions\RestoringPointNotFoundException;
47+
use OCA\Backup\Exceptions\RestoringPointNotInitiatedException;
48+
use OCA\Backup\Exceptions\RestoringPointPackException;
4449
use OCA\Backup\Model\ChunkPartHealth;
45-
use OCA\Backup\Model\RestoringHealth;
4650
use OCA\Backup\Model\RestoringPoint;
4751
use OCA\Backup\Service\ChunkService;
52+
use OCA\Backup\Service\ExternalFolderService;
4853
use OCA\Backup\Service\OutputService;
54+
use OCA\Backup\Service\PackService;
4955
use OCA\Backup\Service\PointService;
5056
use OCA\Backup\Service\RemoteService;
5157
use OCA\Backup\Service\RemoteStreamService;
58+
use OCP\Files\GenericFileException;
5259
use OCP\Files\NotFoundException;
5360
use OCP\Files\NotPermittedException;
61+
use OCP\Lock\LockedException;
62+
use Symfony\Component\Console\Exception\InvalidOptionException;
5463
use Symfony\Component\Console\Input\InputArgument;
5564
use Symfony\Component\Console\Input\InputInterface;
5665
use Symfony\Component\Console\Input\InputOption;
@@ -74,12 +83,18 @@ class PointDownload extends Base {
7483
/** @var ChunkService */
7584
private $chunkService;
7685

86+
/** @var PackService */
87+
private $packService;
88+
7789
/** @var RemoteStreamService */
7890
private $remoteStreamService;
7991

8092
/** @var RemoteService */
8193
private $remoteService;
8294

95+
/** @var ExternalFolderService */
96+
private $externalFolderService;
97+
8398
/** @var OutputService */
8499
private $outputService;
85100

@@ -90,25 +105,31 @@ class PointDownload extends Base {
90105
* @param PointRequest $pointRequest
91106
* @param PointService $pointService
92107
* @param ChunkService $chunkService
108+
* @param PackService $packService
93109
* @param RemoteStreamService $remoteStreamService
94110
* @param RemoteService $remoteService
111+
* @param ExternalFolderService $externalFolderService
95112
* @param OutputService $outputService
96113
*/
97114
public function __construct(
98115
PointRequest $pointRequest,
99116
PointService $pointService,
100117
ChunkService $chunkService,
118+
PackService $packService,
101119
RemoteStreamService $remoteStreamService,
102120
RemoteService $remoteService,
121+
ExternalFolderService $externalFolderService,
103122
OutputService $outputService
104123
) {
105124
parent::__construct();
106125

107126
$this->pointRequest = $pointRequest;
108127
$this->pointService = $pointService;
109128
$this->chunkService = $chunkService;
129+
$this->packService = $packService;
110130
$this->remoteStreamService = $remoteStreamService;
111131
$this->remoteService = $remoteService;
132+
$this->externalFolderService = $externalFolderService;
112133
$this->outputService = $outputService;
113134
}
114135

@@ -119,37 +140,48 @@ public function __construct(
119140
protected function configure() {
120141
$this->setName('backup:point:download')
121142
->setDescription('Download restoring point from remote instance')
122-
->addArgument('instance', InputArgument::REQUIRED, 'address of the remote instance')
123143
->addArgument('pointId', InputArgument::REQUIRED, 'Id of the restoring point')
124-
->addOption('no-check', '', InputOption::VALUE_NONE, 'do not check integrity of restoring point');
144+
->addOption('remote', '', InputOption::VALUE_REQUIRED, 'address of the remote instance')
145+
->addOption('external', '', InputOption::VALUE_REQUIRED, 'storageId of the external storage')
146+
->addOption(
147+
'no-check', '', InputOption::VALUE_NONE, 'do not check integrity of restoring point'
148+
);
125149
}
126150

127151

128152
/**
129153
* @param InputInterface $input
130154
* @param OutputInterface $output
131155
*
156+
* @return int
157+
* @throws ExternalFolderNotFoundException
158+
* @throws GenericFileException
132159
* @throws NotFoundException
133160
* @throws NotPermittedException
134161
* @throws RemoteInstanceException
135162
* @throws RemoteInstanceNotFoundException
136163
* @throws RemoteResourceNotFoundException
137164
* @throws RestoringChunkNotFoundException
165+
* @throws RestoringChunkPartNotFoundException
166+
* @throws RestoringPointException
138167
* @throws RestoringPointNotFoundException
139-
* @throws SignatureException
168+
* @throws RestoringPointPackException
140169
* @throws SignatoryException
170+
* @throws SignatureException
141171
*/
142-
protected function execute(InputInterface $input, OutputInterface $output) {
143-
$instance = $input->getArgument('instance');
172+
protected function execute(InputInterface $input, OutputInterface $output): int {
144173
$pointId = $input->getArgument('pointId');
174+
$remote = $input->getOption('remote');
175+
$external = (int)$input->getOption('external');
145176

146177
try {
147178
$point = $this->pointService->getRestoringPoint($pointId);
148179
$output->writeln('> found a local restoring point');
149180
} catch (RestoringPointNotFoundException $e) {
150181
$output->writeln('> downloading metadata');
151182

152-
$point = $this->remoteService->getRestoringPoint($instance, $pointId);
183+
$point = $this->getRestoringPoint($remote, $external, $pointId);
184+
// $point = $this->remoteService->getRestoringPoint($instance, $pointId);
153185
if (!$input->getOption('no-check')) {
154186
try {
155187
$this->remoteStreamService->verifyPoint($point);
@@ -161,8 +193,8 @@ protected function execute(InputInterface $input, OutputInterface $output) {
161193
}
162194
}
163195

164-
$point->unsetHealth()
165-
->setInstance('');
196+
$point->unsetHealth();
197+
// ->setInstance('');
166198

167199
$this->pointRequest->save($point);
168200
$this->pointService->saveMetadata($point);
@@ -172,7 +204,12 @@ protected function execute(InputInterface $input, OutputInterface $output) {
172204
$output->write('check health status: ');
173205
$this->pointService->generateHealth($point);
174206
$output->writeln($this->outputService->displayHealth($point));
175-
$this->downloadMissingFiles($instance, $point, $point->getHealth(), $output);
207+
$this->downloadMissingFiles($output, $remote, $external, $point);
208+
209+
return 0;
210+
// $this->downloadMissingFiles($instance, $point, $point->getHealth(), $output);
211+
212+
// $point = $this->getRestoringPoint($remote, $external, $pointId);
176213

177214

178215
// echo json_encode($point->getHealth());
@@ -211,40 +248,106 @@ protected function execute(InputInterface $input, OutputInterface $output) {
211248

212249

213250
/**
214-
* @param string $instance
215-
* @param RestoringPoint $point
216-
* @param RestoringHealth $health
217251
* @param OutputInterface $output
252+
* @param string|null $remote
253+
* @param int|null $external
254+
* @param RestoringPoint $point
218255
*
219-
* @throws NotFoundException
256+
* @throws ExternalFolderNotFoundException
257+
* @throws GenericFileException
220258
* @throws NotPermittedException
221259
* @throws RemoteInstanceException
222260
* @throws RemoteInstanceNotFoundException
223261
* @throws RemoteResourceNotFoundException
224262
* @throws RestoringChunkNotFoundException
263+
* @throws RestoringChunkPartNotFoundException
264+
* @throws RestoringPointException
265+
* @throws RestoringPointNotFoundException
266+
* @throws RestoringPointNotInitiatedException
267+
* @throws LockedException
225268
*/
226269
private function downloadMissingFiles(
227-
string $instance,
228-
RestoringPoint $point,
229-
RestoringHealth $health,
230-
OutputInterface $output
270+
OutputInterface $output,
271+
?string $remote,
272+
?int $external,
273+
RestoringPoint $point
231274
): void {
232-
foreach ($health->getParts() as $chunk) {
233-
if ($chunk->getStatus() === ChunkPartHealth::STATUS_OK) {
275+
$health = $point->getHealth();
276+
foreach ($health->getParts() as $partHealth) {
277+
if ($partHealth->getStatus() === ChunkPartHealth::STATUS_OK) {
234278
continue;
235279
}
236280

237-
$output->write(' * Downloading ' . $chunk->getDataName() . '/' . $chunk->getPartName() . ': ');
238-
$restoringChunk = $this->pointService->getChunkContent(
281+
$output->write(
282+
' * Downloading ' . $partHealth->getDataName() .
283+
'/' . $partHealth->getChunkName() . '/' . $partHealth->getPartName() . ': '
284+
);
285+
286+
$chunk = $this->chunkService->getChunkFromRP(
239287
$point,
240-
$chunk->getDataName(),
241-
$chunk->getPartName()
288+
$partHealth->getChunkName(),
289+
$partHealth->getDataName()
242290
);
243291

244-
$chunk = $this->remoteService->downloadChunk($instance, $point, $restoringChunk);
245-
$this->chunkService->saveChunkContent($point, $chunk);
292+
$part = clone $this->packService->getPartFromChunk($chunk, $partHealth->getPartName());
293+
// $this->packService->getChunkPartContent($point, $chunk, $part);
294+
//
295+
// $this->remoteService->uploadPart($instance, $point, $chunk, $part);
296+
297+
if (!is_null($remote)) {
298+
$this->remoteService->downloadPart($remote, $point, $chunk, $part);
299+
} else if ($external > 0) {
300+
$externalFolder = $this->externalFolderService->getByStorageId($external);
301+
$this->externalFolderService->downloadPart(
302+
$externalFolder,
303+
$point,
304+
$chunk,
305+
$part
306+
);
307+
} else {
308+
throw new InvalidOptionException('use --remote or --external');
309+
}
310+
311+
// $chunk = $this->remoteService->downloadChunk($instance, $point, $restoringChunk);
312+
$this->packService->saveChunkPartContent($point, $chunk, $part);
246313
$output->writeln('<info>ok</info>');
247314
}
248315
}
249-
}
250316

317+
318+
/**
319+
* @param string|null $remote
320+
* @param int|null $external
321+
* @param string $pointId
322+
*
323+
* @return RestoringPoint
324+
* @throws NotPermittedException
325+
* @throws RemoteInstanceException
326+
* @throws RemoteInstanceNotFoundException
327+
* @throws RemoteResourceNotFoundException
328+
* @throws RestoringPointNotFoundException
329+
* @throws ExternalFolderNotFoundException
330+
* @throws RestoringChunkPartNotFoundException
331+
* @throws RestoringPointException
332+
* @throws RestoringPointPackException
333+
* @throws GenericFileException
334+
*/
335+
private function getRestoringPoint(
336+
?string $remote,
337+
?int $external,
338+
string $pointId
339+
): RestoringPoint {
340+
if (!is_null($remote)) {
341+
return $this->remoteService->getRestoringPoint($remote, $pointId);
342+
}
343+
344+
if ($external > 0) {
345+
$externalFolder = $this->externalFolderService->getByStorageId($external);
346+
347+
return $this->externalFolderService->getRestoringPoint($externalFolder, $pointId);
348+
}
349+
350+
throw new InvalidOptionException('use --remote or --external');
351+
}
352+
353+
}

lib/Db/PointRequest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public function deletePoint(string $pointId): void {
100100

101101
$qb->andWhere(
102102
$qb->expr()->orX(
103-
$qb->exprLimit('point_id', $pointId),
103+
$qb->exprLimit('uid', $pointId),
104104
$qb->exprLimit('parent', $pointId)
105105
)
106106
);

lib/Service/ChunkService.php

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,10 @@ public function getDataWithChunk(RestoringPoint $point, string $chunk): Restorin
748748
* @return RestoringChunk
749749
* @throws RestoringChunkNotFoundException
750750
*/
751-
public function getChunkFromRP(RestoringPoint $point, string $chunk, string $dataName = ''
751+
public function getChunkFromRP(
752+
RestoringPoint $point,
753+
string $chunk,
754+
string $dataName = ''
752755
): RestoringChunk {
753756
foreach ($point->getRestoringData() as $restoringData) {
754757
if ($dataName !== '' && $restoringData->getName() !== $dataName) {
@@ -795,25 +798,6 @@ public function getChunkResource(RestoringPoint $point, RestoringChunk $chunk):
795798
}
796799

797800

798-
/**
799-
* @param RestoringPoint $point
800-
* @param RestoringChunk $chunk
801-
*/
802-
public function saveChunkContent(RestoringPoint $point, RestoringChunk $chunk) {
803-
$folder = $point->getBaseFolder();
804-
try {
805-
try {
806-
$file = $folder->getFile($chunk->getFilename());
807-
} catch (NotFoundException $e) {
808-
$file = $folder->newFile($chunk->getFilename());
809-
}
810-
811-
$file->putContent(base64_decode($chunk->getContent()));
812-
} catch (NotPermittedException | NotFoundException $e) {
813-
}
814-
}
815-
816-
817801
/**
818802
* @param RestoringPoint $point
819803
* @param RestoringChunk $chunk

lib/Service/ExternalFolderService.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,40 @@ public function uploadPart(
248248
$this->updateMetadataFile($external, $point);
249249
}
250250

251+
252+
/**
253+
* @param ExternalFolder $external
254+
* @param RestoringPoint $point
255+
* @param RestoringChunk $chunk
256+
* @param RestoringChunkPart $part
257+
*
258+
* @return RestoringChunkPart
259+
* @throws ExternalFolderNotFoundException
260+
* @throws GenericFileException
261+
* @throws LockedException
262+
* @throws NotPermittedException
263+
* @throws RestoringChunkPartNotFoundException
264+
* @throws RestoringPointException
265+
* @throws RestoringPointNotFoundException
266+
*/
267+
public function downloadPart(
268+
ExternalFolder $external,
269+
RestoringPoint $point,
270+
RestoringChunk $chunk,
271+
RestoringChunkPart $part
272+
): void {
273+
$folder = $this->getExternalChunkFolder($external, $point, $chunk, true);
274+
/** @var File $file */
275+
$file = $folder->get($part->getName());
276+
$file = $folder->get($part->getName());
277+
if ($file->getType() !== FileInfo::TYPE_FILE) {
278+
throw new RestoringChunkPartNotFoundException('remote part is not a file');
279+
}
280+
281+
$part->setContent(base64_encode($file->getContent()));
282+
}
283+
284+
251285
/**
252286
* @param ExternalFolder $external
253287
*
@@ -483,7 +517,7 @@ public function generateHealth(
483517
}
484518
}
485519
}
486-
520+
487521
if ($globalStatus === RestoringHealth::STATUS_OK && $point->getParent() !== '') {
488522
try {
489523
$this->getRestoringPoint($external, $point->getParent());

0 commit comments

Comments
 (0)