Completed
Push — dev ( 76d1f2...f64915 )
by Darko
11:42
created

Forking::safeBinariesMainMethod()   B

Complexity

Conditions 7
Paths 2

Size

Total Lines 52
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
eloc 35
dl 0
loc 52
ccs 0
cts 22
cp 0
rs 8.4266
c 0
b 0
f 0
cc 7
nc 2
nop 0
crap 56

How to fix   Long Method   

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
3
namespace Blacklight\libraries;
4
5
use Blacklight\Nfo;
6
use Blacklight\NZB;
7
use Blacklight\NNTP;
8
use Spatie\Async\Pool;
9
use App\Models\Settings;
10
use Blacklight\ColorCLI;
11
use App\Models\UsenetGroup;
12
use Illuminate\Support\Carbon;
13
use Illuminate\Support\Facades\DB;
14
use Illuminate\Support\Facades\Log;
15
use Blacklight\processing\PostProcess;
16
17
/**
18
 * Class Forking.
19
 *
20
 * This forks various newznab scripts.
21
 *
22
 * For example, you get all the ID's of the active groups in the groups table, you then iterate over them and spawn
23
 * processes of misc/update_binaries.php passing the group ID's.
24
 */
25
class Forking
26
{
27
    private const OUTPUT_NONE = 0; // Don't display child output.
28
    private const OUTPUT_REALTIME = 1; // Display child output in real time.
29
    private const OUTPUT_SERIALLY = 2; // Display child output when child is done.
30
31
    /**
32
     * @var \Blacklight\ColorCLI
33
     */
34
    public $colorCli;
35
36
    /**
37
     * @var int The type of output
38
     */
39
    protected $outputType;
40
41
    /**
42
     * Path to do not run folder.
43
     *
44
     * @var string
45
     */
46
    private $dnr_path;
47
48
    /**
49
     * Work to work on.
50
     *
51
     * @var array
52
     */
53
    private $work = [];
54
55
    /**
56
     * How much work do we have to do?
57
     *
58
     * @var int
59
     */
60
    public $_workCount = 0;
61
62
    /**
63
     * The type of work we want to work on.
64
     *
65
     * @var string
66
     */
67
    private $workType = '';
68
69
    /**
70
     * List of passed in options for the current work type.
71
     *
72
     * @var array
73
     */
74
    private $workTypeOptions = [];
75
76
    /**
77
     * Max amount of child processes to do work at a time.
78
     *
79
     * @var int
80
     */
81
    private $maxProcesses = 1;
82
83
    /**
84
     * Group used for safe backfill.
85
     *
86
     * @var string
87
     */
88
    private $safeBackfillGroup = '';
89
    /**
90
     * @var int
91
     */
92
    protected $maxSize;
93
94
    /**
95
     * @var int
96
     */
97
    protected $minSize;
98
99
    /**
100
     * @var int
101
     */
102
    protected $maxRetries;
103
104
    /**
105
     * @var int
106
     */
107
    protected $dummy;
108
109
    /**
110
     * @var bool
111
     */
112
    private $processAdditional = false; // Should we process additional?
113
    private $processNFO = false; // Should we process NFOs?
114
    private $processMovies = false; // Should we process Movies?
115
    private $processTV = false; // Should we process TV?
116
117
    /**
118
     * Setup required parent / self vars.
119
     *
120
     * @throws \Exception
121
     */
122
    public function __construct()
123
    {
124
        \Opis\Closure\SerializableClosure::removeSecurityProvider();
125
        $this->colorCli = new ColorCLI();
126
127
        $this->dnr_path = PHP_BINARY.' misc/update/multiprocessing/.do_not_run/switch.php "php  ';
128
129
        switch (config('nntmux.multiprocessing_child_output_type')) {
130
                case 0:
131
                    $this->outputType = self::OUTPUT_NONE;
132
                    break;
133
                case 1:
134
                    $this->outputType = self::OUTPUT_REALTIME;
135
                    break;
136
                case 2:
137
                    $this->outputType = self::OUTPUT_SERIALLY;
138
                    break;
139
                default:
140
                    $this->outputType = self::OUTPUT_REALTIME;
141
            }
142
143
        $this->dnr_path = PHP_BINARY.' misc/update/multiprocessing/.do_not_run/switch.php "php  ';
144
145
        $this->maxSize = (int) Settings::settingValue('..maxsizetoprocessnfo');
146
        $this->minSize = (int) Settings::settingValue('..minsizetoprocessnfo');
147
        $this->maxRetries = (int) Settings::settingValue('..maxnforetries') >= 0 ? -((int) Settings::settingValue('..maxnforetries') + 1) : Nfo::NFO_UNPROC;
148
        $this->maxRetries = $this->maxRetries < -8 ? -8 : $this->maxRetries;
149
    }
150
151
    /**
152
     * Setup the class to work on a type of work, then process the work.
153
     * Valid work types:.
154
     *
155
     * @param string $type The type of multiProcessing to do : backfill, binaries, releases, postprocess
156
     * @param array $options Array containing arguments for the type of work.
157
     *
158
     * @throws \Exception
159
     */
160
    public function processWorkType($type, array $options = [])
161
    {
162
        // Set/reset some variables.
163
        $startTime = now()->timestamp;
164
        $this->workType = $type;
165
        $this->workTypeOptions = $options;
166
        $this->processAdditional = $this->processNFO = $this->processTV = $this->processMovies = $this->ppRenamedOnly = false;
167
        $this->work = [];
168
169
        // Process extra work that should not be forked and done before forking.
170
        $this->processStartWork();
171
172
        // Get work to fork.
173
        $this->getWork();
174
175
        // Process extra work that should not be forked and done after.
176
        $this->processEndWork();
177
178
        if (config('nntmux.echocli')) {
179
            $this->colorCli->header(
180
                'Multi-processing for '.$this->workType.' finished in '.(now()->timestamp - $startTime).
181
                ' seconds at '.now()->toRfc2822String().'.'.PHP_EOL
182
            );
183
        }
184
    }
185
186
    /**
187
     * Only post process renamed movie / tv releases?
188
     *
189
     * @var bool
190
     */
191
    private $ppRenamedOnly;
192
193
    /**
194
     * Get work for our workers to work on, set the max child processes here.
195
     *
196
     * @throws \Exception
197
     */
198
    private function getWork()
199
    {
200
        $this->maxProcesses = 0;
201
202
        switch ($this->workType) {
203
204
            case 'backfill':
205
                $this->backfill();
206
                break;
207
208
            case 'binaries':
209
                $this->binaries();
210
                break;
211
212
            case 'fixRelNames_standard':
213
            case 'fixRelNames_predbft':
214
                $this->fixRelNames();
215
                break;
216
217
            case 'releases':
218
                $this->releases();
219
                break;
220
221
            case 'postProcess_ama':
222
                $this->processSingle();
223
                break;
224
225
            case 'postProcess_add':
226
                $this->postProcessAdd();
227
                break;
228
229
            case 'postProcess_mov':
230
                $this->ppRenamedOnly = (isset($this->workTypeOptions[0]) && $this->workTypeOptions[0] === true);
231
                $this->postProcessMov();
232
                break;
233
234
            case 'postProcess_nfo':
235
                $this->postProcessNfo();
236
                break;
237
238
            case 'postProcess_sha':
239
                $this->processSharing();
240
                break;
241
242
            case 'postProcess_tv':
243
                $this->ppRenamedOnly = (isset($this->workTypeOptions[0]) && $this->workTypeOptions[0] === true);
244
                $this->postProcessTv();
245
                break;
246
247
            case 'safe_backfill':
248
                $this->safeBackfill();
249
                break;
250
251
            case 'safe_binaries':
252
                $this->safeBinaries();
253
                break;
254
255
            case 'update_per_group':
256
                $this->updatePerGroup();
257
                break;
258
        }
259
    }
260
261
    /**
262
     * Process work if we have any.
263
     */
264
    private function processWork()
265
    {
266
        $this->_workCount = \count($this->work);
267
        if ($this->_workCount > 0 && config('nntmux.echocli') === true) {
268
            $this->colorCli->header(
269
                'Multi-processing started at '.now()->toRfc2822String().' for '.$this->workType.' with '.$this->_workCount.
270
                ' job(s) to do using a max of '.$this->maxProcesses.' child process(es).'
271
            );
272
        }
273
        if (empty($this->_workCount) && config('nntmux.echocli') === true) {
274
            $this->colorCli->header('No work to do!');
275
        }
276
    }
277
278
    /**
279
     * Process any work that does not need to be forked, but needs to run at the start.
280
     */
281
    private function processStartWork()
282
    {
283
        switch ($this->workType) {
284
            case 'safe_backfill':
285
            case 'safe_binaries':
286
                $this->_executeCommand(PHP_BINARY.' misc/update/tmux/bin/update_groups.php');
287
                break;
288
        }
289
    }
290
291
    /**
292
     * Process any work that does not need to be forked, but needs to run at the end.
293
     */
294
    private function processEndWork()
295
    {
296
        switch ($this->workType) {
297
            case 'releases':
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
298
299
                $this->_executeCommand($this->dnr_path.'releases  '.\count($this->work).'_"');
300
301
                break;
302
            case 'update_per_group':
303
                $this->_executeCommand($this->dnr_path.'releases  '.\count($this->work).'_"');
304
305
                break;
306
        }
307
    }
308
309
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
310
    //////////////////////////////////////// All backFill code here ////////////////////////////////////////////////////
311
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
312
313
    private function backfill()
314
    {
315
        // The option for backFill is for doing up to x articles. Else it's done by date.
316
        $this->work = DB::select(
317
            sprintf(
318
                'SELECT name %s FROM usenet_groups WHERE backfill = 1',
319
                ($this->workTypeOptions[0] === false ? '' : (', '.$this->workTypeOptions[0].' AS max'))
320
            )
321
        );
322
323
        $pool = Pool::create()->concurrency($this->maxProcesses)->timeout(config('nntmux.multiprocessing_max_child_time'));
324
        $this->processWork();
325
        $maxWork = \count($this->work);
326
        foreach ($this->work as $group) {
327
            $pool->add(function () use ($group) {
328
                $this->_executeCommand(PHP_BINARY.' misc/update/backfill.php '.$group->name.(isset($group->max) ? (' '.$group->max) : ''));
329
            })->then(function () use ($group, $maxWork) {
330
                $this->colorCli->primary('Task #'.$maxWork.' Backfilled group '.$group->name);
331
            })->catch(function (\Throwable $exception) {
0 ignored issues
show
Unused Code introduced by
The parameter $exception is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

331
            })->catch(function (/** @scrutinizer ignore-unused */ \Throwable $exception) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
332
                // Handle exception
333
            });
334
            $maxWork--;
335
        }
336
        $pool->wait();
337
    }
