diff --git a/src/Command/Get.php b/src/Command/Get.php index caeb1ac..015780d 100644 --- a/src/Command/Get.php +++ b/src/Command/Get.php @@ -97,11 +97,12 @@ protected function execute( $downloader = $container->get(Downloader::class); $task = $downloader->download( $softwareCollection->findSoftware('rr') ?? throw new \RuntimeException('Software not found.'), - $container->get(Destination::class), // trap(...), static fn() => null, ); + // $container->get(Destination::class), + ($task->handler)(); // $repo = 'roadrunner-server/roadrunner'; diff --git a/src/Module/Downloader/Downloader.php b/src/Module/Downloader/Downloader.php index b1cf769..5ca8308 100644 --- a/src/Module/Downloader/Downloader.php +++ b/src/Module/Downloader/Downloader.php @@ -5,26 +5,25 @@ namespace Internal\DLoad\Module\Downloader; use Internal\DLoad\Module\Common\Architecture; -use Internal\DLoad\Module\Common\Config\Destination; use Internal\DLoad\Module\Common\Config\DownloaderConfig; use Internal\DLoad\Module\Common\Config\Embed\Software; use Internal\DLoad\Module\Common\OperatingSystem; use Internal\DLoad\Module\Common\Stability; use Internal\DLoad\Module\Downloader\Internal\DownloadContext; +use Internal\DLoad\Module\Downloader\Task\DownloadTask; use Internal\DLoad\Module\Repository\AssetInterface; use Internal\DLoad\Module\Repository\ReleaseInterface; use Internal\DLoad\Module\Repository\RepositoryInterface; use Internal\DLoad\Module\Repository\RepositoryProvider; - +use Internal\DLoad\Service\Destroyable; use Internal\DLoad\Service\Logger; +use React\Promise\PromiseInterface; use function React\Async\await; use function React\Async\coroutine; final class Downloader { - private array $tasks = []; - public function __construct( private readonly DownloaderConfig $config, private readonly Logger $logger, @@ -42,34 +41,43 @@ public function __construct( */ public function download( Software $software, - Destination $destination, \Closure $onProgress, - ): Task { - $task = new Task(); + ): DownloadTask { $context = new DownloadContext( software: $software, - destination: $destination, onProgress: $onProgress, ); $repositories = $software->repositories; - $task->handler = function () use ($repositories, $context): void { - // todo Try every repo to load software. - start: - $repositories === [] and throw new \RuntimeException('No relevant repository found.'); - $context->repoConfig = \array_shift($repositories); - $repository = $this->repositoryProvider->getByConfig($context->repoConfig); - - $this->logger->debug('Trying to load from repo `%s`', $repository->getName()); - - try { - await(coroutine($this->processRepository($repository, $context))); - } catch (\Throwable $e) { - $this->logger->exception($e); - goto start; - } + $handler = function () use ($repositories, $context): PromiseInterface { + return coroutine(function () use ($repositories, $context) { + // Try every repo to load software. + start: + $repositories === [] and throw new \RuntimeException('No relevant repository found.'); + $context->repoConfig = \array_shift($repositories); + $repository = $this->repositoryProvider->getByConfig($context->repoConfig); + + $this->logger->debug('Trying to load from repo `%s`', $repository->getName()); + + try { + await(coroutine($this->processRepository($repository, $context))); + } catch (\Throwable $e) { + $this->logger->exception($e); + yield; + goto start; + } finally { + $repository instanceof Destroyable and $repository->destroy(); + } + + return $context->file; + }); }; - return $task; + + return new DownloadTask( + software: $software, + onProgress: $onProgress, + handler: $handler, + ); } /** @@ -130,22 +138,23 @@ private function processRelease(ReleaseInterface $asset, DownloadContext $contex }; } + /** + * @return \Closure(): \SplFileObject + */ private function processAsset(AssetInterface $asset, DownloadContext $context): \Closure { - return function () use ($asset, $context): void { + return function () use ($asset, $context): \SplFileObject { // Create a file - $temp = $this->getTempDirectory() . '/' . $asset->getName(); + $temp = $this->getTempDirectory() . DIRECTORY_SEPARATOR . $asset->getName(); $file = new \SplFileObject($temp, 'wb+'); - $this->logger->info('Downloading into ' . $temp); + $this->logger->debug('Downloading into ' . $temp); await(coroutine( (static function () use ($asset, $context, $file): void { $generator = $asset->download( static fn(int $dlNow, int $dlSize, array $info) => ($context->onProgress)( new Progress( - step: 1, - steps: 2, total: $dlSize, current: $dlNow, message: 'downloading...', @@ -162,8 +171,7 @@ private function processAsset(AssetInterface $asset, DownloadContext $context): throw $e; })); - // todo Unpack - $this->logger->info('Downloaded into ' . $temp); + return $context->file = $file; }; } diff --git a/src/Module/Downloader/Internal/DownloadContext.php b/src/Module/Downloader/Internal/DownloadContext.php index a72e578..f5bdff6 100644 --- a/src/Module/Downloader/Internal/DownloadContext.php +++ b/src/Module/Downloader/Internal/DownloadContext.php @@ -4,7 +4,6 @@ namespace Internal\DLoad\Module\Downloader\Internal; -use Internal\DLoad\Module\Common\Config\Destination; use Internal\DLoad\Module\Common\Config\Embed\Repository; use Internal\DLoad\Module\Common\Config\Embed\Software; use Internal\DLoad\Module\Downloader\Progress; @@ -13,6 +12,8 @@ final class DownloadContext { /** Current repository config */ public Repository $repoConfig; + /** Downloaded file */ + public \SplFileObject $file; /** * @param \Closure(Progress): mixed $onProgress Callback to report progress. @@ -20,7 +21,6 @@ final class DownloadContext */ public function __construct( public readonly Software $software, - public readonly Destination $destination, public readonly \Closure $onProgress, ) {} } diff --git a/src/Module/Downloader/Progress.php b/src/Module/Downloader/Progress.php index ac4d8b6..4fde937 100644 --- a/src/Module/Downloader/Progress.php +++ b/src/Module/Downloader/Progress.php @@ -7,8 +7,6 @@ final class Progress { public function __construct( - public readonly int $step = 0, - public readonly int $steps = 1, public readonly int $total = 100, public readonly int $current = 0, public readonly string $message = '', diff --git a/src/Module/Downloader/Task.php b/src/Module/Downloader/Task.php deleted file mode 100644 index 27cdba6..0000000 --- a/src/Module/Downloader/Task.php +++ /dev/null @@ -1,10 +0,0 @@ - $handler + */ + public function __construct( + public readonly Software $software, + public readonly \Closure $onProgress, + public readonly \Closure $handler, + ) {} +} diff --git a/src/Module/Repository/Internal/GitHub/GitHubRelease.php b/src/Module/Repository/Internal/GitHub/GitHubRelease.php index 54cb62b..adbf73c 100644 --- a/src/Module/Repository/Internal/GitHub/GitHubRelease.php +++ b/src/Module/Repository/Internal/GitHub/GitHubRelease.php @@ -75,8 +75,9 @@ public function getConfig(): string public function destroy(): void { - $this->assets === null or \array_walk($this->assets, static fn(object $asset) => - $asset instanceof Destroyable and $asset->destroy()); + $this->assets === null or $this->assets->map( + static fn(object $asset) => $asset instanceof Destroyable and $asset->destroy(), + ); unset($this->assets, $this->repository, $this->client); } diff --git a/src/Module/Repository/Internal/GitHub/GitHubRepository.php b/src/Module/Repository/Internal/GitHub/GitHubRepository.php index e3e1315..b66236c 100644 --- a/src/Module/Repository/Internal/GitHub/GitHubRepository.php +++ b/src/Module/Repository/Internal/GitHub/GitHubRepository.php @@ -80,8 +80,9 @@ public function getName(): string public function destroy(): void { - $this->releases === null or \array_walk($this->releases, static fn(object $release) => - $release instanceof Destroyable and $release->destroy()); + $this->releases === null or $this->releases->map( + static fn(object $release) => $release instanceof Destroyable and $release->destroy(), + ); unset($this->releases, $this->client); }