Optimize home page loading by prioritizing critical data
**Motivations:** - La home est très lente au premier lancement - Tous les endpoints sont chargés en parallèle, y compris les plus lents - L'endpoint /api/utxo/list est très lent car il charge toute la liste **Root causes:** - loadData() charge 10 endpoints en parallèle sans priorisation - loadAvailableForAnchor() charge toute la liste UTXO juste pour obtenir un count - Les données moins critiques (avg fee, avg tx amount) bloquent l'affichage initial **Correctifs:** - Chargement en 2 phases : données critiques d'abord, données secondaires ensuite - Création d'un endpoint optimisé /api/utxo/count qui lit directement depuis le fichier texte - loadAvailableForAnchor() utilise maintenant l'endpoint optimisé au lieu de /api/utxo/list - Les données secondaires (avg fee, avg tx amount, avg block time) sont chargées en arrière-plan **Evolutions:** - Affichage initial plus rapide avec les données critiques - Meilleure expérience utilisateur avec chargement progressif - Endpoint optimisé pour obtenir le count sans charger toute la liste UTXO **Pages affectées:** - signet-dashboard/src/server.js : Nouvel endpoint /api/utxo/count - signet-dashboard/public/app.js : Optimisation de loadData() et loadAvailableForAnchor()
This commit is contained in:
parent
bb28499e3f
commit
548eb220da
@ -61,23 +61,32 @@ function startBlockPolling() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Charge toutes les données de supervision
|
* Charge toutes les données de supervision
|
||||||
|
* Optimisé pour charger d'abord les données critiques, puis les données moins critiques
|
||||||
*/
|
*/
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
try {
|
try {
|
||||||
|
// Phase 1 : Charger les données critiques rapidement (affichage immédiat)
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
loadBlockchainInfo(),
|
loadBlockchainInfo(),
|
||||||
loadLatestBlock(),
|
loadLatestBlock(),
|
||||||
loadWalletBalance(),
|
loadWalletBalance(),
|
||||||
loadAnchorCount(),
|
loadAnchorCount(),
|
||||||
loadAvailableForAnchor(),
|
|
||||||
loadNetworkPeers(),
|
loadNetworkPeers(),
|
||||||
loadMiningDifficulty(),
|
loadMiningDifficulty(),
|
||||||
loadAvgBlockTime(),
|
|
||||||
loadAvgFee(),
|
|
||||||
loadAvgTxAmount(),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
updateLastUpdateTime();
|
updateLastUpdateTime();
|
||||||
|
|
||||||
|
// Phase 2 : Charger les données moins critiques en arrière-plan (peuvent être plus lentes)
|
||||||
|
// Ne pas attendre ces données pour mettre à jour l'heure
|
||||||
|
Promise.all([
|
||||||
|
loadAvailableForAnchor(),
|
||||||
|
loadAvgBlockTime(),
|
||||||
|
loadAvgFee(),
|
||||||
|
loadAvgTxAmount(),
|
||||||
|
]).catch((error) => {
|
||||||
|
console.error('Error loading secondary data:', error);
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading data:', error);
|
console.error('Error loading data:', error);
|
||||||
}
|
}
|
||||||
@ -190,13 +199,13 @@ async function loadAnchorCount() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Charge la capacité d'ancrage restante
|
* Charge la capacité d'ancrage restante
|
||||||
|
* Utilise l'endpoint optimisé /api/utxo/count pour éviter de charger toute la liste
|
||||||
*/
|
*/
|
||||||
async function loadAvailableForAnchor() {
|
async function loadAvailableForAnchor() {
|
||||||
const availableForAnchorValue = document.getElementById('available-for-anchor-value');
|
const availableForAnchorValue = document.getElementById('available-for-anchor-value');
|
||||||
const availableForAnchorSpinner = document.getElementById('available-for-anchor-spinner');
|
const availableForAnchorSpinner = document.getElementById('available-for-anchor-spinner');
|
||||||
const confirmedAvailableForAnchorValue = document.getElementById('confirmed-available-for-anchor-value');
|
|
||||||
|
|
||||||
if (!availableForAnchorValue || !availableForAnchorSpinner || !confirmedAvailableForAnchorValue) {
|
if (!availableForAnchorValue || !availableForAnchorSpinner) {
|
||||||
console.error('Elements for available-for-anchor not found in DOM');
|
console.error('Elements for available-for-anchor not found in DOM');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -204,24 +213,21 @@ async function loadAvailableForAnchor() {
|
|||||||
// Afficher le spinner
|
// Afficher le spinner
|
||||||
availableForAnchorSpinner.style.display = 'inline';
|
availableForAnchorSpinner.style.display = 'inline';
|
||||||
availableForAnchorValue.textContent = '...';
|
availableForAnchorValue.textContent = '...';
|
||||||
confirmedAvailableForAnchorValue.textContent = '...';
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}/api/utxo/list`);
|
// Utiliser l'endpoint optimisé qui lit directement depuis le fichier texte
|
||||||
|
const response = await fetch(`${API_BASE_URL}/api/utxo/count`);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
const counts = data.counts || {};
|
const availableForAnchor = data.availableForAnchor || 0;
|
||||||
const availableForAnchor = counts.availableForAnchor || 0;
|
|
||||||
const confirmedAvailableForAnchor = counts.confirmedAvailableForAnchor || 0;
|
|
||||||
|
|
||||||
// Masquer le spinner et mettre à jour les valeurs
|
// Masquer le spinner et mettre à jour la valeur
|
||||||
availableForAnchorSpinner.style.display = 'none';
|
availableForAnchorSpinner.style.display = 'none';
|
||||||
availableForAnchorValue.textContent = availableForAnchor.toLocaleString('fr-FR') + ' ancrages';
|
availableForAnchorValue.textContent = availableForAnchor.toLocaleString('fr-FR') + ' ancrages';
|
||||||
confirmedAvailableForAnchorValue.textContent = confirmedAvailableForAnchor.toLocaleString('fr-FR');
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading available for anchor:', error);
|
console.error('Error loading available for anchor:', error);
|
||||||
// Masquer le spinner
|
// Masquer le spinner
|
||||||
@ -231,7 +237,6 @@ async function loadAvailableForAnchor() {
|
|||||||
if (currentValue === '-' || currentValue === 'Erreur' || currentValue === '...') {
|
if (currentValue === '-' || currentValue === 'Erreur' || currentValue === '...') {
|
||||||
availableForAnchorValue.textContent = '0 ancrages';
|
availableForAnchorValue.textContent = '0 ancrages';
|
||||||
}
|
}
|
||||||
confirmedAvailableForAnchorValue.textContent = '0';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -273,6 +273,60 @@ app.get('/api/hash/list.txt', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Route optimisée pour obtenir uniquement les counts UTXO (sans charger toute la liste)
|
||||||
|
app.get('/api/utxo/count', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { readFileSync, existsSync } = await import('fs');
|
||||||
|
const utxoListPath = join(__dirname, '../../utxo_list.txt');
|
||||||
|
|
||||||
|
if (!existsSync(utxoListPath)) {
|
||||||
|
return res.json({
|
||||||
|
availableForAnchor: 0,
|
||||||
|
confirmedAvailableForAnchor: 0,
|
||||||
|
anchors: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lire le fichier et compter rapidement sans parser toute la structure
|
||||||
|
const content = readFileSync(utxoListPath, 'utf8').trim();
|
||||||
|
const lines = content.split('\n').filter(line => line.trim());
|
||||||
|
|
||||||
|
let anchors = 0;
|
||||||
|
let availableForAnchor = 0;
|
||||||
|
let confirmedAvailableForAnchor = 0;
|
||||||
|
const minAnchorAmount = 2000 / 100000000; // 2000 sats en BTC
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const parts = line.split(';');
|
||||||
|
if (parts.length >= 7) {
|
||||||
|
const category = parts[0];
|
||||||
|
const amount = parseFloat(parts[3]) || 0;
|
||||||
|
const confirmations = parseInt(parts[4], 10) || 0;
|
||||||
|
const isAnchorChange = parts[5] === 'true';
|
||||||
|
|
||||||
|
if (category === 'anchor' && amount >= minAnchorAmount && confirmations > 0) {
|
||||||
|
anchors++;
|
||||||
|
// On assume que les UTXOs dans le fichier ne sont pas dépensés (isSpentOnchain serait dans un autre champ)
|
||||||
|
// Pour être sûr, on vérifie seulement les confirmations
|
||||||
|
availableForAnchor++;
|
||||||
|
if (confirmations >= 6) {
|
||||||
|
confirmedAvailableForAnchor++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
availableForAnchor,
|
||||||
|
confirmedAvailableForAnchor,
|
||||||
|
anchors,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error getting UTXO count', { error: error.message });
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Route pour obtenir la liste des UTXO (fichier texte)
|
// Route pour obtenir la liste des UTXO (fichier texte)
|
||||||
app.get('/api/utxo/list', async (req, res) => {
|
app.get('/api/utxo/list', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user