338
339
    private function safeBackfill()
340
    {
341
        $backfill_qty = (int) Settings::settingValue('site.tmux.backfill_qty');
342
        $backfill_order = (int) Settings::settingValue('site.tmux.backfill_order');
343
        $backfill_days = (int) Settings::settingValue('site.tmux.backfill_days');
344
        $maxmssgs = (int) Settings::settingValue('..maxmssgs');
345
        $threads = (int) Settings::settingValue('..backfillthreads');
346
347
        $orderby = 'ORDER BY a.last_record ASC';
348
        switch ($backfill_order) {
349
            case 1:
350
                $orderby = 'ORDER BY first_record_postdate DESC';
351
                break;
352
353
            case 2:
354
                $orderby = 'ORDER BY first_record_postdate ASC';
355
                break;
356
357
            case 3:
358
                $orderby = 'ORDER BY name ASC';
359
                break;
360
361
            case 4:
362
                $orderby = 'ORDER BY name DESC';
363
                break;
364
365
            case 5:
366
                $orderby = 'ORDER BY a.last_record DESC';
367
                break;
368
        }
369
370
        $backfilldays = '';
371
        if ($backfill_days === 1) {
372
            $days = 'backfill_target';
373
            $backfilldays = now()->diffInDays(Carbon::createFromDate($days));
0 ignored issues
show
Bug introduced by
$days of type string is incompatible with the type integer|null expected by parameter $year of Carbon\Carbon::createFromDate(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

373
            $backfilldays = now()->diffInDays(Carbon::createFromDate(/** @scrutinizer ignore-type */ $days));
Loading history...
374
        } elseif ($backfill_days === 2) {
375
            $backfilldays = now()->diffInDays(Carbon::createFromFormat('Y-m-d', Settings::settingValue('..safebackfilldate')));
376
        }
377
378
        $data = DB::select(
379
            sprintf(
380
                'SELECT g.name,
381
				g.first_record AS our_first,
382
				MAX(a.first_record) AS their_first,
383
				MAX(a.last_record) AS their_last
384
				FROM usenet_groups g
385
				INNER JOIN short_groups a ON g.name = a.name
386
				WHERE g.first_record IS NOT NULL
387
				AND g.first_record_postdate IS NOT NULL
388
				AND g.backfill = 1
389
				AND %s < g.first_record_postdate
390
				GROUP BY a.name, a.last_record, g.name, g.first_record
391
				%s LIMIT 1',
392
                $backfilldays,
393
                $orderby
394
            )
395
        );
396
397
        $count = 0;
398
        if ($data[0]->name) {
399
            $this->safeBackfillGroup = $data[0]->name;
400
401
            $count = ($data[0]->our_first - $data[0]->their_first);
402
        }
403
404
        if ($count > 0) {
405
            if ($count > ($backfill_qty * $threads)) {
406
                $geteach = ceil(($backfill_qty * $threads) / $maxmssgs);
407
            } else {
408
                $geteach = $count / $maxmssgs;
409
            }
410
411
            $queues = [];
412
            for ($i = 0; $i <= $geteach - 1; $i++) {
413
                $queues[$i] = sprintf('get_range  backfill  %s  %s  %s  %s', $data[0]->name, $data[0]->our_first - $i * $maxmssgs - $maxmssgs, $data[0]->our_first - $i * $maxmssgs - 1, $i + 1);
414
            }
415
416
            $pool = Pool::create()->concurrency((int) Settings::settingValue('..backfillthreads'))->timeout(config('nntmux.multiprocessing_max_child_time'));
417
418
            $this->processWork();
419
            foreach ($queues as $queue) {
420
                $pool->add(function () use ($queue) {
421
                    $this->_executeCommand($this->dnr_path.$queue.'"');
422
                })->then(function () use ($data) {
423
                    $this->colorCli->primary('Backfilled group '.$data[0]->name);
424
                })->catch(function (\Throwable $exception) {
0 ignored issues
show
Unused Code introduced by
The parameter $exception is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

424
                })->catch(function (/** @scrutinizer ignore-unused */ \Throwable $exception) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
425
                    // Handle exception
426
                });
427
            }
428
            $pool->wait();
429
        }
430
    }
