fix(ota): asynchronous web reload & fail-safe probe for Safari (v1.4.4)

This commit is contained in:
sorcier committed 2026-11-04 10:13:25 +01:00
1 parent bd8b519753
commit 07b53b8002
5 files changed
+79 -28

No files matched your search

+14 -3
View File
@@ -140,7 +140,7 @@ try {
$installedVerData = file_exists("{$appDir}/version.json") $installedVerData = file_exists("{$appDir}/version.json")
? json_decode((string)file_get_contents("{$appDir}/version.json"), true) ? 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([ echo json_encode([
'success' => true, 'success' => true,
@@ -2311,14 +2311,25 @@ try {
$newVerJson = file_exists("{$appDir}/version.json") $newVerJson = file_exists("{$appDir}/version.json")
? json_decode((string)file_get_contents("{$appDir}/version.json"), true) ? 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([ echo json_encode([
'success' => ($code === 0), 'success' => ($code === 0),
'new_version' => $newVerJson['version'] ?? '1.3.8', 'new_version' => $newVerJson['version'] ?? '1.4.3',
'output' => $outputStr, 'output' => $outputStr,
'message' => ($code === 0) ? "Mise à jour réussie !" : "Erreur lors de la mise à jour", 'message' => ($code === 0) ? "Mise à jour réussie !" : "Erreur lors de la mise à jour",
]); ]);
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
}
break; break;
default: default:
+53 -19
View File
@@ -5962,18 +5962,8 @@ async function executeSystemUpdate() {
localStorage.removeItem('nexus_update_last_check_ts'); localStorage.removeItem('nexus_update_last_check_ts');
localStorage.removeItem('nexus_update_cached_data'); localStorage.removeItem('nexus_update_cached_data');
try { function finalizeUpdateSuccess(newVer) {
const res = await fetch('/api.php?action=run_update&_t=' + Date.now(), { newVer = String(newVer || '').replace(/^v/, '');
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_last_check_ts', Date.now().toString());
localStorage.setItem('nexus_update_cached_data', JSON.stringify({ localStorage.setItem('nexus_update_cached_data', JSON.stringify({
success: true, success: true,
@@ -5984,7 +5974,6 @@ async function executeSystemUpdate() {
release_date: '' release_date: ''
})); }));
// 2. Mettre à jour visuellement les badges immédiatement
const verTag = document.getElementById('system-version-tag'); const verTag = document.getElementById('system-version-tag');
const appBadge = document.getElementById('app-version-badge'); const appBadge = document.getElementById('app-version-badge');
const headerUpdateBadge = document.getElementById('header-update-badge'); const headerUpdateBadge = document.getElementById('header-update-badge');
@@ -6001,20 +5990,53 @@ async function executeSystemUpdate() {
statusText.className = 'text-emerald-400 font-bold'; statusText.className = 'text-emerald-400 font-bold';
statusText.textContent = `Mise à jour terminée avec succès (v${newVer}) ! Rechargement...`; statusText.textContent = `Mise à jour terminée avec succès (v${newVer}) ! Rechargement...`;
} }
if (btnModalConfirm) { 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.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...'; 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(() => { setTimeout(() => {
closeUpdateConfirmModal(); closeUpdateConfirmModal();
window.location.href = window.location.origin + window.location.pathname + '?_t=' + Date.now(); window.location.href = window.location.origin + window.location.pathname + '?_t=' + Date.now();
}, 1800); }, 1800);
} else { }
try {
const res = await fetch('/api.php?action=run_update&_t=' + Date.now(), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({})
});
const rawText = await res.text();
let data = null;
try {
data = JSON.parse(rawText);
} catch (_) {
data = null;
}
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(); closeUpdateConfirmModal();
alert("Erreur lors de la mise à jour :\n\n" + (data.output || data.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) { if (btnRun) {
btnRun.disabled = false; btnRun.disabled = false;
btnRun.innerHTML = 'Réessayer la mise à jour'; btnRun.innerHTML = 'Réessayer la mise à jour';
@@ -6024,10 +6046,22 @@ async function executeSystemUpdate() {
btnModalConfirm.classList.remove('opacity-75', 'cursor-not-allowed'); btnModalConfirm.classList.remove('opacity-75', 'cursor-not-allowed');
btnModalConfirm.innerHTML = '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/></svg><span>Lancer la mise à jour (1-Clic)</span>'; btnModalConfirm.innerHTML = '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"/></svg><span>Lancer la mise à jour (1-Clic)</span>';
} }
}
} catch (e) { } 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(); closeUpdateConfirmModal();
alert("Erreur réseau lors de la mise à jour : " + e.message); alert("Erreur réseau lors de la mise à jour : " + (e.message || "Connexion interrompue"));
if (btnRun) { if (btnRun) {
btnRun.disabled = false; btnRun.disabled = false;
btnRun.innerHTML = 'Réessayer la mise à jour'; btnRun.innerHTML = 'Réessayer la mise à jour';
+1 -1
View File
@@ -18,7 +18,7 @@ $companyLogo = trim($branding['company_logo'] ?? '');
$hasBranding = !empty($companyName) || !empty($companyLogo); $hasBranding = !empty($companyName) || !empty($companyLogo);
$appVerData = file_exists(__DIR__ . '/../version.json') ? json_decode((string)file_get_contents(__DIR__ . '/../version.json'), true) : []; $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';
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="fr" class="h-full"> <html lang="fr" class="h-full">
+6
View File
@@ -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 "core reload" >/dev/null 2>&1 || true
asterisk -rx "pjsip reload" >/dev/null 2>&1 || true asterisk -rx "pjsip reload" >/dev/null 2>&1 || true
asterisk -rx "dialplan reload" >/dev/null 2>&1 || true asterisk -rx "dialplan reload" >/dev/null 2>&1 || 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 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 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" NEW_VER="Inconnue"
if [ -f "$APP_DIR/version.json" ]; then if [ -f "$APP_DIR/version.json" ]; then
+5 -5
View File
@@ -1,12 +1,12 @@
{ {
"version": "1.4.3", "version": "1.4.4",
"codename": "Helios", "codename": "Helios",
"release_date": "2026-11-04", "release_date": "2026-11-04",
"min_php_version": "8.2", "min_php_version": "8.2",
"changelog": [ "changelog": [
"Nouvelle boîte modale élégante et personnalisée pour confirmer le lancement des mises à jour (remplacement du confirm natif)", "Fiabilisation maximale de la mise à jour (rechargement web asynchrone non-bloquant et gestion d'erreurs tolérante)",
"Rendu serveur natif garanti du logo et nom de l'exploitant sur la page de connexion", "Sonde automatique de secours évitant toute fausse alerte réseau sous Safari / WebKit lors du rechargement des services",
"Boîte de connexion allégée en style verre dépoli transparent (Glassmorphism backdrop-blur)", "Nouvelle boîte modale élégante et personnalisée pour confirmer le lancement des mises à jour",
"Nouveau fond d'écran immersif haute définition (réseau constellation)" "Rendu serveur natif garanti du logo et nom de l'exploitant sur la page de connexion"
] ]
} }