/** * Application JavaScript pour le Dashboard Bitcoin Signet */ const API_BASE_URL = window.location.origin; // Utiliser le même origin pour le faucet (sera configuré via le proxy) // Si on est sur dashboard.certificator.4nkweb.com, utiliser faucet.certificator.4nkweb.com let FAUCET_API_URL; if (window.location.hostname.includes('dashboard.certificator.4nkweb.com')) { FAUCET_API_URL = window.location.origin.replace('dashboard.certificator.4nkweb.com', 'faucet.certificator.4nkweb.com'); } else if (window.location.hostname.includes('localhost') || window.location.hostname === '127.0.0.1') { FAUCET_API_URL = 'http://localhost:3021'; } else { FAUCET_API_URL = window.location.origin; } let selectedFile = null; // Initialisation document.addEventListener('DOMContentLoaded', () => { loadData(); setInterval(loadData, 30000); // Rafraîchir toutes les 30 secondes }); /** * Charge toutes les données de supervision */ async function loadData() { try { await Promise.all([ loadBlockchainInfo(), loadLatestBlock(), loadWalletBalance(), loadAnchorCount(), loadNetworkPeers(), ]); updateLastUpdateTime(); } catch (error) { console.error('Error loading data:', error); } } /** * Charge les informations de la blockchain */ async function loadBlockchainInfo() { try { const response = await fetch(`${API_BASE_URL}/api/blockchain/info`); const data = await response.json(); document.getElementById('block-height').textContent = data.blocks || 0; } catch (error) { console.error('Error loading blockchain info:', error); document.getElementById('block-height').textContent = 'Erreur'; } } /** * Charge les informations du dernier bloc */ async function loadLatestBlock() { try { const response = await fetch(`${API_BASE_URL}/api/blockchain/latest-block`); const data = await response.json(); if (data.time) { const date = new Date(data.time * 1000); document.getElementById('last-block-time').textContent = date.toLocaleString('fr-FR'); } else { document.getElementById('last-block-time').textContent = 'Aucun bloc'; } document.getElementById('last-block-tx-count').textContent = data.tx_count || 0; } catch (error) { console.error('Error loading latest block:', error); document.getElementById('last-block-time').textContent = 'Erreur'; document.getElementById('last-block-tx-count').textContent = 'Erreur'; } } /** * Charge le solde du wallet */ async function loadWalletBalance() { try { const response = await fetch(`${API_BASE_URL}/api/wallet/balance`); const data = await response.json(); document.getElementById('balance-mature').textContent = formatBTC(data.mature || 0); document.getElementById('balance-immature').textContent = formatBTC(data.immature || 0); } catch (error) { console.error('Error loading wallet balance:', error); document.getElementById('balance-mature').textContent = 'Erreur'; document.getElementById('balance-immature').textContent = 'Erreur'; } } /** * Charge le nombre d'ancrages */ async function loadAnchorCount() { try { const response = await fetch(`${API_BASE_URL}/api/anchor/count`); const data = await response.json(); document.getElementById('anchor-count').textContent = data.count || 0; } catch (error) { console.error('Error loading anchor count:', error); document.getElementById('anchor-count').textContent = 'Erreur'; } } /** * Charge les informations sur les pairs */ async function loadNetworkPeers() { try { const response = await fetch(`${API_BASE_URL}/api/network/peers`); const data = await response.json(); document.getElementById('peer-count').textContent = data.connections || 0; } catch (error) { console.error('Error loading network peers:', error); document.getElementById('peer-count').textContent = 'Erreur'; } } /** * Formate un montant en BTC */ function formatBTC(btc) { if (btc === 0) return '0 BTC'; if (btc < 0.000001) return `${(btc * 100000000).toFixed(0)} sats`; return `${btc.toFixed(8)} BTC`; } /** * Met à jour l'heure de dernière mise à jour */ function updateLastUpdateTime() { const now = new Date(); document.getElementById('last-update').textContent = now.toLocaleString('fr-FR'); } /** * Change d'onglet */ function switchTab(tab, buttonElement) { // Désactiver tous les onglets document.querySelectorAll('.tab-content').forEach(content => { content.classList.remove('active'); }); document.querySelectorAll('.tab-button').forEach(button => { button.classList.remove('active'); }); // Activer l'onglet sélectionné document.getElementById(`${tab}-tab`).classList.add('active'); // Activer le bouton correspondant if (buttonElement) { buttonElement.classList.add('active'); } } /** * Gère la sélection de fichier */ function handleFileSelect(event) { const file = event.target.files[0]; if (file) { selectedFile = file; const fileInfo = document.getElementById('file-info'); fileInfo.innerHTML = ` Fichier sélectionné : ${file.name}
Taille : ${formatFileSize(file.size)}
Type : ${file.type || 'Non spécifié'} `; } } /** * Formate la taille d'un fichier */ function formatFileSize(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]; } /** * Génère le hash depuis le texte */ async function generateHashFromText() { const text = document.getElementById('anchor-text').value; if (!text.trim()) { showResult('anchor-result', 'error', 'Veuillez entrer un texte à ancrer.'); return; } try { const response = await fetch(`${API_BASE_URL}/api/hash/generate`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ text }), }); const data = await response.json(); if (data.hash) { document.getElementById('anchor-hash').value = data.hash; showResult('anchor-result', 'success', `Hash généré avec succès : ${data.hash}`); } else { showResult('anchor-result', 'error', 'Erreur lors de la génération du hash.'); } } catch (error) { showResult('anchor-result', 'error', `Erreur : ${error.message}`); } } /** * Génère le hash depuis le fichier */ async function generateHashFromFile() { if (!selectedFile) { showResult('anchor-result', 'error', 'Veuillez sélectionner un fichier.'); return; } try { const reader = new FileReader(); reader.onload = async (e) => { const fileContent = e.target.result; try { const response = await fetch(`${API_BASE_URL}/api/hash/generate`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ fileContent }), }); const data = await response.json(); if (data.hash) { document.getElementById('anchor-hash').value = data.hash; showResult('anchor-result', 'success', `Hash généré avec succès : ${data.hash}`); } else { showResult('anchor-result', 'error', 'Erreur lors de la génération du hash.'); } } catch (error) { showResult('anchor-result', 'error', `Erreur : ${error.message}`); } }; reader.readAsText(selectedFile); } catch (error) { showResult('anchor-result', 'error', `Erreur lors de la lecture du fichier : ${error.message}`); } } /** * Ancre le document */ async function anchorDocument() { const hash = document.getElementById('anchor-hash').value; if (!hash || !/^[0-9a-fA-F]{64}$/.test(hash)) { showResult('anchor-result', 'error', 'Veuillez générer un hash valide (64 caractères hexadécimaux).'); return; } try { showResult('anchor-result', 'info', 'Ancrage en cours...'); const response = await fetch(`${API_BASE_URL}/api/anchor/test`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ hash }), }); const data = await response.json(); if (response.ok && data.txid) { showResult('anchor-result', 'success', `Document ancré avec succès !
TXID : ${data.txid}
Statut : ${data.status}
Confirmations : ${data.confirmations || 0}`); // Recharger le nombre d'ancrages après un court délai setTimeout(loadAnchorCount, 2000); } else { showResult('anchor-result', 'error', data.message || data.error || 'Erreur lors de l\'ancrage.'); } } catch (error) { showResult('anchor-result', 'error', `Erreur : ${error.message}`); } } /** * Demande des sats via le faucet */ async function requestFaucet() { const address = document.getElementById('faucet-address').value.trim(); if (!address) { showResult('faucet-result', 'error', 'Veuillez entrer une adresse Bitcoin.'); return; } // Validation basique de l'adresse const addressPattern = /^(tb1|bcrt1|2|3)[a-zA-HJ-NP-Z0-9]{25,62}$/; if (!addressPattern.test(address)) { showResult('faucet-result', 'error', 'Adresse Bitcoin invalide.'); return; } try { showResult('faucet-result', 'info', 'Demande en cours...'); const response = await fetch(`${FAUCET_API_URL}/api/faucet/request`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ address }), }); const data = await response.json(); if (response.ok && data.txid) { showResult('faucet-result', 'success', `50 000 sats envoyés avec succès !
TXID : ${data.txid}
Montant : ${data.amount || '50000'} sats
Statut : ${data.status || 'En attente de confirmation'}`); } else { showResult('faucet-result', 'error', data.message || data.error || 'Erreur lors de la demande.'); } } catch (error) { showResult('faucet-result', 'error', `Erreur : ${error.message}`); } } /** * Affiche un résultat */ function showResult(elementId, type, message) { const element = document.getElementById(elementId); element.className = `result ${type}`; element.innerHTML = message; }