431
432
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
433
    //////////////////////////////////////// All binaries code here ////////////////////////////////////////////////////
434
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
435
436
    private function binaries()
437
    {
438
        $this->work = DB::select(
439
            sprintf(
440
                'SELECT name, %d AS max FROM usenet_groups WHERE active = 1',
441
                $this->workTypeOptions[0]
442
            )
443
        );
444
445
        $this->maxProcesses = (int) Settings::settingValue('..binarythreads');
446
447
        $pool = Pool::create()->concurrency($this->maxProcesses)->timeout(config('nntmux.multiprocessing_max_child_time'));
448
449
        $maxWork = \count($this->work);
450
451
        $this->processWork();
452
        foreach ($this->work as $group) {
453
            $pool->add(function () use ($group) {
454
                $this->_executeCommand(PHP_BINARY.' misc/update/update_binaries.php '.$group->name.' '.$group->max);
455
            })->then(function () use ($group, $maxWork) {
456
                $this->colorCli->primary('Task #'.$maxWork.' Updated group '.$group->name);
457
            })->catch(function (\Throwable $exception) {
458
                echo $exception->getMessage();
459
            });
460
            $maxWork--;
461
        }
462
463
        $pool->wait();
464
    }
465
466
    /**
467
     * @throws \Exception
468
     */
