diff --git a/public/simulate-nis2.php b/public/simulate-nis2.php index fc0bc3a..ccb969f 100644 --- a/public/simulate-nis2.php +++ b/public/simulate-nis2.php @@ -1,27 +1,102 @@ 'error', 'm' => 'simulate-nis2.php non trovato']) . "\n\n"; + echo 'data: ' . json_encode(['t' => 'done', 'stats' => ['pass' => 0, 'fail' => 1, 'skip' => 0, 'warn' => 0]]) . "\n\n"; + flush(); + exit; } -// sim01-sim05 e 'all': SIM_FILTER rimane null → esegue tutti gli scenari -// Includi il simulatore dalla root del progetto. -// __DIR__ nel file incluso punta alla directory di quel file (/var/www/nis2-agile/) -// quindi readEnvValue() trova correttamente .env nella root. -require __DIR__ . '/../simulate-nis2.php'; +// ── Ambiente subprocess ─────────────────────────────────────────────────────── +// NIS2_SSE=1 → il simulatore usa output SSE anche quando php_sapi_name()='cli' +// NIS2_SIM=SIM06 → esegue solo lo scenario B2B (opzionale) +$env = []; +foreach ($_ENV ?: [] as $k => $v) { + if (is_string($v)) $env[$k] = $v; +} +$env['NIS2_SSE'] = '1'; +if ($simParam === 'sim06') { + $env['NIS2_SIM'] = 'SIM06'; +} + +// ── Avvia subprocess (pattern lg231 runCommand) ─────────────────────────────── +$descriptors = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; +$cwd = dirname($scriptPath); +$cmd = PHP_BINARY . ' ' . escapeshellarg($scriptPath); +$proc = proc_open($cmd, $descriptors, $pipes, $cwd, $env); + +if (!is_resource($proc)) { + echo 'data: ' . json_encode(['t' => 'error', 'm' => 'Impossibile avviare il simulatore']) . "\n\n"; + echo 'data: ' . json_encode(['t' => 'done', 'stats' => ['pass' => 0, 'fail' => 1, 'skip' => 0, 'warn' => 0]]) . "\n\n"; + flush(); + exit; +} + +fclose($pipes[0]); +stream_set_blocking($pipes[1], false); +stream_set_blocking($pipes[2], false); + +// ── Streaming riga per riga ────────────────────────────────────────────────── +// Il simulatore emette direttamente eventi SSE (data: {...}\n\n). +// Il wrapper li passa al browser immediatamente senza buffering. +while (true) { + $chunk = fread($pipes[1], 8192); + if ($chunk !== false && $chunk !== '') { + echo $chunk; + flush(); + } + + // Stderr → errori PHP fatali visibili nel terminale SSE + $err = fread($pipes[2], 1024); + if ($err !== false && $err !== '') { + foreach (explode("\n", trim($err)) as $errLine) { + if (trim($errLine) !== '') { + echo 'data: ' . json_encode(['t' => 'error', 'm' => '[stderr] ' . trim($errLine)]) . "\n\n"; + } + } + flush(); + } + + $status = proc_get_status($proc); + if (!$status['running']) { + // Leggi eventuale output residuo dopo la fine del processo + $tail = stream_get_contents($pipes[1]); + if ($tail) { echo $tail; flush(); } + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($proc); + break; + } + + usleep(50000); // 50ms — bilanciamento latenza/CPU (come lg231) +} diff --git a/simulate-nis2.php b/simulate-nis2.php index 6b134ec..d6a7be4 100644 --- a/simulate-nis2.php +++ b/simulate-nis2.php @@ -32,15 +32,18 @@ declare(strict_types=1); define('SIM_VERSION', '1.0.0'); define('DEMO_EMAIL', getenv('NIS2_DEMO_EMAIL') ?: 'demo@nis2agile.it'); define('DEMO_PWD', 'NIS2Demo2026!'); -define('IS_CLI', php_sapi_name() === 'cli'); -define('IS_WEB', !IS_CLI); + +// NIS2_SSE=1 → forza output SSE anche da CLI (usato dal wrapper public/ con proc_open) +$_sseMode = (bool)getenv('NIS2_SSE'); +define('IS_CLI', php_sapi_name() === 'cli' && !$_sseMode); +define('IS_WEB', !IS_CLI); // URL base API — rileva automaticamente ambiente -if (IS_CLI) { - // Sul server Hetzner: Apache serve /var/www/nis2-agile su https://nis2.agile.software/ +if (IS_CLI || $_sseMode) { + // CLI diretto o subprocess: usa server prod (o override da env) define('API_BASE', getenv('NIS2_API_BASE') ?: 'https://nis2.agile.software/api'); } else { - // In web: usa URL relativo allo stesso host + // Web request diretto: ricostruisce URL dal $_SERVER $proto = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; $host = $_SERVER['HTTP_HOST'] ?? 'localhost'; define('API_BASE', "{$proto}://{$host}/api");