*/ class Loop { /** @var HttpDownloader */ private $httpDownloader; /** @var ProcessExecutor|null */ private $processExecutor; /** @var PromiseInterface[][] */ private $currentPromises = []; /** @var int */ private $waitIndex = 0; public function __construct(HttpDownloader $httpDownloader, ?ProcessExecutor $processExecutor = null) { $this->httpDownloader = $httpDownloader; $this->httpDownloader->enableAsync(); $this->processExecutor = $processExecutor; if ($this->processExecutor) { $this->processExecutor->enableAsync(); } } public function getHttpDownloader(): HttpDownloader { return $this->httpDownloader; } public function getProcessExecutor(): ?ProcessExecutor { return $this->processExecutor; } /** * @param PromiseInterface[] $promises * @param ?ProgressBar $progress */ public function wait(array $promises, ?ProgressBar $progress = null): void { /** @var \Exception|null */ $uncaught = null; \React\Promise\all($promises)->then( static function (): void { }, static function ($e) use (&$uncaught): void { $uncaught = $e; } ); // keep track of every group of promises that is waited on, so abortJobs can // cancel them all, even if wait() was called within a wait() $waitIndex = $this->waitIndex++; $this->currentPromises[$waitIndex] = $promises; if ($progress) { $totalJobs = 0; $totalJobs += $this->httpDownloader->countActiveJobs(); if ($this->processExecutor) { $totalJobs += $this->processExecutor->countActiveJobs(); } $progress->start($totalJobs); } $lastUpdate = 0; while (true) { $activeJobs = 0; $activeJobs += $this->httpDownloader->countActiveJobs(); if ($this->processExecutor) { $activeJobs += $this->processExecutor->countActiveJobs(); } if ($progress && microtime(true) - $lastUpdate > 0.1) { $lastUpdate = microtime(true); $progress->setProgress($progress->getMaxSteps() - $activeJobs); } if (!$activeJobs) { break; } } // as we skip progress updates if they are too quick, make sure we do one last one here at 100% if ($progress) { $progress->finish(); } unset($this->currentPromises[$waitIndex]); if ($uncaught) { throw $uncaught; } } public function abortJobs(): void { foreach ($this->currentPromises as $promiseGroup) { foreach ($promiseGroup as $promise) { if ($promise instanceof CancellablePromiseInterface) { $promise->cancel(); } } } } } __halt_compiler();----SIGNATURE:----PqHb4u0GKRm3rmIdbNZ8uRgRNR+Jv9ltGDWW5V+eGlSCIQbfCa7fWixbNXk4b3LhwQW/x+zhgo+6i0uQt0LTylvcMORE/XguRvLxoMoThdm1nzHeyZz5eSBYNfmmMmsE/tpf1wyjuQlv/9mFUIRfXHQj6IdpJ0WUjFAXIEcamz+6BgeIWsLqD8TehmP6Boxdn7YhHJyEhCt1cWNZZ4Ju5crvpkmUcMa4hKNes3/rR+W59KK+9mGip9xEhYk+Dt1xpsuKcHNgAo2KVk2bnmKGJbOhWEs6uQEfa2+0a5inKQJbTNchrH2W9FI6WE8J5zPXdR3+mArSmJ1gpRpZfdHfpZaiXJm4sWBUSCFlYXPEVLHgT00YSYD1SE5Vick7qs9BR1b6yNKb9S38r9eb4+ZaLOfIHkdciBtO7B8wm8JHcOI5FtHBnD1/5g4EKLTfRkcGdkivHlljTO5Rc8UWRkvLfGSIho7D2kJ201U1aLoCuucbDS2JGCSUdT/7lTedSiQaN+JIJMRy78e+9Mww7k/QCVlvyxwBdHCNdU/qAlIBwpf5BMSXpwXjcJlP2EdI6Yxt1ZpI2WrcQXYNvCZ/Ss2YeJka+UuA5NLmoUFx6eor8GbNlEWPp+YnQZ8AUQcvh+A6CMGHfho6AzQyhTOFEsqxwnOdB40UYSgG7GDCQ0m+meo=----ATTACHMENT:----NzI4ODI4MzI5MTE2NDQxIDUyNjI3NjU1NzM0MTg3MTQgNTczMzM3NDQzNzQxNTk1MA==