469
    private function safeBinaries()
470
    {
471
        $maxheaders = (int) Settings::settingValue('..max_headers_iteration') ?: 1000000;
472
        $maxmssgs = (int) Settings::settingValue('..maxmssgs');
473
        $this->maxProcesses = (int) Settings::settingValue('..binarythreads');
474
475
        $this->work = DB::select(
476
            '
477
			SELECT g.name AS groupname, g.last_record AS our_last,
478
				a.last_record AS their_last
479
			FROM usenet_groups g
480
			INNER JOIN short_groups a ON g.active = 1 AND g.name = a.name
481
			ORDER BY a.last_record DESC'
482
        );
483
484
        if (! empty($this->work)) {
485
            $i = 1;
486
            $queues = [];
487
            foreach ($this->work as $group) {
488
                if ((int) $group->our_last === 0) {
489
                    $queues[$i] = sprintf('update_group_headers  %s', $group->groupname);
490
                    $i++;
491
                } else {
492
                    //only process if more than 20k headers available and skip the first 20k
493
                    $count = $group->their_last - $group->our_last - 20000;
494
                    //echo "count: " . $count . "maxmsgs x2: " . ($maxmssgs * 2) . PHP_EOL;
495
                    if ($count <= $maxmssgs * 2) {
496
                        $queues[$i] = sprintf('update_group_headers  %s', $group->groupname);
497
                        $i++;
498
                    } else {
499
                        $queues[$i] = sprintf('part_repair  %s', $group->groupname);
500
                        $i++;
501
                        $geteach = floor(min($count, $maxheaders) / $maxmssgs);
502
                        $remaining = min($count, $maxheaders) - $geteach * $maxmssgs;
503
                        //echo "maxmssgs: " . $maxmssgs . " geteach: " . $geteach . " remaining: " . $remaining . PHP_EOL;
504
                        for ($j = 0; $j < $geteach; $j++) {
505
                            $queues[$i] = sprintf('get_range  binaries  %s  %s  %s  %s', $group->groupname, $group->our_last + $j * $maxmssgs + 1, $group->our_last + $j * $maxmssgs + $maxmssgs, $i);
506
                            $i++;
507
                        }
508
                        //add remainder to queue
509
                        $queues[$i] = sprintf('get_range  binaries  %s  %s  %s  %s', $group->groupname, $group->our_last + ($j + 1) * $maxmssgs + 1, $group->our_last + ($j + 1) * $maxmssgs + $remaining + 1, $i);
510
                        $i++;
511
                    }
512
                }
513
            }
514
            $pool = Pool::create()->concurrency($this->maxProcesses)->timeout(config('nntmux.multiprocessing_max_child_time'));
515
516
            $this->processWork();
517
            foreach ($queues as $queue) {
518
                preg_match('/alt\..+/i', $queue, $match);
519
                $pool->add(function () use ($queue) {
520
                    $this->_executeCommand($this->dnr_path.$queue.'"');
521
                })->then(function () use ($match) {
522
                    if (! empty($match)) {
523
                        $this->colorCli->primary('Updated group '.$match[0]);
524
                    }
525
                })->catch(function (\Throwable $exception) {
0 ignored issues
show
Unused Code introduced by
The parameter $exception is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

525
                })->catch(function (/** @scrutinizer ignore-unused */ \Throwable $exception) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
526
                    // Handle exception
527
                });
528
            }
529
530
            $pool->wait();
531
        }
