Files
newznab-tmux/misc/update/tmux/monitor.php
T
2025-10-30 22:36:05 +01:00

413 lines
16 KiB
PHP

<?php
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
use App\Models\Category;
use App\Models\Release;
use App\Models\Settings;
use Blacklight\ColorCLI;
use Blacklight\Tmux;
use Blacklight\TmuxOutput;
use Blacklight\TmuxRun;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
$pdo = DB::connection()->getPdo();
$tMain = new Tmux;
$colorCli = new ColorCLI;
try {
$tRun = new TmuxRun;
} catch (Exception $e) {
echo $e;
}
try {
$tOut = new TmuxOutput;
} catch (Exception $e) {
echo $e;
}
$runVar['paths']['misc'] = base_path().'/misc/';
$runVar['paths']['cli'] = base_path().'/cli/';
$runVar['paths']['scraper'] = base_path().'/misc/IRCScraper/scrape.php';
$db_name = config('nntmux.db_name');
$tmux_niceness = Settings::settingValue('niceness') ?? 2;
$runVar['constants'] = $tRun->getConstantSettings();
// assign shell commands
$runVar['commands']['_php'] = " nice -n{$tmux_niceness} php";
$runVar['commands']['_phpn'] = "nice -n{$tmux_niceness} php";
$runVar['commands']['_sleep'] = "{$runVar['commands']['_phpn']} {$runVar['paths']['misc']}update/tmux/bin/showsleep.php";
// spawn IRCScraper as soon as possible
try {
$tRun->runPane('scraper', $runVar);
} catch (Exception $e) {
echo $e;
}
// get list of panes by name
$runVar['panes'] = $tRun->getListOfPanes($runVar['constants']);
// totals per category in db, results by parentID
$catCountQuery = 'SELECT c.root_categories_id AS parentid, COUNT(r.id) AS count FROM categories c, releases r WHERE r.categories_id = c.id GROUP BY c.root_categories_id';
// create timers and set to now
$runVar['timers']['timer1'] = $runVar['timers']['timer2'] = $runVar['timers']['timer3'] =
$runVar['timers']['timer4'] = $runVar['timers']['timer5'] = time();
$runVar['timers']['query']['tmux_time'] = $runVar['timers']['query']['split_time'] = $runVar['timers']['query']['init_time'] = $runVar['timers']['query']['proc1_time'] =
$runVar['timers']['query']['proc2_time'] = $runVar['timers']['query']['proc3_time'] = $runVar['timers']['query']['split1_time'] = $runVar['timers']['query']['init1_time'] =
$runVar['timers']['query']['proc11_time'] = $runVar['timers']['query']['proc21_time'] = $runVar['timers']['query']['proc31_time'] = $runVar['timers']['query']['tpg_time'] =
$runVar['timers']['query']['tpg1_time'] = 0;
$runVar['settings']['monitor'] = 0;
$runVar['counts']['iterations'] = 1;
$runVar['modsettings']['fc']['firstrun'] = true;
$runVar['modsettings']['fc']['num'] = 0;
$tblCount = 'SELECT TABLE_ROWS AS count FROM information_schema.TABLES WHERE TABLE_NAME = :table AND TABLE_SCHEMA = '.escapeString($db_name);
$psTableRowCount = $pdo->prepare($tblCount);
while ($runVar['counts']['iterations'] > 0) {
$timer01 = time();
// These queries are very fast, run every loop -- tmux and site settings
$runVar['settings'] = $tRun->getMonitorSettings();
$runVar['timers']['query']['tmux_time'] = (time() - $timer01);
$runVar['settings']['book_reqids'] = (! empty($runVar['settings']['book_reqids'])
? $runVar['settings']['book_reqids'] : Category::BOOKS_ROOT);
// get usenet connection info
$runVar['connections'] = $tOut->getConnectionsInfo($runVar['constants']);
$runVar['constants']['pre_lim'] = ($runVar['counts']['iterations'] > 1 ? '7' : '');
// assign scripts
$runVar['scripts']['releases'] = "{$runVar['commands']['_php']} {$runVar['paths']['misc']}update/multiprocessing/releases.php";
$runVar['scripts']['binaries'] = match ((int) $runVar['settings']['binaries_run']) {
1 => "{$runVar['commands']['_php']} {$runVar['paths']['misc']}update/multiprocessing/safe.php binaries",
default => 0,
};
switch ((int) $runVar['settings']['backfill']) {
case 1:
$runVar['scripts']['backfill'] = "{$runVar['commands']['_php']} {$runVar['paths']['misc']}update/multiprocessing/backfill.php";
break;
case 4:
$runVar['scripts']['backfill'] = "{$runVar['commands']['_php']} {$runVar['paths']['misc']}update/multiprocessing/safe.php backfill";
}
// get usenet connection counts
unset($runVar['conncounts']);
$runVar['conncounts'] = $tOut->getUSPConnections('primary', $runVar['connections']);
if ((int) $runVar['constants']['alternate_nntp'] === 1) {
$alternateConnections = $tOut->getUSPConnections('alternate', $runVar['connections']);
$runVar['conncounts'] = array_merge($runVar['conncounts'], $alternateConnections);
}
// run queries only after time exceeded, these queries can take awhile
if ((int) $runVar['counts']['iterations'] === 1 || (time() - $runVar['timers']['timer2'] >= $runVar['settings']['monitor'] && (int) $runVar['settings']['is_running'] === 1)) {
$runVar['counts']['proc1'] = $runVar['counts']['proc2'] = $runVar['counts']['proc3'] = $splitQry = $newOldQry = false;
$runVar['counts']['now']['total_work'] = 0;
$runVar['modsettings']['fix_crap'] = explode(', ', $runVar['settings']['fix_crap']);
$colorCli->info("\nThe numbers(queries) above are currently being refreshed. \nNo pane(script) can be (re)started until these have completed.\n");
$timer02 = time();
try {
$splitQry = $tRun->proc_query(4, null, $db_name);
} catch (Exception $e) {
echo $e;
}
try {
$newOldQry = $tRun->proc_query(6, null, $db_name);
} catch (Exception $e) {
echo $e;
}
$splitRes = (array) Arr::first(DB::select($splitQry));
$runVar['timers']['newOld'] = (array) Arr::first(DB::select($newOldQry));
// assign split query results to main var
foreach ($splitRes as $splitKey => $split) {
$runVar['counts']['now'][$splitKey] = $split;
}
$runVar['timers']['query']['split_time'] = (time() - $timer02);
$runVar['timers']['query']['split1_time'] = (time() - $timer01);
$timer03 = time();
$tvCount = Release::query()->whereBetween('categories_id', [Category::TV_ROOT, Category::TV_OTHER])->count(['id']);
$movieCount = Release::query()->whereBetween('categories_id', [Category::MOVIE_ROOT, Category::MOVIE_OTHER])->count(['id']);
$audioCount = Release::query()->whereBetween('categories_id', [Category::MUSIC_ROOT, Category::MUSIC_OTHER])->count(['id']);
$bookCount = Release::query()->whereBetween('categories_id', [Category::BOOKS_ROOT, Category::BOOKS_UNKNOWN])->count(['id']);
$consoleCount = Release::query()->whereBetween('categories_id', [Category::GAME_ROOT, Category::GAME_OTHER])->count(['id']);
$pcCount = Release::query()->whereBetween('categories_id', [Category::PC_ROOT, Category::PC_PHONE_ANDROID])->count(['id']);
$xxxCount = Release::query()->whereBetween('categories_id', [Category::XXX_ROOT, Category::XXX_OTHER])->count(['id']);
$miscCount = Release::query()->whereBetween('categories_id', [Category::OTHER_ROOT, Category::OTHER_HASHED])->count(['id']);
$runVar['counts']['now']['audio'] = $audioCount;
$runVar['counts']['now']['books'] = $bookCount;
$runVar['counts']['now']['console'] = $consoleCount;
$runVar['counts']['now']['misc'] = $miscCount;
$runVar['counts']['now']['movies'] = $movieCount;
$runVar['counts']['now']['pc'] = $pcCount;
$runVar['counts']['now']['tv'] = $tvCount;
$runVar['counts']['now']['xxx'] = $xxxCount;
$runVar['timers']['query']['init_time'] = (time() - $timer03);
$runVar['timers']['query']['init1_time'] = (time() - $timer01);
$timer04 = time();
try {
$proc1qry = $tRun->proc_query(1, $runVar['settings']['book_reqids'], $db_name);
} catch (Exception $e) {
echo $e;
}
$proc1res = (array) Arr::first(DB::select($proc1qry));
$runVar['timers']['query']['proc1_time'] = (time() - $timer04);
$runVar['timers']['query']['proc11_time'] = (time() - $timer01);
$timer05 = time();
try {
$proc2qry = $tRun->proc_query(2, $runVar['settings']['book_reqids'], $db_name, $runVar['settings']['maxsize_pp'], $runVar['settings']['minsize_pp']);
} catch (Exception $e) {
echo $e;
}
$proc2res = (array) Arr::first(DB::select($proc2qry));
$runVar['timers']['query']['proc2_time'] = (time() - $timer05);
$runVar['timers']['query']['proc21_time'] = (time() - $timer01);
// Need to remove this
$timer06 = time();
$runVar['timers']['query']['proc3_time'] = (time() - $timer06);
$runVar['timers']['query']['proc31_time'] = (time() - $timer01);
$timer07 = time();
$tables = $tMain->cbpmTableQuery();
$age = time();
$runVar['counts']['now']['collections_table'] = $runVar['counts']['now']['binaries_table'] = 0;
$runVar['counts']['now']['parts_table'] = $runVar['counts']['now']['parterpair_table'] = 0;
if ($psTableRowCount === false) {
echo 'Unable to prepare statement, skipping monitor updates!';
} else {
foreach ($tables as $row) {
$tbl = $row->name;
$stamp = 'UNIX_TIMESTAMP(MIN(dateadded))';
switch (true) {
case str_contains($tbl, 'collections'):
$runVar['counts']['now']['collections_table'] +=
getTableRowCount($psTableRowCount, $tbl);
$added = DB::select(sprintf('SELECT %s AS dateadded FROM %s', $stamp, $tbl));
if (isset($added['dateadded']) && is_numeric($added['dateadded']) &&
$added['dateadded'] < $age
) {
$age = $added['dateadded'];
}
break;
case str_contains($tbl, 'binaries'):
$runVar['counts']['now']['binaries_table'] +=
getTableRowCount($psTableRowCount, $tbl);
break;
// This case must come before the 'parts_' one.
case str_contains($tbl, 'missed_parts'):
$runVar['counts']['now']['missed_parts_table'] +=
getTableRowCount($psTableRowCount, $tbl);
break;
case str_contains($tbl, 'parts'):
$runVar['counts']['now']['parts_table'] +=
getTableRowCount($psTableRowCount, $tbl);
break;
default:
}
}
$runVar['timers']['newOld']['oldestcollection'] = $age;
// free up memory used by now stale data
unset($age, $added, $tables);
$runVar['timers']['query']['tpg_time'] = (time() - $timer07);
$runVar['timers']['query']['tpg1_time'] = (time() - $timer01);
}
$runVar['timers']['timer2'] = time();
// assign postprocess values from $proc
if (is_array($proc1res)) {
foreach ($proc1res as $proc1key => $proc1) {
$runVar['counts']['now'][$proc1key] = $proc1;
}
} else {
errorOnSQL();
}
if (is_array($proc2res)) {
foreach ($proc2res as $proc2key => $proc2) {
$runVar['counts']['now'][$proc2key] = $proc2;
}
} else {
errorOnSQL();
}
// now that we have merged our query data we can unset these to free up memory
unset($proc1res, $proc2res, $splitRes);
// Zero out any post proc counts when that type of pp has been turned off
foreach ($runVar['settings'] as $settingKey => $setting) {
if ((int) $setting === 0 && (int) strpos($settingKey, 'process') === 0) {
$runVar['counts']['now'][$settingKey] = $runVar['counts']['start'][$settingKey] = 0;
}
if ($settingKey === 'fix_names' && (int) $setting === 0) {
$runVar['counts']['now']['processrenames'] = $runVar['counts']['start']['processrenames'] = 0;
}
}
// set initial start postproc values from work queries -- this is used to determine diff variables
if ((int) $runVar['counts']['iterations'] === 1) {
$runVar['counts']['start'] = $runVar['counts']['now'];
}
foreach ($runVar['counts']['now'] as $key => $proc) {
// if key is a process type, add it to total_work
if (str_starts_with($key, 'process')) {
$runVar['counts']['now']['total_work'] += $proc;
}
// calculate diffs
$runVar['counts']['diff'][$key] = number_format($proc - $runVar['counts']['start'][$key]);
// calculate percentages -- if user has no releases, set 0 for each key or this will fail on divide by zero
$runVar['counts']['percent'][$key] = $runVar['counts']['now']['releases'] > 0
? sprintf('%02s', floor(($proc / $runVar['counts']['now']['releases']) * 100)) : 0;
}
$runVar['counts']['now']['total_work'] += $runVar['counts']['now']['work'];
// Set initial total work count for diff
if ((int) $runVar['counts']['iterations'] === 1) {
$runVar['counts']['start']['total_work'] = $runVar['counts']['now']['total_work'];
}
// Set diff total work count
$runVar['counts']['diff']['total_work'] = number_format($runVar['counts']['now']['total_work'] - $runVar['counts']['start']['total_work']);
}
// set kill switches
$runVar['killswitch']['pp'] = (($runVar['settings']['postprocess_kill'] < $runVar['counts']['now']['total_work']) && ((int) $runVar['settings']['postprocess_kill'] !== 0));
$runVar['killswitch']['coll'] = (($runVar['settings']['collections_kill'] < $runVar['counts']['now']['collections_table']) && ((int) $runVar['settings']['collections_kill'] !== 0));
$tOut->updateMonitorPane($runVar);
// begin pane run execution
if ((int) $runVar['settings']['is_running'] === 1) {
// run main updating function(s)
try {
$tRun->runPane('main', $runVar);
} catch (Exception $e) {
echo $e;
}
// run postprocess_releases amazon
try {
$tRun->runPane('amazon', $runVar);
} catch (Exception $e) {
echo $e;
}
// respawn IRCScraper if it has been killed
try {
$tRun->runPane('scraper', $runVar);
} catch (Exception $e) {
echo $e;
}
// update tv and theaters
try {
$tRun->runPane('updatetv', $runVar);
} catch (Exception $e) {
echo $e;
}
// run these if complete sequential not set
if ((int) $runVar['constants']['sequential'] !== 2) {
// fix names
try {
$tRun->runPane('fixnames', $runVar);
} catch (Exception $e) {
echo $e;
}
// dehash releases
try {
$tRun->runPane('dehash', $runVar);
} catch (Exception $e) {
echo $e;
}
// Remove crap releases.
try {
$tRun->runPane('removecrap', $runVar);
} catch (Exception $e) {
echo $e;
}
// run postprocess_releases additional
try {
$tRun->runPane('ppadditional', $runVar);
} catch (Exception $e) {
echo $e;
}
// run postprocess_releases non amazon
try {
$tRun->runPane('nonamazon', $runVar);
} catch (Exception $e) {
echo $e;
}
}
} elseif ((int) $runVar['settings']['is_running'] === 0) {
try {
$tRun->runPane('notrunning', $runVar);
} catch (Exception $e) {
echo $e;
}
}
$exit = Settings::settingValue('exit');
if ((int) $exit === 0) {
$runVar['counts']['iterations']++;
sleep(10);
} else {
// Set counter to less than one so the loop will exit.
$runVar['counts']['iterations'] = ($exit < 0) ? $exit : 0;
}
}
function errorOnSQL()
{
(new ColorCLI)->error(PHP_EOL.'Monitor encountered severe errors retrieving process data from MySQL. Please diagnose and try running again.'.PHP_EOL);
}
/**
* @return bool|int|string
*/
function getTableRowCount(PDOStatement $ps, $table)
{
if ($ps->execute([':table' => $table])) {
$result = $ps->fetch();
return is_numeric($result['count']) ? $result['count'] : 0;
}
return false;
}