diff --git a/docker/bitcoin-ui/index.html b/docker/bitcoin-ui/index.html index d24dc0fd..fd656fd1 100644 --- a/docker/bitcoin-ui/index.html +++ b/docker/bitcoin-ui/index.html @@ -779,6 +779,18 @@ if (el) el.textContent = value || fallback; } + function setTextIfPresent(id, value) { + const el = document.getElementById(id); + if (el) el.textContent = value; + return el; + } + + function setWidthIfPresent(id, value) { + const el = document.getElementById(id); + if (el) el.style.width = value; + return el; + } + function renderRelayRequests(requests = []) { const list = document.getElementById('relayRequestsList'); if (!list) return; @@ -1115,7 +1127,9 @@ const rpcEl = document.getElementById('settingsRpc'); if (rpcEl) { const port = chain === 'main' ? 8332 : (chain === 'test' ? 18332 : (chain === 'signet' ? 38332 : 18443)); - rpcEl.textContent = status.stale + const statusAgeMs = status.updated_at_ms ? Date.now() - status.updated_at_ms : Number.POSITIVE_INFINITY; + const displayStale = status.stale === true && statusAgeMs > 30000; + rpcEl.textContent = displayStale ? `Reconnecting on port ${port}` : `Reachable on port ${port}`; } @@ -1128,6 +1142,10 @@ const isSynced = headers > 0 && blocks >= headers - 1 && !initialBlockDownload; const diskSize = formatBytes(blockchainInfo.size_on_disk || 0); const appearsToBeReindexing = initialBlockDownload && blocks === 0 && headers > 0 && (blockchainInfo.size_on_disk || 0) > 1024 * 1024 * 1024; + const previousBlockCount = lastBlockCount; + const statusAgeMs = status.updated_at_ms ? Date.now() - status.updated_at_ms : Number.POSITIVE_INFINITY; + const snapshotAdvanced = previousBlockCount > 0 && blocks > previousBlockCount; + const displayStale = status.stale === true && !snapshotAdvanced && statusAgeMs > 30000; // Calculate actual sync percentage based on blocks/headers const actualSyncValue = headers > 0 ? (blocks / headers) * 100 : 0; @@ -1137,21 +1155,21 @@ // Animate block count if it changed const currentHeightElem = document.getElementById('currentHeight'); - if (blocks !== lastBlockCount && lastBlockCount > 0) { + if (currentHeightElem && blocks !== lastBlockCount && lastBlockCount > 0) { currentHeightElem.classList.add('number-update'); setTimeout(() => currentHeightElem.classList.remove('number-update'), 500); } lastBlockCount = blocks; - currentHeightElem.textContent = blocks.toLocaleString(); - document.getElementById('networkHeight').textContent = headers.toLocaleString(); - document.getElementById('headers').textContent = headers.toLocaleString(); - document.getElementById('verificationProgress').textContent = `${verificationPercentage}%`; - document.getElementById('syncPercentage').textContent = `${actualSyncPercentage}%`; - document.getElementById('currentBlock').textContent = appearsToBeReindexing + setTextIfPresent('currentHeight', blocks.toLocaleString()); + setTextIfPresent('networkHeight', headers.toLocaleString()); + setTextIfPresent('headers', headers.toLocaleString()); + setTextIfPresent('verificationProgress', `${verificationPercentage}%`); + setTextIfPresent('syncPercentage', `${actualSyncPercentage}%`); + setTextIfPresent('currentBlock', appearsToBeReindexing ? 'Reindexing from disk' - : `Block ${blocks.toLocaleString()}`; - document.getElementById('syncProgressBar').style.width = `${progressWidth}%`; + : `Block ${blocks.toLocaleString()}`); + setWidthIfPresent('syncProgressBar', `${progressWidth}%`); // Update sync status text and icon const syncStatusText = document.getElementById('syncStatusText'); @@ -1165,10 +1183,10 @@ syncIcon.classList.remove('text-green-500'); } } else if (isSynced) { - syncStatusText.textContent = status.stale + syncStatusText.textContent = displayStale ? 'Bitcoin node is reconnecting... showing last known synchronized state' : '✓ Fully synchronized with the network'; - syncStatusText.className = status.stale ? 'text-yellow-300 text-sm font-medium' : 'text-green-400 text-sm font-medium'; + syncStatusText.className = displayStale ? 'text-yellow-300 text-sm font-medium' : 'text-green-400 text-sm font-medium'; // Stop spinning when synced if (syncIcon) { syncIcon.classList.remove('animate-spin-slow'); @@ -1176,12 +1194,12 @@ } } else { const remaining = headers - blocks; - syncStatusText.textContent = status.stale + syncStatusText.textContent = displayStale ? 'Bitcoin node is reconnecting... showing last known sync state' : initialBlockDownload ? `Initial block download... ${remaining.toLocaleString()} blocks remaining` : `Syncing... ${remaining.toLocaleString()} blocks remaining`; - syncStatusText.className = status.stale ? 'text-yellow-300 text-sm font-medium' : 'text-orange-400 text-sm font-medium'; + syncStatusText.className = displayStale ? 'text-yellow-300 text-sm font-medium' : 'text-orange-400 text-sm font-medium'; // Keep spinning while syncing if (syncIcon) { syncIcon.classList.add('animate-spin-slow'); diff --git a/neode-ui/src/views/home/HomeSystemCard.vue b/neode-ui/src/views/home/HomeSystemCard.vue index d32f5a32..0ea5f36b 100644 --- a/neode-ui/src/views/home/HomeSystemCard.vue +++ b/neode-ui/src/views/home/HomeSystemCard.vue @@ -13,7 +13,7 @@

{{ t('home.system') }}

{{ uptimeDisplay }}

- + diff --git a/scripts/deploy-to-target.sh b/scripts/deploy-to-target.sh index 96e17ce4..5770bc7a 100755 --- a/scripts/deploy-to-target.sh +++ b/scripts/deploy-to-target.sh @@ -1817,34 +1817,37 @@ LNDCONF # resolve container IPs for nginx proxy (DNS resolver 127.0.0.11 is unreliable in podman) progress "Fixing IndeedHub for NIP-07" ssh $SSH_OPTS "$TARGET_HOST" ' - if podman ps --format "{{.Names}}" 2>/dev/null | grep -q "^indeedhub$"; then + podman_quick() { timeout 20 podman "$@"; } + podman_exec_quick() { timeout 20 podman exec "$@"; } + + if podman_quick ps --format "{{.Names}}" 2>/dev/null | grep -q "^indeedhub$"; then CHANGED=false - NETWORK=$(podman inspect indeedhub --format "{{range \$k, \$v := .NetworkSettings.Networks}}{{\$k}}{{end}}" 2>/dev/null) + NETWORK=$(podman_quick inspect indeedhub --format "{{range \$k, \$v := .NetworkSettings.Networks}}{{\$k}}{{end}}" 2>/dev/null || true) # Remove X-Frame-Options so iframe works - if podman exec indeedhub grep -q "X-Frame-Options" /etc/nginx/conf.d/default.conf 2>/dev/null; then - podman exec indeedhub sed -i "/X-Frame-Options/d" /etc/nginx/conf.d/default.conf + if podman_exec_quick indeedhub grep -q "X-Frame-Options" /etc/nginx/conf.d/default.conf 2>/dev/null; then + podman_exec_quick indeedhub sed -i "/X-Frame-Options/d" /etc/nginx/conf.d/default.conf || true CHANGED=true echo " Removed X-Frame-Options from IndeedHub" fi # Fix Host header for NIP-98 auth — $host strips port, $http_host preserves it - podman exec indeedhub sh -c "sed -i '"'"'s/proxy_set_header Host \$host;/proxy_set_header Host \$http_host;/g'"'"' /etc/nginx/conf.d/default.conf" 2>/dev/null && CHANGED=true && echo " Fixed Host header for NIP-98 auth" || true + podman_exec_quick indeedhub sh -c "sed -i '"'"'s/proxy_set_header Host \$host;/proxy_set_header Host \$http_host;/g'"'"' /etc/nginx/conf.d/default.conf" 2>/dev/null && CHANGED=true && echo " Fixed Host header for NIP-98 auth" || true # Inject nostr-provider.js for NIP-07 signing - if ! podman exec indeedhub test -f /usr/share/nginx/html/nostr-provider.js 2>/dev/null; then - podman cp /opt/archipelago/web-ui/nostr-provider.js indeedhub:/usr/share/nginx/html/nostr-provider.js 2>/dev/null + if ! podman_exec_quick indeedhub test -f /usr/share/nginx/html/nostr-provider.js 2>/dev/null; then + podman_quick cp /opt/archipelago/web-ui/nostr-provider.js indeedhub:/usr/share/nginx/html/nostr-provider.js 2>/dev/null || true echo " Copied nostr-provider.js into IndeedHub" fi # Add nostr-provider.js + sub_filter to nginx config - if ! podman exec indeedhub grep -q "nostr-provider" /etc/nginx/conf.d/default.conf 2>/dev/null; then - podman exec indeedhub cat /etc/nginx/conf.d/default.conf > /tmp/ih-nginx.conf 2>/dev/null + if ! podman_exec_quick indeedhub grep -q "nostr-provider" /etc/nginx/conf.d/default.conf 2>/dev/null; then + podman_exec_quick indeedhub cat /etc/nginx/conf.d/default.conf > /tmp/ih-nginx.conf 2>/dev/null || true # Add nostr-provider location block before sw.js block sed -i "/location = \/sw.js {/i\\ location = /nostr-provider.js {\n add_header Cache-Control \"no-cache, no-store, must-revalidate\";\n expires off;\n }\n" /tmp/ih-nginx.conf # Add sub_filter for nostr-provider injection sed -i "/try_files.*index.html/a\\ sub_filter_once on;\n sub_filter '"'"''"'"' '"'"''"'"';" /tmp/ih-nginx.conf - podman cp /tmp/ih-nginx.conf indeedhub:/etc/nginx/conf.d/default.conf 2>/dev/null + podman_quick cp /tmp/ih-nginx.conf indeedhub:/etc/nginx/conf.d/default.conf 2>/dev/null || true rm -f /tmp/ih-nginx.conf CHANGED=true echo " Injected nostr-provider.js into IndeedHub nginx" @@ -1852,26 +1855,26 @@ LNDCONF # Replace DNS-based upstream resolution with hardcoded container IPs # (podman DNS resolver 127.0.0.11 is unreliable, causing 502 errors) - API_IP=$(podman inspect indeedhub-build_api_1 --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null) - MINIO_IP=$(podman inspect indeedhub-minio --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null) - RELAY_IP=$(podman inspect indeedhub-relay --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null) + API_IP=$(podman_quick inspect indeedhub-build_api_1 --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null || true) + MINIO_IP=$(podman_quick inspect indeedhub-minio --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null || true) + RELAY_IP=$(podman_quick inspect indeedhub-relay --format "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" 2>/dev/null || true) if [ -n "$API_IP" ] && [ -n "$MINIO_IP" ] && [ -n "$RELAY_IP" ]; then - podman exec indeedhub cat /etc/nginx/conf.d/default.conf > /tmp/ih-nginx.conf 2>/dev/null + podman_exec_quick indeedhub cat /etc/nginx/conf.d/default.conf > /tmp/ih-nginx.conf 2>/dev/null || true # Remove DNS resolver lines and replace upstream variables with hardcoded IPs sed -i "s|resolver 127.0.0.11 valid=30s ipv6=off;||g" /tmp/ih-nginx.conf sed -i "s|set \$api_upstream http://api:4000;|set \$api_upstream http://$API_IP:4000;|g" /tmp/ih-nginx.conf sed -i "s|set \$minio_upstream http://minio:9000;|set \$minio_upstream http://$MINIO_IP:9000;|g" /tmp/ih-nginx.conf sed -i "s|set \$relay_upstream http://relay:8080;|set \$relay_upstream http://$RELAY_IP:8080;|g" /tmp/ih-nginx.conf sed -i "s|proxy_set_header Host \$host;|proxy_set_header Host \$http_host;|g" /tmp/ih-nginx.conf - podman cp /tmp/ih-nginx.conf indeedhub:/etc/nginx/conf.d/default.conf 2>/dev/null + podman_quick cp /tmp/ih-nginx.conf indeedhub:/etc/nginx/conf.d/default.conf 2>/dev/null || true rm -f /tmp/ih-nginx.conf CHANGED=true echo " Patched IndeedHub nginx with container IPs (API=$API_IP MINIO=$MINIO_IP RELAY=$RELAY_IP)" fi if [ "$CHANGED" = true ]; then - podman exec indeedhub nginx -s reload 2>/dev/null + podman_exec_quick indeedhub nginx -s reload 2>/dev/null || true fi fi ' 2>&1 | sed 's/^/ /' || true