532
    }
533
534
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
535
    //////////////////////////////////// All fix release names code here ///////////////////////////////////////////////
536
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
537
538
    private function fixRelNames()
539
    {
540
        $this->maxProcesses = (int) Settings::settingValue('..fixnamethreads');
541
        $maxperrun = (int) Settings::settingValue('..fixnamesperrun');
542
543
        if ($this->maxProcesses > 16) {
544
            $this->maxProcesses = 16;
545
        } elseif ($this->maxProcesses === 0) {
546
            $this->maxProcesses = 1;
547
        }
548
549
        $leftGuids = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
550
551
        // Prevent PreDB FT from always running
552
        if ($this->workTypeOptions[0] === 'predbft') {
553
            $preCount = DB::select(
554
                sprintf(
555
                    "
556
					SELECT COUNT(p.id) AS num
557
					FROM predb p
558
					WHERE LENGTH(p.title) >= 15
559
					AND p.title NOT REGEXP '[\"\<\> ]'
560
					AND p.searched = 0
561
					AND p.predate < (NOW() - INTERVAL 1 DAY)"
562
                )
563
            );
564
            if ($preCount[0]->num > 0) {
565
                $leftGuids = \array_slice($leftGuids, 0, (int) ceil($preCount[0]->num / $maxperrun));
566
            } else {
567
                $leftGuids = [];
568
            }
569
        }
570
571
        $count = 0;
572
        $queues = [];
573
        foreach ($leftGuids as $leftGuid) {
574
            $count++;
575
            if ($maxperrun > 0) {
576
                $queues[$count] = sprintf('%s %s %s %s', $this->workTypeOptions[0], $leftGuid, $maxperrun, $count);
577
            }
578
        }
579
580
        $this->work = $queues;
581
582
        $pool = Pool::create()->concurrency($this->maxProcesses)->timeout(config('nntmux.multiprocessing_max_child_time'));
583
584
        $maxWork = \count($queues);
585
586
        $this->processWork();
587
        foreach ($this->work as $queue) {
588
            $pool->add(function () use ($queue) {
589
                $this->_executeCommand(PHP_BINARY.' misc/update/tmux/bin/groupfixrelnames.php "'.$queue.'"'.' true');
590
            })->then(function () use ($maxWork) {
591
                $this->colorCli->primary('Task #'.$maxWork.' Finished fixing releases names');
592
            })->catch(function (\Throwable $exception) {
0 ignored issues
show
Unused Code introduced by
The parameter $exception is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

592
            })->catch(function (/** @scrutinizer ignore-unused */ \Throwable $exception) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
593
                // Handle exception
594
            });
595
            $maxWork--;
596
        }
597
        $pool->wait();
598
    }
599
600
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
601
    //////////////////////////////////////// All releases code here ////////////////////////////////////////////////////
602
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
603
604
    private function releases()
605
    {
606
        $this->work = DB::select('SELECT id, name FROM usenet_groups WHERE (active = 1 OR backfill = 1)');
607
        $this->maxProcesses = (int) Settings::settingValue('..releasethreads');
608
609
        $uGroups = [];
610
        foreach ($this->work as $group) {
611
            try {
612
                if (! empty(DB::select(sprintf('SELECT id FROM collections LIMIT 1')))) {
613
                    $uGroups[] = ['id' => $group->id, 'name' => $group->name];
614
                }
615
            } catch (\PDOException $e) {
616
                if (config('app.debug') === true) {
617
                    Log::debug($e->getMessage());
618
                }
619
            }
620
        }
621
622
        $maxWork = \count($this->work);
623
624
        $pool = Pool::create()->concurrency($this->maxProcesses)->timeout(config('nntmux.multiprocessing_max_child_time'));
625
626
        $this->processWork();
627
        foreach ($uGroups as $group) {
628
            $pool->add(function () use ($group) {
629
                $this->_executeCommand($this->dnr_path.'releases  '.$group['id'].'"');
630
            })->then(function () use ($maxWork) {
631
                $this->colorCli->primary('Task #'.$maxWork.' Finished performing release processing');
632
            })->catch(function (\Throwable $exception) {
0 ignored issues
show
Unused Code introduced by
The parameter $exception is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

632
            })->catch(function (/** @scrutinizer ignore-unused */ \Throwable $exception) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
633
                // Handle exception
634
            });
635
            $maxWork--;
636
        }
