Stabilize discovery workflow
This commit is contained in:
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace Domovoy\Services\Jobs;
|
||||
|
||||
use Domovoy\Models\ScanJob;
|
||||
use Domovoy\Repositories\NetworkRangeRepository;
|
||||
use Domovoy\Repositories\ScanJobRepository;
|
||||
use Domovoy\Services\Discovery\NetworkScanner;
|
||||
|
||||
@@ -12,13 +13,16 @@ class ScanJobRunner
|
||||
{
|
||||
private ScanJobRepository $scanJobRepository;
|
||||
private NetworkScanner $networkScanner;
|
||||
private NetworkRangeRepository $networkRangeRepository;
|
||||
|
||||
public function __construct(
|
||||
ScanJobRepository $scanJobRepository,
|
||||
NetworkScanner $networkScanner
|
||||
NetworkScanner $networkScanner,
|
||||
NetworkRangeRepository $networkRangeRepository
|
||||
) {
|
||||
$this->scanJobRepository = $scanJobRepository;
|
||||
$this->networkScanner = $networkScanner;
|
||||
$this->networkRangeRepository = $networkRangeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,16 +68,25 @@ class ScanJobRunner
|
||||
$this->scanJobRepository->save($job);
|
||||
|
||||
try {
|
||||
$finalStatus = null;
|
||||
switch ($job->type) {
|
||||
case 'network_discovery':
|
||||
$this->runNetworkDiscovery($job);
|
||||
$finalStatus = $this->runNetworkDiscovery($job);
|
||||
break;
|
||||
default:
|
||||
throw new \RuntimeException("Unknown scan job type: {$job->type}");
|
||||
}
|
||||
|
||||
$job->status = 'done';
|
||||
$job->finishedAt = new \DateTimeImmutable();
|
||||
if ($finalStatus === 'done') {
|
||||
$job->status = 'done';
|
||||
$job->finishedAt = new \DateTimeImmutable();
|
||||
} elseif ($finalStatus === 'paused') {
|
||||
$job->status = 'paused';
|
||||
$job->finishedAt = null;
|
||||
} elseif ($finalStatus === 'cancelled') {
|
||||
$job->status = 'cancelled';
|
||||
$job->finishedAt = new \DateTimeImmutable();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$job->status = 'failed';
|
||||
$job->errorMessage = $e->getMessage();
|
||||
@@ -83,13 +96,77 @@ class ScanJobRunner
|
||||
$this->scanJobRepository->save($job);
|
||||
}
|
||||
|
||||
private function runNetworkDiscovery(ScanJob $job): void
|
||||
private function runNetworkDiscovery(ScanJob $job): string
|
||||
{
|
||||
// For MVP, we scan all enabled network ranges if no specific range set
|
||||
// TODO: filter by specific range when network_range_id is set
|
||||
$settings = require dirname(__DIR__, 3) . '/../phinx.php';
|
||||
if ($job->networkRangeId === null) {
|
||||
throw new \RuntimeException('Network discovery job has no network_range_id');
|
||||
}
|
||||
|
||||
// Use the ranges from database via NetworkRangeRepository
|
||||
// For now, this is handled by the controller that creates the job with a specific range
|
||||
$range = $this->networkRangeRepository->findById($job->networkRangeId);
|
||||
if ($range === null) {
|
||||
throw new \RuntimeException("Network range #{$job->networkRangeId} not found");
|
||||
}
|
||||
if (!$range->enabled) {
|
||||
throw new \RuntimeException("Network range #{$job->networkRangeId} is disabled");
|
||||
}
|
||||
|
||||
$existingProgress = $this->decodeProgress($job);
|
||||
$startIndex = (int)($existingProgress['next_ip_index'] ?? 0);
|
||||
$previousHostsFound = (int)($existingProgress['hosts_found'] ?? 0);
|
||||
|
||||
$result = $this->networkScanner->scanResumable(
|
||||
$range,
|
||||
$job->id ?? 0,
|
||||
$startIndex,
|
||||
function () use ($job): bool {
|
||||
$fresh = $this->scanJobRepository->findById((int)$job->id);
|
||||
return $fresh !== null && in_array($fresh->status, ['paused', 'cancelled'], true);
|
||||
},
|
||||
function (array $state) use ($job, $range, $previousHostsFound): void {
|
||||
$fresh = $this->scanJobRepository->findById((int)$job->id);
|
||||
if ($fresh !== null && in_array($fresh->status, ['paused', 'cancelled'], true)) {
|
||||
$job->status = $fresh->status;
|
||||
}
|
||||
$job->resultJson = json_encode([
|
||||
'network_range_id' => $range->id,
|
||||
'cidr' => $range->cidr,
|
||||
'next_ip_index' => $state['next_ip_index'],
|
||||
'total_ips' => $state['total_ips'],
|
||||
'scanned_count' => $state['scanned_count'],
|
||||
'hosts_found' => $previousHostsFound + $state['hosts_found'],
|
||||
], JSON_THROW_ON_ERROR);
|
||||
$this->scanJobRepository->save($job);
|
||||
}
|
||||
);
|
||||
|
||||
$job->resultJson = json_encode([
|
||||
'network_range_id' => $range->id,
|
||||
'cidr' => $range->cidr,
|
||||
'next_ip_index' => $result['next_ip_index'],
|
||||
'total_ips' => $result['total_ips'],
|
||||
'scanned_count' => $result['scanned_count'],
|
||||
'hosts_found' => $previousHostsFound + $result['hosts_found'],
|
||||
], JSON_THROW_ON_ERROR);
|
||||
|
||||
if ($result['completed']) {
|
||||
return 'done';
|
||||
}
|
||||
|
||||
$fresh = $this->scanJobRepository->findById((int)$job->id);
|
||||
if ($fresh !== null && in_array($fresh->status, ['paused', 'cancelled'], true)) {
|
||||
return $fresh->status;
|
||||
}
|
||||
|
||||
return 'paused';
|
||||
}
|
||||
|
||||
private function decodeProgress(ScanJob $job): array
|
||||
{
|
||||
if ($job->resultJson === null || $job->resultJson === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$decoded = json_decode($job->resultJson, true);
|
||||
return is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user