Completed
Push — master ( 17b2fe...3ff7d4 )
by C
21:32 queued 05:15
created

DownloadCommand::doWork()   D

Complexity

Conditions 30
Paths 20

Size

Total Lines 149
Code Lines 88

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 79
CRAP Score 30.0017

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 149
ccs 79
cts 80
cp 0.9875
rs 4.425
cc 30
eloc 88
nc 20
nop 2
crap 30.0017

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace Local\Console\Command;
3
4
use GuzzleHttp\Promise;
5
use Joomla\Registry\Registry;
6
use League\Flysystem\Adapter\Local;
7
use Monolog\Logger;
8
use Tartana\Component\Command\Command;
9
use Tartana\Domain\Command\SaveDownloads;
10
use Tartana\Domain\DownloadRepository;
11
use Tartana\Entity\Download;
12
use Tartana\Host\Common\Http;
13
use Tartana\Host\HostFactory;
14
use Tartana\Mixins\CommandBusAwareTrait;
15
use Tartana\Mixins\LoggerAwareTrait;
16
use Tartana\Util;
17
use Symfony\Component\Console\Input\InputInterface;
18
use Symfony\Component\Console\Input\InputOption;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Tartana\Console\Command\AbstractDaemonCommand;
21
use Tartana\Component\Command\Runner;
22
23
class DownloadCommand extends AbstractDaemonCommand
24
{
25
	use LoggerAwareTrait;
26
	use CommandBusAwareTrait;
27
28
	private $repository = null;
29
30
	private $factory = null;
31
32 16
	public function __construct(DownloadRepository $repository, HostFactory $factory, Runner $runner)
33
	{
34 16
		parent::__construct($runner);
35
36 16
		$this->repository = $repository;
37 16
		$this->factory = $factory;
38 16
	}
39
40 16
	protected function configure()
41
	{
42 16
		parent::configure();
43
44 16
		$this->setName('download');
45 16
		$this->setDescription('Downloads links from the database. This command is running in foreground!');
46
47 16
		$this->addOption('force', 'f', InputOption::VALUE_NONE, 'Should all downloads set back to not started.');
48 16
	}
49
50 15
	protected function doWork(InputInterface $input, OutputInterface $output)
51
	{
52 15
		$repository = $this->repository;
53
54 15
		$this->log('Started to download links from the database');
55
56
		// Loading configuration for the hosters if it exists
57 15
		$config = new Registry();
58 15
		if (file_exists(TARTANA_PATH_ROOT . '/app/config/parameters.yml')) {
59 15
			$config->loadFile(TARTANA_PATH_ROOT . '/app/config/parameters.yml', 'yaml');
60
		}
61 15
		if (file_exists(TARTANA_PATH_ROOT . '/app/config/hosters.yml')) {
62 1
			$config->loadFile(TARTANA_PATH_ROOT . '/app/config/hosters.yml', 'yaml');
63
		}
64
65 15
		$force = (boolean)$input->getOption('force');
66
67 15
		while (true) {
68 15
			$resets = $repository->findDownloads([
69 15
					Download::STATE_DOWNLOADING_STARTED,
70 15
					Download::STATE_DOWNLOADING_ERROR
71
			]);
72 15
			$hasChanged = false;
73 15
			if (!empty($resets)) {
74 5
				foreach ($resets as $resetDownload) {
75 5
					if ($resetDownload->getState() != Download::STATE_DOWNLOADING_STARTED && !$force) {
76
						// When not forcing only check for zombie downloads
77 2
						continue;
78
					}
79 4
					if ($resetDownload->getState() == Download::STATE_DOWNLOADING_STARTED && $resetDownload->getPid() && Util::isPidRunning(
80 4
						$resetDownload->getPid()
81
					)) {
82
					// There is an active process
83 2
						continue;
84
					}
85 3
					$resetDownload = Download::reset($resetDownload);
86 3
					$hasChanged = true;
87
				}
88
			}
89 15
			if ($hasChanged) {
90 3
				$this->log('Restarting zombie downloads, error downloads will be ' . ($force ? '' : 'not') . ' restarted');
91 3
				$this->handleCommand(new SaveDownloads($resets));
92
			}
93
94 15
			$notStartedDownloads = $repository->findDownloads(Download::STATE_DOWNLOADING_NOT_STARTED);
95 15
			if (empty($notStartedDownloads)) {
96
			// Nothing to do anymore
97 15
				break;
98
			}
99
100 11
			$concurrentDownloads = 5;
101 11
			$counter = count($repository->findDownloads(Download::STATE_DOWNLOADING_STARTED));
102
103
			// Set download speed limit
104 11
			if (isset($config->get('parameters')->{'tartana.local.downloads.speedlimit'}) &&
105 11
					 $config->get('parameters')->{'tartana.local.downloads.speedlimit'} > 0) {
106 1
				$config->set('speedlimit', $config->get('parameters')->{'tartana.local.downloads.speedlimit'} / $concurrentDownloads);
107
			}
108
109
			// Check day limit
110 11
			if (isset($config->get('parameters')->{'tartana.local.downloads.daylimit'}) &&
111 11
					 $config->get('parameters')->{'tartana.local.downloads.daylimit'} > 0) {
112 2
				$dayLimit = $config->get('parameters')->{'tartana.local.downloads.daylimit'} * 1000;
113
114 2
				$today = (new \DateTime())->format('D');
115 2
				foreach ($repository->findDownloads(Download::STATE_DOWNLOADING_COMPLETED) as $download) {
116 2
					if ($download->getFinishedAt() && $download->getFinishedAt()->format('D') != $today) {
117 1
						continue;
118
					}
119
120 2
					$dayLimit -= $download->getSize();
121
				}
122
123 2
				if ($dayLimit <= 0) {
124 1
					$this->log('Reached day limit, not starting any download');
125 1
					$counter = $concurrentDownloads;
126
				}
127
			}
128
129 11
			$this->log('Found ' . $counter . ' started downloads.');
130
131
			// Processing the downloads
132 11
			$promises = [];
133 11
			$sharedClients = [];
134 11
			$startedDownloads = [];
135 11
			foreach ($notStartedDownloads as $download) {
136 11
				if ($counter >= $concurrentDownloads) {
137 2
					break;
138
				}
139
140 9
				$downloader = $this->factory->createHostDownloader($download->getLink(), $config);
141 9
				if ($downloader == null) {
142 1
					$this->log('No downloader found for link ' . $download->getLink(), Logger::WARNING);
143 1
					continue;
144
				}
145
146 8
				$this->log('Started to download ' . $download->getLink() . ' with the class ' . get_class($downloader));
147
148 8
				$download = Download::reset($download);
149 8
				$download->setState(Download::STATE_DOWNLOADING_STARTED);
150 8
				$download->setPid(getmypid());
151 8
				$this->handleCommand(new SaveDownloads([
152 8
						$download
153
				]));
154
155 8
				if ($downloader instanceof Http) {
156 2
					$name = get_class($downloader);
157 2
					if (!key_exists($name, $sharedClients)) {
158 2
						$sharedClients[$name] = $downloader->getClient();
159
					} else {
160 1
						$downloader->setClient($sharedClients[$name]);
161
					}
162
				}
163
164 8
				$tmp = $downloader->download([
165 8
						clone $download
166
				]);
167 8
				$startedDownloads[] = $download;
168
169 8
				$promises = array_merge($promises, $tmp ? $tmp : []);
170 8
				$counter ++;
171
			}
172
173 11
			$this->log('Downloading ' . count($promises) . ' links');
174
175
			try {
176 11
				Promise\unwrap($promises);
177
			} catch (\Exception $e) {
178
			// @codeCoverageIgnoreStart
179
				$this->log('Exception happened, waiting for the downloads: ' . $e->getMessage(), Logger::ERROR);
180
				foreach ($startedDownloads as $download) {
181
					$download = Download::reset($download);
182
					$download->setState(Download::STATE_DOWNLOADING_ERROR);
183
					$download->setMessage($e->getMessage());
184
					$this->handleCommand(new SaveDownloads([
185
							$download
186
					]));
187
				}
188
				// @codeCoverageIgnoreEnd
189
			}
190
191
			// We sleep her as we are a daemon to relax the system a bit
192 11
			sleep($config->get('sleepTime', 10));
193
		}
194 15
		$this->log('Finished to download links from the database');
195
196 15
		$this->log('Calling default command for post processing');
197 15
		$this->getCommandRunner()->execute(Command::getAppCommand('default'));
198 15
	}
199
}
200