637
638
        $pool->wait();
639
    }
640
641
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
642
    /////////////////////////////////////// All post process code here /////////////////////////////////////////////////
643
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
644
645
    /**
646
     * Only 1 exit method is used for post process, since they are all similar.
647
     *
648
     *
649
     * @param array $releases
650
     * @param int   $maxProcess
651
     */
652
    public function postProcess($releases, $maxProcess)
653
    {
654
        $type = $desc = '';
655
        if ($this->processAdditional) {
656
            $type = 'pp_additional  ';
657
            $desc = 'additional postprocessing';
658
        } elseif ($this->processNFO) {
659
            $type = 'pp_nfo  ';
660
            $desc = 'nfo postprocessing';
661
        } elseif ($this->processMovies) {
662
            $type = 'pp_movie  ';
663
            $desc = 'movies postprocessing';
664
        } elseif ($this->processTV) {
665
            $type = 'pp_tv  ';
666
            $desc = 'tv postprocessing';
667
        }
668
        $pool = Pool::create()->concurrency($maxProcess)->timeout(config('nntmux.multiprocessing_max_child_time'));
669
        $count = \count($releases);
670
        $this->processWork();
671
        foreach ($releases as $release) {
672
            if ($type !== '') {
673
                $pool->add(function () use ($release, $type) {
674
                    $this->_executeCommand($this->dnr_path.$type.$release->id.(isset($release->renamed) ? ('  '.$release->renamed) : '').'"');
675
                })->then(function () use ($desc, $count) {
676
                    $this->colorCli->primary('Finished task #'.$count.' for '.$desc);
677
                })->catch(function (\Throwable $exception) {
0 ignored issues
show
Unused Code introduced by
The parameter $exception is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

677
                })->catch(function (/** @scrutinizer ignore-unused */ \Throwable $exception) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
678
                    // Handle exception
679
                })->timeout(function () use ($count) {
680
                    $this->colorCli->notice('Task #'.$count.': Timeout occurred.');
681
                });
682
                $count--;
683
            }
684
        }
685
        $pool->wait();
686
    }
687
688
    /**
689
     * @throws \Exception
690
     */
691
    private function postProcessAdd()
692
    {
693
        $ppAddMinSize = Settings::settingValue('..minsizetopostprocess') !== '' ? (int) Settings::settingValue('..minsizetopostprocess') : 1;
0 ignored issues
show
introduced by
The condition App\Models\Settings::set...etopostprocess') !== '' is always true.
Loading history...
694
        $ppAddMinSize = ($ppAddMinSize > 0 ? ('AND r.size > '.($ppAddMinSize * 1048576)) : '');
695
        $ppAddMaxSize = (Settings::settingValue('..maxsizetopostprocess') !== '') ? (int) Settings::settingValue('..maxsizetopostprocess') : 100;
0 ignored issues
show
introduced by
The condition App\Models\Settings::set...etopostprocess') !== '' is always true.
Loading history...
696
        $ppAddMaxSize = ($ppAddMaxSize > 0 ? ('AND r.size < '.($ppAddMaxSize * 1073741824)) : '');
697
        $this->maxProcesses = 1;
698
        $ppQueue = DB::select(
699
            sprintf(
700
                '
701
					SELECT r.leftguid AS id
702
					FROM releases r
703
					LEFT JOIN categories c ON c.id = r.categories_id
704
					WHERE r.nzbstatus = %d
705
					AND r.passwordstatus BETWEEN -6 AND -1
706
					AND r.haspreview = -1
707
					AND c.disablepreview = 0
708
					%s %s
709
					GROUP BY r.leftguid
710
					LIMIT 16',
711
                NZB::NZB_ADDED,
712
                $ppAddMaxSize,
713
                $ppAddMinSize
714
            )
715
        );
716
        if (\count($ppQueue) > 0) {
717
            $this->processAdditional = true;
718
            $this->work = $ppQueue;
719
            $this->maxProcesses = (int) Settings::settingValue('..postthreads');
720
        }
721
722
        $this->postProcess($this->work, $this->maxProcesses);
723
    }
724
725
    private $nfoQueryString = '';
