Files
newznab-tmux/app/Console/Commands/ProcessAdditionalGuid.php
T
2026-08-14 08:46:01 +02:00

177 lines
6.1 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Facades\Search;
use App\Models\Release;
use App\Services\AdditionalProcessing\AdditionalProcessingOrchestrator;
use App\Services\AdditionalProcessing\DTO\ReleaseProcessingResult;
use Illuminate\Console\Command;
class ProcessAdditionalGuid extends Command
{
protected $signature = 'releases:additional
{guid? : Release GUID (optional if using --id)}
{--id= : Numeric release ID to run additional postprocessing on (alternative to GUID)}
{--reset : Reset key additional postprocessing flags before running}
{--no-progress : Suppress progress / status output (forces quiet mode)}
{--profile : Display stage, network, and persistence metrics}';
protected $description = 'Run additional postprocessing for a specific release by GUID or ID regardless of prior postprocessing status';
public function handle(): int
{
$guidArg = trim((string) $this->argument('guid'));
$idOpt = $this->option('id');
if ($guidArg === '' && ($idOpt === null || $idOpt === '')) {
$this->error('You must supply either a GUID argument or --id=<release id>.');
return 1; // missing identifier
}
if ($guidArg !== '' && $idOpt !== null && $idOpt !== '') {
$this->error('Provide only one identifier: GUID or --id, not both.');
return 4; // conflicting identifiers
}
$release = null;
$guid = '';
if ($idOpt !== null && $idOpt !== '') {
if (! ctype_digit((string) $idOpt)) {
$this->error('Release ID must be numeric.');
return 5; // invalid id format
}
$release = Release::find((int) $idOpt);
if ($release === null) {
$this->error('Release not found for ID: '.$idOpt);
return 2; // not found
}
$guid = $release->guid;
} else {
$guid = $guidArg;
if ($guid === '') { // should not happen but guard
$this->error('GUID is required if --id not supplied.');
return 1;
}
$release = Release::where('guid', $guid)->first();
if ($release === null) {
$this->error('Release not found for GUID: '.$guid);
return 2;
}
}
if ($this->option('reset')) {
Release::where('id', $release->id)->update([
'passwordstatus' => -1,
'haspreview' => -1,
'jpgstatus' => 0,
'videostatus' => 0,
'nfostatus' => -1,
]);
Search::updateRelease((int) $release->id);
$this->info('Reset postprocessing flags for release ID '.$release->id.' (GUID '.$guid.')');
}
if ($this->option('no-progress')) {
config(['nntmux.echocli' => false]);
}
$processor = app(AdditionalProcessingOrchestrator::class);
try {
$result = $processor->processSingleGuid($guid);
} finally {
$processor->finish();
}
$identifier = $idOpt ? 'ID '.$idOpt : 'GUID '.$guid;
$this->displayResult($result, $identifier);
if ($this->option('profile')) {
$this->displayProfile($result);
}
if (! $result->isSuccessful()) {
return 3;
}
return 0;
}
private function displayResult(ReleaseProcessingResult $result, string $identifier): void
{
$rows = [
['Release', $identifier],
['Pipeline', 'v2'],
['Outcome', $result->outcome->value],
['Artifacts created', $result->artifactsCreated ? 'yes' : 'no'],
['Release files added', (string) $result->releaseFilesAdded],
['Duration', number_format($result->elapsedSeconds, 3).' seconds'],
];
if ($result->reason !== '') {
$rows[] = ['Reason', $result->reason];
}
$this->table(['Result', 'Value'], $rows);
$message = 'Additional postprocessing ended with outcome '.$result->outcome->value.' for '.$identifier
.' after '.number_format($result->elapsedSeconds, 3).' seconds.';
if ($result->isSuccessful()) {
$this->info($message);
return;
}
$this->error($message);
}
private function displayProfile(ReleaseProcessingResult $result): void
{
$stageRows = [];
foreach ($result->stageDurations as $stage => $duration) {
$stageRows[] = [$stage, number_format($duration, 3)];
}
if ($stageRows !== []) {
$this->newLine();
$this->line('Stage profile');
$this->table(['Stage', 'Seconds'], $stageRows);
}
if ($result->downloadMetrics !== null) {
$this->newLine();
$this->line('Download profile');
$this->table(['Metric', 'Value'], [
['Logical requests', (string) $result->downloadMetrics->logicalRequests],
['Network requests', (string) $result->downloadMetrics->networkRequests],
['Cache hits', (string) $result->downloadMetrics->cacheHits],
['Bytes downloaded', (string) $result->downloadMetrics->bytesDownloaded],
['Bytes reused', (string) $result->downloadMetrics->bytesReused],
]);
}
if ($result->persistenceMetrics !== null) {
$this->newLine();
$this->line('Persistence profile');
$this->table(['Metric', 'Value'], [
['Database statements', (string) $result->persistenceMetrics->databaseStatements],
['Database milliseconds', number_format($result->persistenceMetrics->databaseMilliseconds, 3)],
['Search sync requests', (string) $result->persistenceMetrics->searchSyncRequests],
['Search sync executions', (string) $result->persistenceMetrics->searchSyncExecutions],
]);
}
}
}