[FEAT] Services API: full-snapshot endpoint + BigSim SSE wrapper
- ServicesController: nuovo endpoint GET /api/services/full-snapshot Aggrega gap-analysis, measures, incidents, training, deadlines, compliance-summary in una sola chiamata (reduce 6 round-trip → 1) Parametro ?days=N per finestra deadlines (default 30, max 365) - public/index.php: route GET:fullSnapshot aggiunta all'action map services - public/simulate-nis2-big.php: wrapper SSE per simulate-nis2-big.php Esegue il simulatore come sottoprocesso CLI con NIS2_SSE=1 e streama l'output al browser tramite Server-Sent Events Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
a122b49721
commit
56df54f8b1
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* NIS2 Agile — Wrapper SSE per simulate-nis2-big.php
|
||||
*
|
||||
* DocumentRoot è public/ → il file principale è fuori dalla web root.
|
||||
* Usa proc_open per eseguire il simulatore come sottoprocesso CLI con NIS2_SSE=1.
|
||||
*
|
||||
* URL: https://nis2.agile.software/simulate-nis2-big.php
|
||||
*/
|
||||
|
||||
set_time_limit(0);
|
||||
ignore_user_abort(true);
|
||||
ini_set('memory_limit', '64M');
|
||||
|
||||
header('Content-Type: text/event-stream');
|
||||
header('Cache-Control: no-cache');
|
||||
header('X-Accel-Buffering: no');
|
||||
header('Connection: keep-alive');
|
||||
ob_implicit_flush(true);
|
||||
while (ob_get_level()) ob_end_flush();
|
||||
|
||||
$scriptPath = realpath(__DIR__ . '/../simulate-nis2-big.php');
|
||||
|
||||
if (!$scriptPath || !is_file($scriptPath)) {
|
||||
echo 'data: ' . json_encode(['t' => 'error', 'm' => 'simulate-nis2-big.php non trovato']) . "\n\n";
|
||||
echo 'data: ' . json_encode(['t' => 'done', 'stats' => ['pass' => 0, 'fail' => 1, 'skip' => 0, 'warn' => 0]]) . "\n\n";
|
||||
flush();
|
||||
exit;
|
||||
}
|
||||
|
||||
$env = [];
|
||||
foreach ($_ENV ?: [] as $k => $v) {
|
||||
if (is_string($v)) $env[$k] = $v;
|
||||
}
|
||||
$env['NIS2_SSE'] = '1';
|
||||
|
||||
$descriptors = [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']];
|
||||
$cwd = dirname($scriptPath);
|
||||
$phpBin = PHP_BINARY;
|
||||
if (str_contains($phpBin, 'fpm') || !is_executable($phpBin)) {
|
||||
foreach (['/usr/bin/php' . PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION, '/usr/bin/php', 'php'] as $try) {
|
||||
if (is_executable($try) || shell_exec("which $try 2>/dev/null")) { $phpBin = $try; break; }
|
||||
}
|
||||
}
|
||||
$cmd = $phpBin . ' ' . 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 BIG']) . "\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);
|
||||
|
||||
while (true) {
|
||||
$chunk = fread($pipes[1], 8192);
|
||||
if ($chunk !== false && $chunk !== '') {
|
||||
echo $chunk;
|
||||
flush();
|
||||
}
|
||||
$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']) {
|
||||
$tail = stream_get_contents($pipes[1]);
|
||||
if ($tail) { echo $tail; flush(); }
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
proc_close($proc);
|
||||
break;
|
||||
}
|
||||
usleep(50000);
|
||||
}
|
||||
Reference in New Issue
Block a user