726
727
    /**
728
     * Check if we should process NFO's.
729
     *
730
     * @return bool
731
     * @throws \Exception
732
     */
733
    private function checkProcessNfo(): bool
734
    {
735
        if ((int) Settings::settingValue('..lookupnfo') === 1) {
736
            $this->nfoQueryString = Nfo::NfoQueryString();
737
738
            return DB::select(sprintf('SELECT r.id FROM releases r WHERE 1=1 %s LIMIT 1', $this->nfoQueryString)) > 0;
739
        }
740
741
        return false;
742
    }
743
744
    /**
745
     * @throws \Exception
746
     */
747
    private function postProcessNfo()
748
    {
749
        $this->maxProcesses = 1;
750
        if ($this->checkProcessNfo()) {
751
            $this->processNFO = true;
752
            $this->work = DB::select(
753
                sprintf(
754
                    '
755
					SELECT r.leftguid AS id
756
					FROM releases r
757
					WHERE 1=1 %s
758
					GROUP BY r.leftguid
759
					LIMIT 16',
760
                    $this->nfoQueryString
761
                )
762
            );
763
            $this->maxProcesses = (int) Settings::settingValue('..nfothreads');
764
        }
765
766
        $this->postProcess($this->work, $this->maxProcesses);
767
    }
768
769
    /**
770
     * @return bool
771
     * @throws \Exception
772
     */
773
    private function checkProcessMovies(): bool
