Passed
Push — dev ( 6efead...54dc54 )
by Darko
06:52
created

Tmux::command_exist()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 5
ccs 0
cts 1
cp 0
rs 10
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
namespace Blacklight;
4
5
use App\Models\Category;
6
use App\Models\Settings;
7
use Illuminate\Support\Carbon;
8
use Illuminate\Support\Facades\DB;
9
10
/**
11
 * Class Tmux.
12
 */
13
class Tmux
14
{
15
    /**
16
     * @var \PDO
17
     */
18
    public $pdo;
19
20
    /**
21
     * @var
22
     */
23
    public $tmux_session;
24
25
    /**
26
     * @var \Blacklight\ColorCLI
27
     */
28
    protected $colorCli;
29
30
    /**
31
     * Tmux constructor.
32
     */
33
    public function __construct()
34
    {
35
        $this->pdo = DB::connection()->getPdo();
36
        $this->colorCli = new ColorCLI();
37
    }
38
39
    /**
40
     * @param $constants
41
     *
42
     * @return mixed
43
     */
44
    public function getConnectionsInfo($constants)
45
    {
46
        $runVar['connections']['port_a'] = $runVar['connections']['host_a'] = $runVar['connections']['ip_a'] = false;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$runVar was never initialized. Although not strictly required by PHP, it is generally a good practice to add $runVar = array(); before regardless.
Loading history...
47
        $runVar['connections']['port'] = config('nntmux_nntp.port');
48
        $runVar['connections']['host'] = config('nntmux_nntp.server');
49
        $runVar['connections']['ip'] = gethostbyname($runVar['connections']['host']);
50
        if ($constants['alternate_nntp'] === '1') {
51
            $runVar['connections']['port_a'] = config('nntmux_nntp.alternate_server_port');
52
            $runVar['connections']['host_a'] = config('nntmux_nntp.alternate_server');
53
            $runVar['connections']['ip_a'] = gethostbyname($runVar['connections']['host_a']);
54
        }
55
56
        return $runVar['connections'];
57
    }
58
59
    /**
60
     * @param $which
61
     * @param $connections
62
     *
63
     * @return mixed
64
     */
65
    public function getUSPConnections($which, $connections)
66
    {
67
        switch ($which) {
68
            case 'alternate':
69
                $ip = 'ip_a';
70
                $port = 'port_a';
71
                break;
72
            case 'primary':
73
            default:
74
                $ip = 'ip';
75
                $port = 'port';
76
                break;
77
        }
78
79
        $runVar['conncounts'][$which]['active'] = str_replace("\n", '', shell_exec('ss -n | grep '.$connections[$ip].':'.$connections[$port].' | grep -c ESTAB'));
0 ignored issues
show
Comprehensibility Best Practice introduced by
$runVar was never initialized. Although not strictly required by PHP, it is generally a good practice to add $runVar = array(); before regardless.
Loading history...
80
        $runVar['conncounts'][$which]['total'] = str_replace("\n", '', shell_exec('ss -n | grep -c '.$connections[$ip].':'.$connections[$port]));
81
82
        if ((int) $runVar['conncounts'][$which]['active'] === 0 && (int) $runVar['conncounts'][$which]['total'] === 0) {
83
            $runVar['conncounts'][$which]['active'] = str_replace("\n", '', shell_exec('ss -n | grep '.$connections[$ip].':https | grep -c ESTAB'));
84
            $runVar['conncounts'][$which]['total'] = str_replace("\n", '', shell_exec('ss -n | grep -c '.$connections[$ip].':https'));
85
        }
86
        if ((int) $runVar['conncounts'][$which]['active'] === 0 && (int) $runVar['conncounts'][$which]['total'] === 0) {
87
            $runVar['conncounts'][$which]['active'] = str_replace("\n", '', shell_exec('ss -n | grep '.$connections[$port].' | grep -c ESTAB'));
88
            $runVar['conncounts'][$which]['total'] = str_replace("\n", '', shell_exec('ss -n | grep -c '.$connections[$port]));
89
        }
90
        if ((int) $runVar['conncounts'][$which]['active'] === 0 && (int) $runVar['conncounts'][$which]['total'] === 0) {
91
            $runVar['conncounts'][$which]['active'] = str_replace("\n", '', shell_exec('ss -n | grep '.$connections[$ip].' | grep -c ESTAB'));
92
            $runVar['conncounts'][$which]['total'] = str_replace("\n", '', shell_exec('ss -n | grep -c '.$connections[$ip]));
93
        }
94
95
        return $runVar['conncounts'];
96
    }
97
98
    /**
99
     * @param $constants
100
     *
101
     * @return array
102
     */
103
    public function getListOfPanes($constants): array
104
    {
105
        $panes = ['zero' => '', 'one' => '', 'two' => ''];
106
        switch ($constants['sequential']) {
107
            case 0:
108
            case 1:
109
                $panes_win_1 = shell_exec("echo `tmux list-panes -t {$constants['tmux_session']}:0 -F '#{pane_title}'`");
110
                $panes['zero'] = str_replace("\n", '', explode(' ', $panes_win_1));
111
                $panes_win_2 = shell_exec("echo `tmux list-panes -t {$constants['tmux_session']}:1 -F '#{pane_title}'`");
112
                $panes['one'] = str_replace("\n", '', explode(' ', $panes_win_2));
113
                $panes_win_3 = shell_exec("echo `tmux list-panes -t {$constants['tmux_session']}:2 -F '#{pane_title}'`");
114
                $panes['two'] = str_replace("\n", '', explode(' ', $panes_win_3));
115
                break;
116
            case 2:
117
                $panes_win_1 = shell_exec("echo `tmux list-panes -t {$constants['tmux_session']}:0 -F '#{pane_title}'`");
118
                $panes['zero'] = str_replace("\n", '', explode(' ', $panes_win_1));
119
                $panes_win_2 = shell_exec("echo `tmux list-panes -t {$constants['tmux_session']}:1 -F '#{pane_title}'`");
120
                $panes['one'] = str_replace("\n", '', explode(' ', $panes_win_2));
121
                break;
122
        }
123
124
        return $panes;
125
    }
126
127
    /**
128
     * @return string
129
     */
130
    public function getConstantSettings(): string
131
    {
132
        $settstr = 'SELECT value FROM settings WHERE setting =';
133
134
        $sql = sprintf(
135
            "SELECT
136
					(%1\$s 'sequential') AS sequential,
137
					(%1\$s 'tmux_session') AS tmux_session,
138
					(%1\$s 'run_ircscraper') AS run_ircscraper,
139
					(%1\$s 'alternate_nntp') AS alternate_nntp,
140
					(%1\$s 'delaytime') AS delaytime",
141
            $settstr
142
        );
143
144
        return $sql;
145
    }
146
147
    /**
148
     * @return string
149
     */
150
    public function getMonitorSettings(): string
151
    {
152
        $settstr = 'SELECT value FROM settings WHERE setting =';
153
154
        $sql = sprintf(
155
            "SELECT
156
					(%1\$s 'monitor_delay') AS monitor,
157
					(%1\$s 'binaries') AS binaries_run,
158
					(%1\$s 'backfill') AS backfill,
159
					(%1\$s 'backfill_qty') AS backfill_qty,
160
					(%1\$s 'import') AS import,
161
					(%1\$s 'nzbs') AS nzbs,
162
					(%1\$s 'post') AS post,
163
					(%1\$s 'releases') AS releases_run,
164
					(%1\$s 'releases_threaded') AS releases_threaded,
165
					(%1\$s 'fix_names') AS fix_names,
166
					(%1\$s 'seq_timer') AS seq_timer,
167
					(%1\$s 'bins_timer') AS bins_timer,
168
					(%1\$s 'back_timer') AS back_timer,
169
					(%1\$s 'import_count') AS import_count,
170
					(%1\$s 'import_timer') AS import_timer,
171
					(%1\$s 'rel_timer') AS rel_timer,
172
					(%1\$s 'fix_timer') AS fix_timer,
173
					(%1\$s 'post_timer') AS post_timer,
174
					(%1\$s 'collections_kill') AS collections_kill,
175
					(%1\$s 'postprocess_kill') AS postprocess_kill,
176
					(%1\$s 'crap_timer') AS crap_timer,
177
					(%1\$s 'fix_crap') AS fix_crap,
178
					(%1\$s 'fix_crap_opt') AS fix_crap_opt,
179
					(%1\$s 'tv_timer') AS tv_timer,
180
					(%1\$s 'update_tv') AS update_tv,
181
					(%1\$s 'post_kill_timer') AS post_kill_timer,
182
					(%1\$s 'monitor_path') AS monitor_path,
183
					(%1\$s 'monitor_path_a') AS monitor_path_a,
184
					(%1\$s 'monitor_path_b') AS monitor_path_b,
185
					(%1\$s 'progressive') AS progressive,
186
					(%1\$s 'dehash') AS dehash,
187
					(%1\$s 'dehash_timer') AS dehash_timer,
188
					(%1\$s 'backfill_days') AS backfilldays,
189
					(%1\$s 'post_amazon') AS post_amazon,
190
					(%1\$s 'post_timer_amazon') AS post_timer_amazon,
191
					(%1\$s 'post_non') AS post_non,
192
					(%1\$s 'post_timer_non') AS post_timer_non,
193
					(%1\$s 'colors_start') AS colors_start,
194
					(%1\$s 'colors_end') AS colors_end,
195
					(%1\$s 'colors_exc') AS colors_exc,
196
					(%1\$s 'showquery') AS show_query,
197
					(%1\$s 'running') AS is_running,
198
					(%1\$s 'run_sharing') AS run_sharing,
199
					(%1\$s 'sharing_timer') AS sharing_timer,
200
					(%1\$s 'lookupbooks') AS processbooks,
201
					(%1\$s 'lookupmusic') AS processmusic,
202
					(%1\$s 'lookupgames') AS processgames,
203
					(%1\$s 'lookupxxx') AS processxxx,
204
					(%1\$s 'lookupimdb') AS processmovies,
205
					(%1\$s 'lookuptvrage') AS processtvrage,
206
					(%1\$s 'lookupanidb') AS processanime,
207
					(%1\$s 'lookupnfo') AS processnfo,
208
					(%1\$s 'lookuppar2') AS processpar2,
209
					(%1\$s 'nzbthreads') AS nzbthreads,
210
					(%1\$s 'tmpunrarpath') AS tmpunrar,
211
					(%1\$s 'compressedheaders') AS compressed,
212
					(%1\$s 'maxsizetopostprocess') AS maxsize_pp,
213
					(%1\$s 'minsizetopostprocess') AS minsize_pp",
214
            $settstr
215
        );
216
217
        return $sql;
218
    }
219
220
    /**
221
     * @param $setting
222
     * @param $value
223
     *
224
     * @return int
225
     */
226
    public function updateItem($setting, $value)
227
    {
228
        return Settings::query()->where('setting', '=', $setting)->update(['value' => $value]);
229
    }
230
231
    /**
232
     * @return float
233
     */
234
    public function microtime_float(): float
235
    {
236
        [$usec, $sec] = explode(' ', microtime());
237
238
        return (float) $usec + (float) $sec;
239
    }
240
241
    /**
242
     * @param float $bytes
243
     *
244
     * @return string
245
     */
246
    public function decodeSize($bytes): string
247
    {
248
        $types = ['B', 'KB', 'MB', 'GB', 'TB'];
249
        $suffix = 'B';
250
        foreach ($types as $type) {
251
            if ($bytes < 1024.0) {
252
                $suffix = $type;
253
                break;
254
            }
255
            $bytes /= 1024;
256
        }
257
258
        return round($bytes, 2).' '.$suffix;
259
    }
260
261
    /**
262
     * @param $pane
263
     *
264
     * @return string
265
     */
266
    public function writelog($pane): ?string
267
    {
268
        $path = NN_LOGS;
269
        $getdate = gmdate('Ymd');
270
        $logs = Settings::settingValue('site.tmux.write_logs') ?? 0;
271
        if ($logs === 1) {
272
            return "2>&1 | tee -a $path/$pane-$getdate.log";
273
        }
274
275
        return '';
276
    }
277
278
    /**
279
     * @param $colors_start
280
     * @param $colors_end
281
     * @param $colors_exc
282
     *
283
     * @return int
284
     * @throws \Exception
285
     */
286
    public function get_color($colors_start, $colors_end, $colors_exc): int
287
    {
288
        $exception = str_replace('.', '.', $colors_exc);
289
        $exceptions = explode(',', $exception);
290
        sort($exceptions);
291
        $number = random_int($colors_start, $colors_end - \count($exceptions));
292
        foreach ($exceptions as $exception) {
293
            if ($number >= $exception) {
294
                $number++;
295
            } else {
296
                break;
297
            }
298
        }
299
300
        return $number;
301
    }
302
303
    /**
304
     * Returns random bool, weighted by $chance.
305
     *
306
     *
307
     * @param     $loop
308
     * @param int $chance
309
     *
310
     * @return bool
311
     * @throws \Exception
312
     */
313
    public function rand_bool($loop, $chance = 60): bool
314
    {
315
        $usecache = Settings::settingValue('site.tmux.usecache') ?? 0;
316
        if ($loop === 1 || $usecache === 0) {
317
            return false;
318
        }
319
320
        return random_int(1, 100) <= $chance;
321
    }
322
323
    /**
324
     * @param $_time
325
     *
326
     * @return string
327
     */
328
    public function relativeTime($_time): string
329
    {
330
        $time = Carbon::createFromTimestamp($_time);
331
332
        return $time->ago();
333
    }
334
335
    /**
336
     * @param $cmd
337
     *
338
     * @return bool
339
     */
340
    public function command_exist($cmd): bool
341
    {
342
        $returnVal = shell_exec("which $cmd 2>/dev/null");
343
344
        return empty($returnVal) ? false : true;
345
    }
346
347
    /**
348
     * @param        $qry
349
     * @param        $bookreqids
350
     * @param string $db_name
351
     * @param string $ppmax
352
     * @param string $ppmin
353
     *
354
     * @return bool|string
355
     * @throws \Exception
356
     */
357
    public function proc_query($qry, $bookreqids, $db_name, $ppmax = '', $ppmin = '')
358
    {
359
        switch ((int) $qry) {
360
            case 1:
361
                return sprintf(
362
                    '
363
					SELECT
364
					SUM(IF(nzbstatus = %d AND categories_id BETWEEN %d AND %d AND categories_id != %d AND videos_id = 0 AND tv_episodes_id BETWEEN -3 AND 0 AND size > 1048576,1,0)) AS processtv,
365
					SUM(IF(nzbstatus = %1$d AND categories_id = %d AND anidbid IS NULL,1,0)) AS processanime,
366
					SUM(IF(nzbstatus = %1$d AND categories_id BETWEEN %d AND %d AND imdbid IS NULL,1,0)) AS processmovies,
367
					SUM(IF(nzbstatus = %1$d AND categories_id IN (%d, %d, %d) AND musicinfo_id IS NULL,1,0)) AS processmusic,
368
					SUM(IF(nzbstatus = %1$d AND categories_id BETWEEN %d AND %d AND consoleinfo_id IS NULL,1,0)) AS processconsole,
369
					SUM(IF(nzbstatus = %1$d AND categories_id IN (%s) AND bookinfo_id IS NULL,1,0)) AS processbooks,
370
					SUM(IF(nzbstatus = %1$d AND categories_id = %d AND gamesinfo_id = 0,1,0)) AS processgames,
371
					SUM(IF(nzbstatus = %1$d AND categories_id BETWEEN %d AND %d AND xxxinfo_id = 0,1,0)) AS processxxx,
372
					SUM(IF(1=1 %s,1,0)) AS processnfo,
373
					SUM(IF(nzbstatus = %1$d AND isrenamed = %d AND predb_id = 0 AND passwordstatus >= 0 AND nfostatus > %d
374
						AND ((nfostatus = %d AND proc_nfo = %d) OR proc_files = %d OR proc_par2 = %d
375
							OR (ishashed = 1 AND dehashstatus BETWEEN -6 AND 0)) AND categories_id IN (%s),1,0)) AS processrenames,
376
					SUM(IF(isrenamed = %d,1,0)) AS renamed,
377
					SUM(IF(nzbstatus = %1$d AND nfostatus = %20$d,1,0)) AS nfo,
378
					SUM(IF(predb_id > 0,1,0)) AS predb_matched,
379
					COUNT(DISTINCT(predb_id)) AS distinct_predb_matched
380
					FROM releases r',
381
                    NZB::NZB_ADDED,
382
                    Category::TV_ROOT,
383
                    Category::TV_OTHER,
384
                    Category::TV_ANIME,
385
                    Category::TV_ANIME,
386
                    Category::MOVIE_ROOT,
387
                    Category::MOVIE_OTHER,
388
                    Category::MUSIC_MP3,
389
                    Category::MUSIC_LOSSLESS,
390
                    Category::MUSIC_OTHER,
391
                    Category::GAME_ROOT,
392
                    Category::GAME_OTHER,
393
                    $bookreqids,
394
                    Category::PC_GAMES,
395
                    Category::XXX_ROOT,
396
                    Category::XXX_X264,
397
                    Nfo::NfoQueryString(),
398
                    NameFixer::IS_RENAMED_NONE,
399
                    Nfo::NFO_UNPROC,
400
                    Nfo::NFO_FOUND,
401
                    NameFixer::PROC_NFO_NONE,
402
                    NameFixer::PROC_FILES_NONE,
403
                    NameFixer::PROC_PAR2_NONE,
404
                    Category::getCategoryOthersGroup(),
405
                    NameFixer::IS_RENAMED_DONE
406
                );
407
408
            case 2:
409
                $ppminString = $ppmaxString = '';
410
                if (is_numeric($ppmax) && ! empty($ppmax)) {
411
                    $ppmax *= 1073741824;
412
                    $ppmaxString = "AND r.size < {$ppmax}";
413
                }
414
                if (is_numeric($ppmin) && ! empty($ppmin)) {
415
                    $ppmin *= 1048576;
416
                    $ppminString = "AND r.size > {$ppmin}";
417
                }
418
419
                return "SELECT
420
					(SELECT COUNT(r.id) FROM releases r
421
						LEFT JOIN categories c ON c.id = r.categories_id
422
						WHERE r.nzbstatus = 1
423
						AND r.passwordstatus = -1
424
						AND r.haspreview = -1
425
						{$ppminString}
426
						{$ppmaxString}
427
						AND c.disablepreview = 0
428
					) AS work,
429
					(SELECT COUNT(id) FROM usenet_groups WHERE active = 1) AS active_groups,
430
					(SELECT COUNT(id) FROM usenet_groups WHERE name IS NOT NULL) AS all_groups";
431
432
            case 4:
433
                return sprintf(
434
                    "
435
					SELECT
436
					(SELECT TABLE_ROWS FROM information_schema.TABLES WHERE table_name = 'predb' AND TABLE_SCHEMA = %1\$s) AS predb,
437
					(SELECT TABLE_ROWS FROM information_schema.TABLES WHERE table_name = 'missed_parts' AND TABLE_SCHEMA = %1\$s) AS missed_parts_table,
438
					(SELECT TABLE_ROWS FROM information_schema.TABLES WHERE table_name = 'parts' AND TABLE_SCHEMA = %1\$s) AS parts_table,
439
					(SELECT TABLE_ROWS FROM information_schema.TABLES WHERE table_name = 'binaries' AND TABLE_SCHEMA = %1\$s) AS binaries_table,
440
					(SELECT TABLE_ROWS FROM information_schema.TABLES WHERE table_name = 'collections' AND TABLE_SCHEMA = %1\$s) AS collections_table,
441
					(SELECT TABLE_ROWS FROM information_schema.TABLES WHERE table_name = 'releases' AND TABLE_SCHEMA = %1\$s) AS releases,
442
					(SELECT COUNT(id) FROM usenet_groups WHERE first_record IS NOT NULL AND backfill = 1
443
						AND (now() - INTERVAL backfill_target DAY) < first_record_postdate
444
					) AS backfill_groups_days,
445
					(SELECT COUNT(id) FROM usenet_groups WHERE first_record IS NOT NULL AND backfill = 1 AND (now() - INTERVAL datediff(curdate(),
446
					(SELECT VALUE FROM settings WHERE setting = 'safebackfilldate')) DAY) < first_record_postdate) AS backfill_groups_date",
447
                    escapeString($db_name)
448
                );
449
            case 6:
450
                return 'SELECT
451
					(SELECT searchname FROM releases ORDER BY id DESC LIMIT 1) AS newestrelname,
452
					(SELECT UNIX_TIMESTAMP(MIN(dateadded)) FROM collections) AS oldestcollection,
453
					(SELECT UNIX_TIMESTAMP(MAX(predate)) FROM predb) AS newestpre,
454
					(SELECT UNIX_TIMESTAMP(adddate) FROM releases ORDER BY id DESC LIMIT 1) AS newestrelease';
455
            default:
456
                return false;
457
        }
458
    }
459
460
    /**
461
     * @return bool true if tmux is running, false otherwise.
462
     * @throws \RuntimeException
463
     */
464
    public function isRunning(): bool
465
    {
466
        $running = Settings::query()->where(['section' => 'site', 'subsection' => 'tmux', 'setting' => 'running'])->first(['value']);
467
        if ($running === null) {
468
            throw new \RuntimeException('Tmux\\\'s running flag was not found in the database.'.PHP_EOL.'Please check the tables are correctly setup.'.PHP_EOL);
469
        }
470
471
        return ! ((int) $running->value === 0);
472
    }
473
474
    /**
475
     * @return bool
476
     * @throws \Exception
477
     */
478
    public function stopIfRunning(): bool
479
    {
480
        if ($this->isRunning() === true) {
481
            Settings::query()->where(['section' => 'site', 'subsection' => 'tmux', 'setting' => 'running'])->update(['value' => 0]);
482
            $sleep = Settings::settingValue('site.tmux.monitor_delay');
483
            $this->colorCli->header('Stopping tmux scripts and waiting '.$sleep.' seconds for all panes to shutdown');
484
            sleep($sleep);
0 ignored issues
show
Bug introduced by
$sleep of type App\Models\Settings is incompatible with the type integer expected by parameter $seconds of sleep(). ( Ignorable by Annotation )

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

484
            sleep(/** @scrutinizer ignore-type */ $sleep);
Loading history...
485
486
            return true;
487
        }
488
        $this->colorCli->info('Tmux scripts are not running!');
489
490
        return false;
491
    }
492
493
    /**
494
     * @throws \RuntimeException
495
     */
496
    public function startRunning(): void
497
    {
498
        if ($this->isRunning() === false) {
499
            Settings::query()->where(['section' => 'site', 'subsection' => 'tmux', 'setting' => 'running'])->update(['value' => 1]);
500
        }
501
    }
502
503
    /**
504
     * @return array
505
     */
506
    public function cbpmTableQuery()
507
    {
508
        return DB::select(
509
            "
510
			SELECT TABLE_NAME AS name
511
      		FROM information_schema.TABLES
512
      		WHERE TABLE_SCHEMA = (SELECT DATABASE())
513
			AND TABLE_NAME REGEXP {escapeString('^(multigroup_)?(collections|binaries|parts|missed_parts)(_[0-9]+)?$')}
514
			ORDER BY TABLE_NAME ASC"
515
        );
516
    }
517
}
518