Enhanced state handling
This commit is contained in:
54
installer
54
installer
@ -405,6 +405,10 @@ $stratum = 'stratum+tcp://' . $host . ':3333';
|
|||||||
const syncTracker = { samples: [] };
|
const syncTracker = { samples: [] };
|
||||||
const WINDOW_SECONDS = 900; // 15 minutes
|
const WINDOW_SECONDS = 900; // 15 minutes
|
||||||
|
|
||||||
|
// 30-second heartbeat
|
||||||
|
let lastStatusOk = Date.now(); // timestamp of last good fetch
|
||||||
|
const STALE_MS = 30000; // 30 seconds
|
||||||
|
|
||||||
function formatEta(seconds) {
|
function formatEta(seconds) {
|
||||||
if (seconds == null || !isFinite(seconds)) return 'estimating…';
|
if (seconds == null || !isFinite(seconds)) return 'estimating…';
|
||||||
if (seconds < 60) return seconds.toFixed(0) + 's';
|
if (seconds < 60) return seconds.toFixed(0) + 's';
|
||||||
@ -457,13 +461,15 @@ async function loadStatus() {
|
|||||||
const res = await fetch('/status.php', {cache: 'no-store'});
|
const res = await fetch('/status.php', {cache: 'no-store'});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const box = document.getElementById('node-status');
|
const box = document.getElementById('node-status');
|
||||||
|
const rawIbd = data.initialblockdownload;
|
||||||
|
const hasRealIbd = (typeof rawIbd === 'boolean');
|
||||||
|
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
box.innerHTML = '<h2>Status</h2><p class="status-err">' + data.error + '</p>' + renderServices(data.services);
|
box.innerHTML = '<h2>Status</h2><p class="status-err">' + data.error + '</p>' + renderServices(data.services);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ibd = !!data.initialblockdownload;
|
const ibd = hasRealIbd ? rawIbd : true; // default to "syncing/problem" if unknown
|
||||||
const blocks = data.blocks ?? '–';
|
const blocks = data.blocks ?? '–';
|
||||||
const pruned = data.pruned ? '(pruned)' : '';
|
const pruned = data.pruned ? '(pruned)' : '';
|
||||||
let progress = 0;
|
let progress = 0;
|
||||||
@ -474,15 +480,32 @@ async function loadStatus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update favicon dynamically
|
// Update favicon dynamically
|
||||||
setFaviconAndTitle(ibd, progress);
|
lastStatusOk = Date.now();
|
||||||
|
const bitcoindActive = data.services && data.services.bitcoind === 'active';
|
||||||
|
if (!bitcoindActive) {
|
||||||
|
setFaviconAndTitle(false, 0, true); // show Disconnected
|
||||||
|
} else {
|
||||||
|
setFaviconAndTitle(ibd, progress, false);
|
||||||
|
}
|
||||||
|
|
||||||
// update window + estimate
|
// update window + estimate
|
||||||
updateSamples(progress);
|
updateSamples(progress);
|
||||||
const etaSeconds = ibd ? estimateEta(progress) : null;
|
const etaSeconds = ibd ? estimateEta(progress) : null;
|
||||||
|
|
||||||
let html = '<h2>Status</h2>';
|
let html = '<h2>Status</h2>';
|
||||||
|
if (!hasRealIbd) {
|
||||||
if (ibd) {
|
if (data.services && data.services.bitcoind === 'active') {
|
||||||
|
html += '<p class="status-err">❌ Cannot read Bitcoin Core status. If this persists, try refreshing your browser.</p>';
|
||||||
|
} else {
|
||||||
|
html += '<p class="status-err">❌ Bitcoin service is not running.</p>';
|
||||||
|
}
|
||||||
|
} else if (!bitcoindActive) {
|
||||||
|
// technically covered above, but keep explicit
|
||||||
|
html += '<p class="status-err">❌ Bitcoin service is not running.</p>';
|
||||||
|
} else if (ibd && progress < 0.1) {
|
||||||
|
// active but no real progress yet
|
||||||
|
html += '<p class="status-warn">⚠ Bitcoin Core is starting up and loading blockchain data. Please wait...</p>';
|
||||||
|
} else if (ibd) {
|
||||||
html += '<p class="status-warn">⚠ Bitcoin Core is syncing. Your miners will not be able to submit shares or receive work until the node is fully synced.</p>';
|
html += '<p class="status-warn">⚠ Bitcoin Core is syncing. Your miners will not be able to submit shares or receive work until the node is fully synced.</p>';
|
||||||
} else {
|
} else {
|
||||||
html += '<p class="status-ok">✔ Bitcoin Core is in sync.</p>';
|
html += '<p class="status-ok">✔ Bitcoin Core is in sync.</p>';
|
||||||
@ -519,27 +542,44 @@ async function loadStatus() {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
const box = document.getElementById('node-status');
|
const box = document.getElementById('node-status');
|
||||||
box.innerHTML = '<h2>Status</h2><p class="status-err">Failed to fetch status.</p>';
|
box.innerHTML = '<h2>Status</h2><p class="status-err">Failed to fetch status.</p>';
|
||||||
|
setFaviconAndTitle(false, 0, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inline SVG favicons
|
// Inline SVG favicons
|
||||||
const FAV_SYNC = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Crect width='64' height='64' fill='%23222'/%3E%3Ctext x='50%25' y='55%25' text-anchor='middle' font-size='32' fill='%23ffb347'%3E%E2%9A%A0%3C/text%3E%3C/svg%3E";
|
const FAV_SYNC = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Crect width='64' height='64' fill='%23222'/%3E%3Ctext x='50%25' y='55%25' text-anchor='middle' font-size='32' fill='%23ffb347'%3E%E2%9A%A0%3C/text%3E%3C/svg%3E";
|
||||||
const FAV_READY = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Crect width='64' height='64' fill='%23161717'/%3E%3Ctext x='50%25' y='55%25' text-anchor='middle' font-size='34' fill='%238f8'%3E%E2%9C%94%3C/text%3E%3C/svg%3E";
|
const FAV_READY = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Crect width='64' height='64' fill='%23161717'/%3E%3Ctext x='50%25' y='55%25' text-anchor='middle' font-size='34' fill='%238f8'%3E%E2%9C%94%3C/text%3E%3C/svg%3E";
|
||||||
|
const FAV_ERR = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Crect width='64' height='64' fill='%23222222'/%3E%3Ctext x='50%25' y='55%25' text-anchor='middle' font-size='34' fill='%23ff6b6b'%3E!%3C/text%3E%3C/svg%3E";
|
||||||
|
|
||||||
function setFaviconAndTitle(isSyncing, progress) {
|
function setFaviconAndTitle(isSyncing, progress, isError = false) {
|
||||||
const link = document.getElementById('app-favicon');
|
const link = document.getElementById('app-favicon');
|
||||||
if (!link) return;
|
if (!link) return;
|
||||||
|
if (isError) {
|
||||||
|
link.href = FAV_ERR;
|
||||||
|
document.title = "Disconnected • Bitcoin Solo Miner";
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isSyncing) {
|
if (isSyncing) {
|
||||||
link.href = FAV_SYNC;
|
link.href = FAV_SYNC;
|
||||||
document.title = "Syncing… " + progress.toFixed(1) + "% | Bitcoin Node";
|
document.title = "Syncing… " + progress.toFixed(1) + "% | Bitcoin Solo Miner";
|
||||||
} else {
|
} else {
|
||||||
link.href = FAV_READY;
|
link.href = FAV_READY;
|
||||||
document.title = "Ready • Bitcoin Node";
|
document.title = "Ready • Bitcoin Solo Miner";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadStatus();
|
loadStatus();
|
||||||
setInterval(loadStatus, 5000);
|
setInterval(loadStatus, 5000);
|
||||||
|
setInterval(() => {
|
||||||
|
if (Date.now() - lastStatusOk > STALE_MS) {
|
||||||
|
// no successful poll in 30s -> error state
|
||||||
|
setFaviconAndTitle(false, 0, true);
|
||||||
|
const box = document.getElementById('node-status');
|
||||||
|
if (box && !box.innerHTML.includes('Failed to fetch')) {
|
||||||
|
box.innerHTML = '<h2>Status</h2><p class="status-err">Status information unavailable (stale data > 30s). If this persists, try refreshing your browser.</p>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user