774
    {
775
        if (Settings::settingValue('..lookupimdb') > 0) {
776
            return DB::select(sprintf('
777
						SELECT id
778
						FROM releases
779
						WHERE categories_id BETWEEN 5000 AND 5999
780
						AND nzbstatus = %d
781
						AND imdbid IS NULL
782
						%s %s
783
						LIMIT 1', NZB::NZB_ADDED, ((int) Settings::settingValue('..lookupimdb') === 2 ? 'AND isrenamed = 1' : ''), ($this->ppRenamedOnly ? 'AND isrenamed = 1' : ''))) > 0;
784
        }
785
786
        return false;
787
    }
788
789
    /**
790
     * @throws \Exception
791
     */
792
    private function postProcessMov()
793
    {
794
        $this->maxProcesses = 1;
795
        if ($this->checkProcessMovies()) {
796
            $this->processMovies = true;
797
            $this->work = DB::select(
798
                sprintf(
799
                    '
800
					SELECT leftguid AS id, %d AS renamed
801
					FROM releases
802
					WHERE categories_id BETWEEN 5000 AND 5999
803
					AND nzbstatus = %d
804
					AND imdbid IS NULL
805
					%s %s
806
					GROUP BY leftguid
807
					LIMIT 16',
808
                    ($this->ppRenamedOnly ? 2 : 1),
809
                    NZB::NZB_ADDED,
810
                    ((int) Settings::settingValue('..lookupimdb') === 2 ? 'AND isrenamed = 1' : ''),
811
                    ($this->ppRenamedOnly ? 'AND isrenamed = 1' : '')
812
                )
813
            );
814
            $this->maxProcesses = (int) Settings::settingValue('..postthreadsnon');
815
        }
816
817
        $this->postProcess($this->work, $this->maxProcesses);
818
    }
819
820
    /**
821
     * Check if we should process TV's.
822
     * @return bool
823
     * @throws \Exception
824
     */
825
    private function checkProcessTV()
826
    {
827
        if ((int) Settings::settingValue('..lookuptvrage') > 0) {
828
            return DB::select(sprintf('
829
						SELECT id
830
						FROM releases
831
						WHERE categories_id BETWEEN 5000 AND 5999
832
						AND nzbstatus = %d
833
						AND size > 1048576
834
						AND tv_episodes_id BETWEEN -2 AND 0
835
						%s %s
836
						', NZB::NZB_ADDED, (int) Settings::settingValue('..lookuptvrage') === 2 ? 'AND isrenamed = 1' : '', $this->ppRenamedOnly ? 'AND isrenamed = 1' : '')) > 0;
837
        }
838
839
        return false;
840
    }
841
842
    /**
843
     * @throws \Exception
844
     */
845
    private function postProcessTv()
846
    {
847
        $this->maxProcesses = 1;
848
        if ($this->checkProcessTV()) {
849
            $this->processTV = true;
850
            $this->work = DB::select(
851
                sprintf(
852
                    '
853
					SELECT leftguid AS id, %d AS renamed
854
					FROM releases
855
					WHERE categories_id BETWEEN 3000 AND 3999
856
					AND nzbstatus = %d
857
					AND tv_episodes_id BETWEEN -2 AND 0
858
					AND size > 1048576
859
					%s %s
860
					GROUP BY leftguid
861
					LIMIT 16',
862
                    ($this->ppRenamedOnly ? 2 : 1),
863
                    NZB::NZB_ADDED,
864
                    (int) Settings::settingValue('..lookuptvrage') === 2 ? 'AND isrenamed = 1' : '',
865
                    ($this->ppRenamedOnly ? 'AND isrenamed = 1' : '')
866
                )
867
            );
868
            $this->maxProcesses = (int) Settings::settingValue('..postthreadsnon');
869
        }
870
871
        $this->postProcess($this->work, $this->maxProcesses);
872
    }
873
874
    /**
875
     * Process sharing.
876
     * @return bool
877
     * @throws \Exception
878
     */
879
    private function processSharing()
880
    {
881
        $sharing = DB::select('SELECT enabled FROM sharing');
882
        if ($sharing > 0 && (int) $sharing[0]->enabled === 1) {
883
            $nntp = new NNTP();
884
            if ((int) (Settings::settingValue('..alternate_nntp') === 1 ? $nntp->doConnect(true, true) : $nntp->doConnect()) === true) {
0 ignored issues
show
introduced by
The condition (int)App\Models\Settings...p->doConnect() === true is always false.
Loading history...
introduced by
The condition App\Models\Settings::set....alternate_nntp') === 1 is always false.
Loading history...
885
                (new PostProcess(['ColorCLI' => $this->colorCli]))->processSharing($nntp);
886
            }
887
888
            return true;
889
        }
890
891
        return false;
892
    }
893
894
    /**
895
     * Process all that require a single thread.
896
     *
897
     * @throws \Exception
898
     */
899
    private function processSingle()
900
    {
901
        $postProcess = new PostProcess(['ColorCLI' => $this->colorCli]);
902
        //$postProcess->processAnime();
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
903
        $postProcess->processBooks();
904
        $postProcess->processConsoles();
905
        $postProcess->processGames();
906
        $postProcess->processMusic();
907
        $postProcess->processXXX();
908
    }
909
910
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
911
    ///////////////////////////////// All "update_per_Group" code goes here ////////////////////////////////////////////
912
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
913
914
    /**
915
     * @throws \Exception
916
     */
917
    private function updatePerGroup()
918
    {
919
        $this->work = DB::select('SELECT id , name FROM usenet_groups WHERE (active = 1 OR backfill = 1)');
920
921
        $maxProcess = (int) Settings::settingValue('..releasethreads');
922
923
        $pool = Pool::create()->concurrency($maxProcess)->timeout(config('nntmux.multiprocessing_max_child_time'));
924
        $this->processWork();
925
        foreach ($this->work as $group) {
926
            $pool->add(function () use ($group) {
927
                $this->_executeCommand($this->dnr_path.'update_per_group  '.$group->id.'"');
928
            })->then(function () use ($group) {
929
                $name = UsenetGroup::getNameByID($group->id);
930
                $this->colorCli->primary('Finished updating binaries, processing releases and additional postprocessing for group:'.$name);
931
            })->catch(function (\Throwable $exception) {
0 ignored issues
show
Unused Code introduced by
The parameter $exception is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

931
            })->catch(function (/** @scrutinizer ignore-unused */ \Throwable $exception) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
932
                // Handle exception
933
            });
934
        }
935
936
        $pool->wait();
937
    }
938
939
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
940
    //////////////////////////////////////////// Various methods ///////////////////////////////////////////////////////
941
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
942
943
    /**
944
     * Execute a shell command.
945
     *
946
     * @param string $command
947
     */
948
    protected function _executeCommand($command)
949
    {
950
        switch ($this->outputType) {
951
            case self::OUTPUT_NONE:
952
                exec($command);
953
                break;
954
            case self::OUTPUT_REALTIME:
955
                passthru($command);
956
                break;
957
            case self::OUTPUT_SERIALLY:
958
                echo shell_exec($command);
959
                break;
960
        }
961
    }
962
963
    /**
964
     * Echo a message to CLI.
965
     *
966
     * @param string $message
967
     */
968
    public function logger($message)
969
    {
970
        if (config('nntmux.echocli')) {
971
            echo $message.PHP_EOL;
972
        }
973
    }
974
975
    /**
976
     * This method is executed whenever a child is finished doing work.
977
     *
978
     * @param string $pid        The PID numbers.
979
     */
980
    public function exit($pid)
981
    {
982
        if (config('nntmux.echocli')) {
983
            $this->colorCli->header(
984
                'Process ID #'.$pid.' has completed.'.PHP_EOL.
985
                'There are '.($this->maxProcesses - 1).' process(es) still active with '.
986
                (--$this->_workCount).' job(s) left in the queue.',
987
                true
988
            );
989
        }
990
    }
991
}
992