warm cache run
This commit is contained in:
@@ -103,6 +103,14 @@
|
||||
<div class="menu-title">Stats</div>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="warm_cache_run.php">
|
||||
<div class="parent-icon">
|
||||
<i class="bx bx-bar-chart-alt-2"></i>
|
||||
</div>
|
||||
<div class="menu-title">Warm Cache</div>
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
<li class="menu-label">Others</li>
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
|
||||
$startTime = microtime(true);
|
||||
$isCli = (php_sapi_name() === 'cli');
|
||||
$isStream = (!$isCli && isset($_GET['stream']));
|
||||
|
||||
// Analisi incluse? Default SÌ (il cron non passa il parametro → fa tutto).
|
||||
// Solo una richiesta HTTP con analisi=0 le salta.
|
||||
$includeAnalisi = !(!$isCli && isset($_GET['analisi']) && $_GET['analisi'] === '0');
|
||||
|
||||
if (!$isCli) {
|
||||
// When called via HTTP, require auth
|
||||
@@ -15,7 +20,17 @@ if (!$isCli) {
|
||||
echo json_encode(['error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if ($isStream) {
|
||||
// Streaming mode: send progress line-by-line (Server-Sent Events)
|
||||
set_time_limit(0);
|
||||
header('Content-Type: text/event-stream');
|
||||
header('Cache-Control: no-cache');
|
||||
header('X-Accel-Buffering: no'); // disable nginx buffering
|
||||
while (ob_get_level() > 0) ob_end_flush();
|
||||
} else {
|
||||
header('Content-Type: application/json');
|
||||
}
|
||||
}
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
@@ -23,15 +38,38 @@ require_once __DIR__ . '/class/VisualLimsApiClient.class.php';
|
||||
require_once __DIR__ . '/class/db-functions.php';
|
||||
|
||||
$cacheDir = __DIR__ . '/cache';
|
||||
if (!is_dir($cacheDir)) mkdir($cacheDir, 0777, true);
|
||||
if (!is_dir($cacheDir)) mkdir($cacheDir, 0755, true);
|
||||
|
||||
$log = [];
|
||||
|
||||
// Prevent two runs at the same time (e.g. cron + manual click)
|
||||
$lockHandle = fopen($cacheDir . '/.warm.lock', 'w');
|
||||
if ($lockHandle === false || !flock($lockHandle, LOCK_EX | LOCK_NB)) {
|
||||
$busyMsg = 'Un aggiornamento è già in corso in questo momento. Riprova tra poco.';
|
||||
if ($isCli) {
|
||||
echo $busyMsg . PHP_EOL;
|
||||
} elseif ($isStream) {
|
||||
header('Content-Type: text/event-stream');
|
||||
echo "event: busy\ndata: " . $busyMsg . "\n\n";
|
||||
@flush();
|
||||
} else {
|
||||
echo json_encode(['success' => false, 'busy' => true, 'message' => $busyMsg]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
function warmLog(string $msg, bool $isCli)
|
||||
{
|
||||
global $log;
|
||||
global $log, $isStream;
|
||||
$line = date('H:i:s') . " $msg";
|
||||
$log[] = $line;
|
||||
if ($isCli) echo $line . PHP_EOL;
|
||||
if ($isCli) {
|
||||
echo $line . PHP_EOL;
|
||||
} elseif (!empty($isStream)) {
|
||||
echo "data: " . str_replace("\n", ' ', $line) . "\n\n";
|
||||
@ob_flush();
|
||||
@flush();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -115,30 +153,38 @@ try {
|
||||
|
||||
// 6. Analisi — only for matrici actually used by parts (warming all ~2500 matrici
|
||||
// would mean one API call each; the used set is a few dozen).
|
||||
$stmt = $pdo->query("SELECT DISTINCT idmatrice FROM identification_parts WHERE idmatrice IS NOT NULL AND idmatrice > 0 ORDER BY idmatrice ASC");
|
||||
$matriceIds = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
warmLog("[analisi] Fetching for " . count($matriceIds) . " matrici in use...", $isCli);
|
||||
if (!$includeAnalisi) {
|
||||
warmLog('[analisi] Saltate su richiesta.', $isCli);
|
||||
} else {
|
||||
$stmt = $pdo->query("SELECT DISTINCT idmatrice FROM identification_parts WHERE idmatrice IS NOT NULL AND idmatrice > 0 ORDER BY idmatrice ASC");
|
||||
$matriceIds = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
warmLog("[analisi] Fetching for " . count($matriceIds) . " matrici in use...", $isCli);
|
||||
|
||||
foreach ($matriceIds as $mid) {
|
||||
$mid = (int)$mid;
|
||||
// Same query as get_analisi_matrice_filter.php with web_only=1 (what the analysis modal requests)
|
||||
$filter = rawurlencode("Matrice/IdMatrice eq $mid and SelezionabileSuWeb eq true");
|
||||
try {
|
||||
$data = $api->get("Analisi?\$filter={$filter}");
|
||||
$values = $data['value'] ?? [];
|
||||
file_put_contents($cacheDir . '/analisi_matrice_' . $mid . '.json', json_encode(['value' => $values]));
|
||||
warmLog("[analisi] Matrice $mid: " . count($values) . " analisi", $isCli);
|
||||
} catch (Exception $e) {
|
||||
warmLog("[analisi] Matrice $mid: ERROR " . $e->getMessage(), $isCli);
|
||||
foreach ($matriceIds as $mid) {
|
||||
$mid = (int)$mid;
|
||||
// Same query as get_analisi_matrice_filter.php with web_only=1 (what the analysis modal requests)
|
||||
$filter = rawurlencode("Matrice/IdMatrice eq $mid and SelezionabileSuWeb eq true");
|
||||
try {
|
||||
$data = $api->get("Analisi?\$filter={$filter}");
|
||||
$values = $data['value'] ?? [];
|
||||
file_put_contents($cacheDir . '/analisi_matrice_' . $mid . '.json', json_encode(['value' => $values]));
|
||||
warmLog("[analisi] Matrice $mid: " . count($values) . " analisi", $isCli);
|
||||
} catch (Exception $e) {
|
||||
warmLog("[analisi] Matrice $mid: ERROR " . $e->getMessage(), $isCli);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // fine if includeAnalisi
|
||||
|
||||
$elapsed = round(microtime(true) - $startTime, 1);
|
||||
warmLog("Done in {$elapsed}s", $isCli);
|
||||
warmLog("Aggiornamento completato in {$elapsed}s", $isCli);
|
||||
} catch (Exception $e) {
|
||||
warmLog("FATAL: " . $e->getMessage(), $isCli);
|
||||
$elapsed = round(microtime(true) - $startTime, 1);
|
||||
warmLog("ERRORE: " . $e->getMessage(), $isCli);
|
||||
}
|
||||
|
||||
if (!$isCli) {
|
||||
if ($isStream) {
|
||||
echo "event: done\ndata: " . json_encode(['elapsed' => $elapsed ?? 0]) . "\n\n";
|
||||
@flush();
|
||||
} elseif (!$isCli) {
|
||||
echo json_encode(['success' => true, 'log' => $log]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,519 @@
|
||||
<?php
|
||||
include('include/headscript.php');
|
||||
|
||||
/*
|
||||
* NOTE PERMESSI:
|
||||
* Il login è già gestito da headscript.php (Auth::check + redirect).
|
||||
* Se vuoi limitare questa pagina a determinati ruoli, aggiungi qui il tuo
|
||||
* controllo, esattamente come nelle altre pagine. Esempio:
|
||||
*
|
||||
* if (!$user->hasRole('Admin') && !$user->hasRole('SuperUser')) {
|
||||
* header('Location: import_dashboard.php');
|
||||
* exit;
|
||||
* }
|
||||
*/
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="it">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
||||
<?php include('cssinclude.php'); ?>
|
||||
|
||||
<title>Aggiornamento dati - <?= htmlspecialchars($titlewebsite ?? 'SmartTRF', ENT_QUOTES, 'UTF-8'); ?></title>
|
||||
|
||||
<style>
|
||||
.warm-hero {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.warm-hero .warm-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 30px;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #0f172a, #1d4ed8);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.warm-progress-wrap {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.warm-progress-wrap.is-visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.progress.warm-progress {
|
||||
height: 22px;
|
||||
border-radius: 12px;
|
||||
background: #eef2f7;
|
||||
}
|
||||
|
||||
.progress.warm-progress .progress-bar {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.warm-steps {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 18px 0 0 0;
|
||||
}
|
||||
|
||||
.warm-steps li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 6px;
|
||||
background: #f8fafc;
|
||||
border: 1px solid #eef2f7;
|
||||
transition: background .2s, border-color .2s;
|
||||
}
|
||||
|
||||
.warm-steps li .step-icon {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
flex-shrink: 0;
|
||||
background: #e5e7eb;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.warm-steps li.is-active {
|
||||
background: #eff6ff;
|
||||
border-color: #bfdbfe;
|
||||
}
|
||||
|
||||
.warm-steps li.is-active .step-icon {
|
||||
background: #2563eb;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.warm-steps li.is-done {
|
||||
background: #f0fdf4;
|
||||
border-color: #bbf7d0;
|
||||
}
|
||||
|
||||
.warm-steps li.is-done .step-icon {
|
||||
background: #16a34a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.warm-steps li .step-label {
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
.warm-steps li .step-detail {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
margin-left: auto;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.warm-log {
|
||||
display: none;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.warm-log.is-visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.warm-log pre {
|
||||
max-height: 320px;
|
||||
overflow: auto;
|
||||
background: #0f172a;
|
||||
color: #cbd5e1;
|
||||
padding: 16px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.warm-result {
|
||||
display: none;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.warm-result.is-visible {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<?php include('include/navbar.php'); ?>
|
||||
<?php include('include/topbar.php'); ?>
|
||||
|
||||
<div class="page-wrapper">
|
||||
<div class="page-content">
|
||||
|
||||
<div class="card radius-10">
|
||||
<div class="card-body p-4">
|
||||
|
||||
<div class="warm-hero">
|
||||
<div class="warm-icon"><i class="bx bx-refresh"></i></div>
|
||||
<div>
|
||||
<h5 class="mb-1">Aggiornamento dati dal gestionale</h5>
|
||||
<p class="mb-0 text-muted">
|
||||
Ricarica clienti, matrici, analisi e le altre liste dal software di laboratorio.
|
||||
Da usare quando sono state fatte modifiche sul gestionale e vuoi vederle subito
|
||||
senza aspettare l'aggiornamento automatico.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
<div class="form-check form-switch mb-3" id="analisiSwitchWrap">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="includeAnalisi" checked>
|
||||
<label class="form-check-label" for="includeAnalisi">
|
||||
Aggiorna anche le <strong>analisi</strong>
|
||||
<span class="text-muted small">(più lento — togli la spunta se hai modificato solo clienti o altre liste)</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-primary btn-lg px-4" id="btnStart">
|
||||
<i class="bx bx-play-circle me-1"></i> Avvia aggiornamento
|
||||
</button>
|
||||
<div class="small text-muted mt-2" id="idleHint">
|
||||
L'operazione può richiedere da qualche secondo a un paio di minuti.
|
||||
</div>
|
||||
|
||||
<!-- Progress -->
|
||||
<div class="warm-progress-wrap mt-4" id="progressWrap">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<span class="fw-semibold" id="progressTitle">Aggiornamento in corso…</span>
|
||||
<span class="text-muted small" id="progressElapsed">0s</span>
|
||||
</div>
|
||||
|
||||
<div class="progress warm-progress">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated bg-primary"
|
||||
id="progressBar" role="progressbar" style="width: 0%;">0%</div>
|
||||
</div>
|
||||
|
||||
<ul class="warm-steps" id="stepsList">
|
||||
<!-- steps injected by JS -->
|
||||
</ul>
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="javascript:;" class="small text-decoration-none" id="toggleLog">
|
||||
<i class="bx bx-code-alt"></i> Mostra dettaglio tecnico
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="warm-log" id="logBox">
|
||||
<pre id="logPre"></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Result -->
|
||||
<div class="warm-result" id="resultBox">
|
||||
<div class="alert d-flex align-items-center" id="resultAlert" role="alert">
|
||||
<i class="bx me-2 fs-4" id="resultIcon"></i>
|
||||
<div id="resultText"></div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-primary" id="btnAgain">
|
||||
<i class="bx bx-refresh me-1"></i> Esegui di nuovo
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overlay toggle-icon"></div>
|
||||
<a href="javaScript:;" class="back-to-top"><i class='bx bxs-up-arrow-alt'></i></a>
|
||||
<?php include('include/footer.php'); ?>
|
||||
</div>
|
||||
|
||||
<?php include('jsinclude.php'); ?>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
/*
|
||||
* Se sposti warm_cache.php in un'altra cartella, cambia SOLO questa riga.
|
||||
*/
|
||||
const WARM_ENDPOINT = 'warm_cache.php';
|
||||
|
||||
const btnStart = document.getElementById('btnStart');
|
||||
const btnAgain = document.getElementById('btnAgain');
|
||||
const idleHint = document.getElementById('idleHint');
|
||||
const includeAnalisi = document.getElementById('includeAnalisi');
|
||||
const progressWrap = document.getElementById('progressWrap');
|
||||
const progressBar = document.getElementById('progressBar');
|
||||
const progressTitle = document.getElementById('progressTitle');
|
||||
const progressElapsed = document.getElementById('progressElapsed');
|
||||
const stepsList = document.getElementById('stepsList');
|
||||
const toggleLog = document.getElementById('toggleLog');
|
||||
const logBox = document.getElementById('logBox');
|
||||
const logPre = document.getElementById('logPre');
|
||||
const resultBox = document.getElementById('resultBox');
|
||||
const resultAlert = document.getElementById('resultAlert');
|
||||
const resultIcon = document.getElementById('resultIcon');
|
||||
const resultText = document.getElementById('resultText');
|
||||
|
||||
/*
|
||||
* I "passi" mostrati al cliente in modo leggibile.
|
||||
* key = frammento che compare nel log tecnico (dentro le parentesi quadre)
|
||||
* label = nome umano
|
||||
* Il progresso avanza man mano che questi tag compaiono nel log.
|
||||
*/
|
||||
const STEPS = [{
|
||||
key: 'clients',
|
||||
label: 'Clienti'
|
||||
},
|
||||
{
|
||||
key: 'MoltiplicatorePrezzo',
|
||||
label: 'Listini prezzi'
|
||||
},
|
||||
{
|
||||
key: 'AnagraficaCertest',
|
||||
label: 'Anagrafiche Certest'
|
||||
},
|
||||
{
|
||||
key: 'ClienteResponsabile',
|
||||
label: 'Responsabili cliente'
|
||||
},
|
||||
{
|
||||
key: 'CustomField',
|
||||
label: 'Campi personalizzati'
|
||||
},
|
||||
{
|
||||
key: 'matrici',
|
||||
label: 'Matrici'
|
||||
},
|
||||
{
|
||||
key: 'analisi',
|
||||
label: 'Analisi'
|
||||
}
|
||||
];
|
||||
|
||||
let stepEls = {};
|
||||
let currentStepIndex = -1;
|
||||
let timerId = null;
|
||||
let startedAt = 0;
|
||||
let activeSteps = []; // i passi effettivamente in gioco per questa esecuzione
|
||||
|
||||
function buildSteps() {
|
||||
stepsList.innerHTML = '';
|
||||
stepEls = {};
|
||||
// Se le analisi sono disattivate, escludo quel passo dalla lista.
|
||||
const withAnalisi = includeAnalisi.checked;
|
||||
activeSteps = STEPS.filter(function(s) {
|
||||
return withAnalisi || s.key !== 'analisi';
|
||||
});
|
||||
activeSteps.forEach(function(step, i) {
|
||||
const li = document.createElement('li');
|
||||
li.dataset.index = i;
|
||||
li.innerHTML =
|
||||
'<span class="step-icon"><i class="bx bx-time"></i></span>' +
|
||||
'<span class="step-label">' + step.label + '</span>' +
|
||||
'<span class="step-detail"></span>';
|
||||
stepsList.appendChild(li);
|
||||
stepEls[i] = li;
|
||||
});
|
||||
}
|
||||
|
||||
function markStep(index, state, detail) {
|
||||
const li = stepEls[index];
|
||||
if (!li) return;
|
||||
li.classList.remove('is-active', 'is-done');
|
||||
const icon = li.querySelector('.step-icon i');
|
||||
if (state === 'active') {
|
||||
li.classList.add('is-active');
|
||||
icon.className = 'bx bx-loader-alt bx-spin';
|
||||
} else if (state === 'done') {
|
||||
li.classList.add('is-done');
|
||||
icon.className = 'bx bx-check';
|
||||
}
|
||||
if (detail !== undefined) {
|
||||
li.querySelector('.step-detail').textContent = detail;
|
||||
}
|
||||
}
|
||||
|
||||
function advanceTo(index, detail) {
|
||||
if (index <= currentStepIndex) {
|
||||
// stesso passo, aggiorna solo il dettaglio (es. conteggio)
|
||||
if (detail !== undefined) markStep(index, 'active', detail);
|
||||
return;
|
||||
}
|
||||
// chiudi i passi precedenti
|
||||
for (let i = 0; i <= currentStepIndex; i++) markStep(i, 'done');
|
||||
currentStepIndex = index;
|
||||
markStep(index, 'active', detail);
|
||||
const pct = Math.round(((index) / activeSteps.length) * 100);
|
||||
setProgress(Math.max(pct, 3));
|
||||
}
|
||||
|
||||
function setProgress(pct) {
|
||||
pct = Math.max(0, Math.min(100, pct));
|
||||
progressBar.style.width = pct + '%';
|
||||
progressBar.textContent = pct + '%';
|
||||
}
|
||||
|
||||
function matchStep(line) {
|
||||
// cerca [clients], [matrici], [analisi] ecc. nella riga di log
|
||||
for (let i = 0; i < activeSteps.length; i++) {
|
||||
if (line.indexOf('[' + activeSteps[i].key) !== -1 ||
|
||||
line.indexOf(activeSteps[i].key + ']') !== -1) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function extractDetail(line) {
|
||||
// prova a estrarre un conteggio tipo "Cached 128 clients" o "34 analisi"
|
||||
const m = line.match(/(\d+)\s+(clients|items|values|responsabili|analisi)/i);
|
||||
if (m) return m[1] + ' elementi';
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function startTimer() {
|
||||
startedAt = Date.now();
|
||||
timerId = setInterval(function() {
|
||||
const s = Math.round((Date.now() - startedAt) / 1000);
|
||||
progressElapsed.textContent = s + 's';
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function stopTimer() {
|
||||
if (timerId) clearInterval(timerId);
|
||||
timerId = null;
|
||||
}
|
||||
|
||||
function resetUI() {
|
||||
buildSteps();
|
||||
currentStepIndex = -1;
|
||||
setProgress(0);
|
||||
logPre.textContent = '';
|
||||
progressTitle.textContent = 'Aggiornamento in corso…';
|
||||
progressElapsed.textContent = '0s';
|
||||
resultBox.classList.remove('is-visible');
|
||||
progressWrap.classList.add('is-visible');
|
||||
}
|
||||
|
||||
function showResult(type, message) {
|
||||
stopTimer();
|
||||
progressBar.classList.remove('progress-bar-animated', 'progress-bar-striped');
|
||||
|
||||
resultAlert.className = 'alert d-flex align-items-center';
|
||||
if (type === 'success') {
|
||||
resultAlert.classList.add('alert-success');
|
||||
resultIcon.className = 'bx bx-check-circle me-2 fs-4';
|
||||
progressBar.classList.add('bg-success');
|
||||
} else if (type === 'warning') {
|
||||
resultAlert.classList.add('alert-warning');
|
||||
resultIcon.className = 'bx bx-error me-2 fs-4';
|
||||
progressBar.classList.add('bg-warning');
|
||||
} else {
|
||||
resultAlert.classList.add('alert-danger');
|
||||
resultIcon.className = 'bx bx-x-circle me-2 fs-4';
|
||||
progressBar.classList.add('bg-danger');
|
||||
}
|
||||
resultText.textContent = message;
|
||||
resultBox.classList.add('is-visible');
|
||||
btnStart.disabled = false;
|
||||
includeAnalisi.disabled = false;
|
||||
}
|
||||
|
||||
function run() {
|
||||
btnStart.disabled = true;
|
||||
includeAnalisi.disabled = true;
|
||||
idleHint.style.display = 'none';
|
||||
resetUI();
|
||||
startTimer();
|
||||
|
||||
const analisiParam = includeAnalisi.checked ? '1' : '0';
|
||||
const es = new EventSource(WARM_ENDPOINT + '?stream=1&analisi=' + analisiParam);
|
||||
|
||||
es.onmessage = function(e) {
|
||||
const line = e.data;
|
||||
logPre.textContent += line + '\n';
|
||||
logPre.scrollTop = logPre.scrollHeight;
|
||||
|
||||
const idx = matchStep(line);
|
||||
if (idx !== -1) {
|
||||
advanceTo(idx, extractDetail(line));
|
||||
}
|
||||
};
|
||||
|
||||
es.addEventListener('busy', function(e) {
|
||||
es.close();
|
||||
showResult('warning', e.data ||
|
||||
'Un aggiornamento è già in corso. Attendi qualche istante e riprova.');
|
||||
});
|
||||
|
||||
es.addEventListener('done', function(e) {
|
||||
es.close();
|
||||
// completa tutti i passi
|
||||
for (let i = 0; i < activeSteps.length; i++) markStep(i, 'done');
|
||||
setProgress(100);
|
||||
let elapsed = '';
|
||||
try {
|
||||
elapsed = JSON.parse(e.data).elapsed;
|
||||
} catch (err) {}
|
||||
|
||||
// se nel log è comparsa la parola ERRORE, segnala come warning
|
||||
if (logPre.textContent.indexOf('ERRORE') !== -1) {
|
||||
showResult('warning',
|
||||
'Aggiornamento terminato, ma alcuni dati potrebbero non essere stati caricati. ' +
|
||||
'Controlla il dettaglio tecnico.');
|
||||
} else {
|
||||
progressTitle.textContent = 'Completato';
|
||||
showResult('success',
|
||||
'Dati aggiornati correttamente' +
|
||||
(elapsed ? ' in ' + elapsed + ' secondi.' : '.') +
|
||||
' Le nuove informazioni sono ora disponibili.');
|
||||
}
|
||||
});
|
||||
|
||||
es.onerror = function() {
|
||||
// EventSource tenta il reconnect da solo: lo blocchiamo.
|
||||
es.close();
|
||||
stopTimer();
|
||||
// Se avevamo già finito, il done è già scattato: non sovrascrivere.
|
||||
if (!resultBox.classList.contains('is-visible')) {
|
||||
showResult('error',
|
||||
'Connessione interrotta durante l\'aggiornamento. ' +
|
||||
'Verifica la rete e riprova.');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
btnStart.addEventListener('click', run);
|
||||
btnAgain.addEventListener('click', run);
|
||||
|
||||
toggleLog.addEventListener('click', function() {
|
||||
logBox.classList.toggle('is-visible');
|
||||
toggleLog.innerHTML = logBox.classList.contains('is-visible') ?
|
||||
'<i class="bx bx-hide"></i> Nascondi dettaglio tecnico' :
|
||||
'<i class="bx bx-code-alt"></i> Mostra dettaglio tecnico';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user