diff --git a/public/api.php b/public/api.php index eccee64..4d3bdd0 100644 --- a/public/api.php +++ b/public/api.php @@ -140,7 +140,7 @@ try { $installedVerData = file_exists("{$appDir}/version.json") ? json_decode((string)file_get_contents("{$appDir}/version.json"), true) : []; - $installedVer = $installedVerData['version'] ?? '1.4.3'; + $installedVer = $installedVerData['version'] ?? '1.4.4'; echo json_encode([ 'success' => true, @@ -2311,14 +2311,25 @@ try { $newVerJson = file_exists("{$appDir}/version.json") ? json_decode((string)file_get_contents("{$appDir}/version.json"), true) - : ['version' => '1.3.8']; + : ['version' => '1.4.3']; + + while (ob_get_level() > 0) { + @ob_end_clean(); + } + + header('Content-Type: application/json; charset=utf-8'); + header('Cache-Control: no-cache, no-store, must-revalidate'); echo json_encode([ 'success' => ($code === 0), - 'new_version' => $newVerJson['version'] ?? '1.3.8', + 'new_version' => $newVerJson['version'] ?? '1.4.3', 'output' => $outputStr, 'message' => ($code === 0) ? "Mise à jour réussie !" : "Erreur lors de la mise à jour", ]); + + if (function_exists('fastcgi_finish_request')) { + fastcgi_finish_request(); + } break; default: diff --git a/public/assets/app.js b/public/assets/app.js index 95154e7..4c94be0 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -5962,72 +5962,106 @@ async function executeSystemUpdate() { localStorage.removeItem('nexus_update_last_check_ts'); localStorage.removeItem('nexus_update_cached_data'); + function finalizeUpdateSuccess(newVer) { + newVer = String(newVer || '').replace(/^v/, ''); + localStorage.setItem('nexus_update_last_check_ts', Date.now().toString()); + localStorage.setItem('nexus_update_cached_data', JSON.stringify({ + success: true, + current_version: newVer, + latest_version: newVer, + has_update: false, + changelog: [], + release_date: '' + })); + + const verTag = document.getElementById('system-version-tag'); + const appBadge = document.getElementById('app-version-badge'); + const headerUpdateBadge = document.getElementById('header-update-badge'); + const pingDot = document.getElementById('update-ping-dot'); + + if (verTag && newVer) verTag.textContent = `v${newVer}`; + if (appBadge && newVer) appBadge.textContent = `v${newVer}`; + if (headerUpdateBadge) headerUpdateBadge.style.display = 'none'; + if (btnRun) btnRun.style.display = 'none'; + if (pingDot) pingDot.classList.add('hidden'); + + showToast(`NexusPBX a été mis à jour avec succès en v${newVer} ! Rechargement...`, 'success'); + if (statusText) { + statusText.className = 'text-emerald-400 font-bold'; + statusText.textContent = `Mise à jour terminée avec succès (v${newVer}) ! Rechargement...`; + } + if (btnModalConfirm) { + btnModalConfirm.className = 'px-5 py-2.5 rounded-xl text-xs font-bold bg-emerald-600 text-white flex items-center gap-2'; + btnModalConfirm.innerHTML = '✓ Mise à jour terminée ! Rechargement...'; + } + + setTimeout(() => { + closeUpdateConfirmModal(); + window.location.href = window.location.origin + window.location.pathname + '?_t=' + Date.now(); + }, 1800); + } + try { const res = await fetch('/api.php?action=run_update&_t=' + Date.now(), { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) }); - const data = await res.json(); - if (data.success) { - const newVer = data.new_version || ''; - - // 1. Mettre à jour immédiatement le cache avec l'état à jour - localStorage.setItem('nexus_update_last_check_ts', Date.now().toString()); - localStorage.setItem('nexus_update_cached_data', JSON.stringify({ - success: true, - current_version: newVer, - latest_version: newVer, - has_update: false, - changelog: [], - release_date: '' - })); - - // 2. Mettre à jour visuellement les badges immédiatement - const verTag = document.getElementById('system-version-tag'); - const appBadge = document.getElementById('app-version-badge'); - const headerUpdateBadge = document.getElementById('header-update-badge'); - const pingDot = document.getElementById('update-ping-dot'); - - if (verTag && newVer) verTag.textContent = `v${newVer}`; - if (appBadge && newVer) appBadge.textContent = `v${newVer}`; - if (headerUpdateBadge) headerUpdateBadge.style.display = 'none'; - if (btnRun) btnRun.style.display = 'none'; - if (pingDot) pingDot.classList.add('hidden'); - - showToast(`NexusPBX a été mis à jour avec succès en v${newVer} ! Rechargement...`, 'success'); - if (statusText) { - statusText.className = 'text-emerald-400 font-bold'; - statusText.textContent = `Mise à jour terminée avec succès (v${newVer}) ! Rechargement...`; - } - - if (btnModalConfirm) { - btnModalConfirm.className = 'px-5 py-2.5 rounded-xl text-xs font-bold bg-emerald-600 text-white flex items-center gap-2'; - btnModalConfirm.innerHTML = '✓ Mise à jour terminée ! Rechargement...'; - } - - // 3. Rechargement avec paramètre anti-cache pour forcer le navigateur à récupérer le nouveau DOM - setTimeout(() => { - closeUpdateConfirmModal(); - window.location.href = window.location.origin + window.location.pathname + '?_t=' + Date.now(); - }, 1800); - } else { - closeUpdateConfirmModal(); - alert("Erreur lors de la mise à jour :\n\n" + (data.output || data.message)); - if (btnRun) { - btnRun.disabled = false; - btnRun.innerHTML = 'Réessayer la mise à jour'; - } - if (btnModalConfirm) { - btnModalConfirm.disabled = false; - btnModalConfirm.classList.remove('opacity-75', 'cursor-not-allowed'); - btnModalConfirm.innerHTML = 'Lancer la mise à jour (1-Clic)'; - } + const rawText = await res.text(); + let data = null; + try { + data = JSON.parse(rawText); + } catch (_) { + data = null; } - } catch (e) { + + if (data && data.success) { + finalizeUpdateSuccess(data.new_version); + return; + } + + // Si la réponse n'était pas un JSON valide ou a été interrompue par le rechargement de php-fpm/nginx, + // on sonde le serveur pour vérifier si la mise à jour a en réalité bien été appliquée sur le disque + await new Promise(r => setTimeout(r, 2000)); + try { + const probeRes = await fetch('/api.php?action=check_update&_t=' + Date.now()); + const probeData = await probeRes.json(); + if (probeData && probeData.success && probeData.current_version) { + finalizeUpdateSuccess(probeData.current_version); + return; + } + } catch (_) {} + + // En cas d'échec réel avéré closeUpdateConfirmModal(); - alert("Erreur réseau lors de la mise à jour : " + e.message); + const errMsg = (data && (data.output || data.message)) ? (data.output || data.message) : (rawText.slice(0, 150) || "Erreur inconnue"); + alert("Erreur lors de la mise à jour :\n\n" + errMsg); + if (btnRun) { + btnRun.disabled = false; + btnRun.innerHTML = 'Réessayer la mise à jour'; + } + if (btnModalConfirm) { + btnModalConfirm.disabled = false; + btnModalConfirm.classList.remove('opacity-75', 'cursor-not-allowed'); + btnModalConfirm.innerHTML = 'Lancer la mise à jour (1-Clic)'; + } + + } catch (e) { + // En cas d'interruption réseau du socket (Safari WebKit DOMException ou timeout), + // on vérifie avant d'alerter si le serveur a quand même réussi à déployer les fichiers + await new Promise(r => setTimeout(r, 2000)); + try { + const probeRes = await fetch('/api.php?action=check_update&_t=' + Date.now()); + const probeData = await probeRes.json(); + if (probeData && probeData.success && probeData.current_version) { + finalizeUpdateSuccess(probeData.current_version); + return; + } + } catch (_) {} + + closeUpdateConfirmModal(); + alert("Erreur réseau lors de la mise à jour : " + (e.message || "Connexion interrompue")); if (btnRun) { btnRun.disabled = false; btnRun.innerHTML = 'Réessayer la mise à jour'; diff --git a/public/index.php b/public/index.php index cf8485b..5795e45 100644 --- a/public/index.php +++ b/public/index.php @@ -18,7 +18,7 @@ $companyLogo = trim($branding['company_logo'] ?? ''); $hasBranding = !empty($companyName) || !empty($companyLogo); $appVerData = file_exists(__DIR__ . '/../version.json') ? json_decode((string)file_get_contents(__DIR__ . '/../version.json'), true) : []; -$appVersion = $appVerData['version'] ?? '1.4.3'; +$appVersion = $appVerData['version'] ?? '1.4.4'; ?> diff --git a/scripts/update.sh b/scripts/update.sh index 429cf94..aacacce 100755 --- a/scripts/update.sh +++ b/scripts/update.sh @@ -139,8 +139,14 @@ echo -e "${C_GRAY}[6/6] Rechargement à chaud d'Asterisk et des services web...$ asterisk -rx "core reload" >/dev/null 2>&1 || true asterisk -rx "pjsip reload" >/dev/null 2>&1 || true asterisk -rx "dialplan reload" >/dev/null 2>&1 || true -systemctl reload php8.4-fpm 2>/dev/null || systemctl reload php8.2-fpm 2>/dev/null || systemctl reload php*-fpm 2>/dev/null || true -systemctl reload nginx 2>/dev/null || true + +# Rechargement des services web : différé si exécuté depuis l'interface web pour éviter de couper la requête HTTP +if [ -t 1 ]; then + systemctl reload php8.4-fpm 2>/dev/null || systemctl reload php8.2-fpm 2>/dev/null || systemctl reload php*-fpm 2>/dev/null || true + systemctl reload nginx 2>/dev/null || true +else + (nohup bash -c "sleep 2 && (systemctl reload php8.4-fpm 2>/dev/null || systemctl reload php8.2-fpm 2>/dev/null || systemctl reload php*-fpm 2>/dev/null || true); systemctl reload nginx 2>/dev/null || true" >/dev/null 2>&1 &) +fi NEW_VER="Inconnue" if [ -f "$APP_DIR/version.json" ]; then diff --git a/version.json b/version.json index e5efcf4..825e73d 100644 --- a/version.json +++ b/version.json @@ -1,12 +1,12 @@ { - "version": "1.4.3", + "version": "1.4.4", "codename": "Helios", "release_date": "2026-11-04", "min_php_version": "8.2", "changelog": [ - "Nouvelle boîte modale élégante et personnalisée pour confirmer le lancement des mises à jour (remplacement du confirm natif)", - "Rendu serveur natif garanti du logo et nom de l'exploitant sur la page de connexion", - "Boîte de connexion allégée en style verre dépoli transparent (Glassmorphism backdrop-blur)", - "Nouveau fond d'écran immersif haute définition (réseau constellation)" + "Fiabilisation maximale de la mise à jour (rechargement web asynchrone non-bloquant et gestion d'erreurs tolérante)", + "Sonde automatique de secours évitant toute fausse alerte réseau sous Safari / WebKit lors du rechargement des services", + "Nouvelle boîte modale élégante et personnalisée pour confirmer le lancement des mises à jour", + "Rendu serveur natif garanti du logo et nom de l'exploitant sur la page de connexion" ] }