From 2d230f7576b8f4bdf01e1c12dadff92c60ddad97 Mon Sep 17 00:00:00 2001 From: Mathieu De Keyzer Date: Thu, 19 Dec 2024 10:28:39 +0100 Subject: [PATCH] fix(common/storage): put zip archive in cache (#1108) --- .../LoadArchiveItemsInCacheCommand.php | 55 ++++++++++++++++++- .../src/Storage/StorageManager.php | 11 ++++ EMS/helpers/src/File/TempFile.php | 8 ++- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/EMS/common-bundle/src/Command/Storage/LoadArchiveItemsInCacheCommand.php b/EMS/common-bundle/src/Command/Storage/LoadArchiveItemsInCacheCommand.php index 0eec5dde4..bf20dd5dd 100644 --- a/EMS/common-bundle/src/Command/Storage/LoadArchiveItemsInCacheCommand.php +++ b/EMS/common-bundle/src/Command/Storage/LoadArchiveItemsInCacheCommand.php @@ -6,12 +6,18 @@ use EMS\CommonBundle\Commands; use EMS\CommonBundle\Common\Command\AbstractCommand; +use EMS\CommonBundle\Helper\MimeTypeHelper; use EMS\CommonBundle\Storage\Archive; use EMS\CommonBundle\Storage\StorageManager; +use EMS\Helpers\File\TempDirectory; +use EMS\Helpers\File\TempFile; +use EMS\Helpers\Html\MimeTypes; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Finder\Finder; +use Symfony\Component\Finder\SplFileInfo; class LoadArchiveItemsInCacheCommand extends AbstractCommand { @@ -47,7 +53,34 @@ protected function execute(InputInterface $input, OutputInterface $output): int { $this->io->title('Load archive\'s items in storage cache'); - $archive = Archive::fromStructure($this->storageManager->getContents($this->archiveHash), $this->storageManager->getHashAlgo()); + $this->io->section('Downloading archive'); + + $progressBar = $this->io->createProgressBar($this->storageManager->getSize($this->archiveHash)); + + $archiveFile = TempFile::create()->loadFromStream($this->storageManager->getStream($this->archiveHash), $this->output->isQuiet() ? null : function ($size) use ($progressBar): void { + $progressBar->advance($size); + }); + $mimeType = MimeTypeHelper::getInstance()->guessMimeType($archiveFile->path); + $this->io->newLine(); + + switch ($mimeType) { + case MimeTypes::APPLICATION_ZIP->value: + case MimeTypes::APPLICATION_GZIP->value: + $this->loadZipArchive($archiveFile); + break; + case MimeTypes::APPLICATION_JSON->value: + $this->loadEmsArchive($archiveFile); + break; + default: + throw new \RuntimeException(\sprintf('Archive format %s not supported', $mimeType)); + } + + return self::EXECUTE_SUCCESS; + } + + private function loadEmsArchive(TempFile $tempFile): void + { + $archive = Archive::fromStructure($tempFile->getContents(), $this->storageManager->getHashAlgo()); $progressBar = $this->io->createProgressBar($archive->getCount()); $this->storageManager->loadArchiveItemsInCache($this->archiveHash, $archive->skip($this->continue), $this->output->isQuiet() ? null : function () use ($progressBar) { $progressBar->advance(); @@ -55,7 +88,25 @@ protected function execute(InputInterface $input, OutputInterface $output): int $progressBar->finish(); $this->io->newLine(); $this->io->writeln(\sprintf('%d files have been pushed in cache', $archive->getCount())); + } - return self::EXECUTE_SUCCESS; + private function loadZipArchive(TempFile $archiveFile): void + { + $dir = TempDirectory::createFromZipArchive($archiveFile->path); + $archiveFile->clean(); + $finder = new Finder(); + $finder->in($dir->path)->files(); + $this->io->progressStart($finder->count()); + $mimeTypeHelper = MimeTypeHelper::getInstance(); + $counter = 0; + /** @var SplFileInfo $file */ + foreach ($finder as $file) { + $mimeType = $mimeTypeHelper->guessMimeType($file->getPathname()); + $counter += $this->storageManager->addFileInArchiveCache($this->archiveHash, $file, $mimeType) ? 1 : 0; + $this->io->progressAdvance(); + } + $this->io->progressFinish(); + $this->io->newLine(); + $this->io->writeln(\sprintf('%d files have been pushed in cache', $counter)); } } diff --git a/EMS/common-bundle/src/Storage/StorageManager.php b/EMS/common-bundle/src/Storage/StorageManager.php index 3c4f7a75c..1f56aa259 100644 --- a/EMS/common-bundle/src/Storage/StorageManager.php +++ b/EMS/common-bundle/src/Storage/StorageManager.php @@ -706,4 +706,15 @@ public function loadArchiveItemsInCache(string $archiveHash, Archive $archive, c } } } + + public function addFileInArchiveCache(string $hash, SplFileInfo $file, string $mimeType): bool + { + foreach ($this->adapters as $adapter) { + if ($adapter->addFileInArchiveCache($hash, $file, $mimeType)) { + return true; + } + } + + return false; + } } diff --git a/EMS/helpers/src/File/TempFile.php b/EMS/helpers/src/File/TempFile.php index 7e89a47d2..f5d11f115 100644 --- a/EMS/helpers/src/File/TempFile.php +++ b/EMS/helpers/src/File/TempFile.php @@ -45,16 +45,20 @@ public function exists(): bool return \file_exists($this->path); } - public function loadFromStream(StreamInterface $stream): self + public function loadFromStream(StreamInterface $stream, callable $callback = null): self { if (!$handle = \fopen($this->path, 'w')) { throw new \RuntimeException(\sprintf('Can\'t open a temporary file %s', $this->path)); } while (!$stream->eof()) { - if (false === \fwrite($handle, $stream->read(8192))) { + $size = \fwrite($handle, $stream->read(File::DEFAULT_CHUNK_SIZE)); + if (false === $size) { throw new \RuntimeException(\sprintf('Can\'t write in temporary file %s', $this->path)); } + if (null !== $callback) { + $callback($size); + } } if (false === \fclose($handle)) {