mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2025-08-24 07:55:06 +03:00
Add timeout handling and loading state management in API calls
This commit is contained in:
parent
1f75299312
commit
fcb5efd753
4 changed files with 76 additions and 2 deletions
|
@ -15,12 +15,18 @@ class YggdrasilAPI {
|
|||
*/
|
||||
async callAdmin(command, args = {}) {
|
||||
const url = command ? `${this.baseURL}/${command}` : this.baseURL;
|
||||
|
||||
// Create AbortController for timeout functionality
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5 second timeout
|
||||
|
||||
const options = {
|
||||
method: Object.keys(args).length > 0 ? 'POST' : 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin' // Include session cookies
|
||||
credentials: 'same-origin', // Include session cookies
|
||||
signal: controller.signal
|
||||
};
|
||||
|
||||
if (Object.keys(args).length > 0) {
|
||||
|
@ -29,6 +35,7 @@ class YggdrasilAPI {
|
|||
|
||||
try {
|
||||
const response = await fetch(url, options);
|
||||
clearTimeout(timeoutId); // Clear timeout on successful response
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
|
@ -42,6 +49,13 @@ class YggdrasilAPI {
|
|||
|
||||
return data.response || data.commands;
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId); // Clear timeout on error
|
||||
|
||||
if (error.name === 'AbortError') {
|
||||
console.error(`API call timeout for ${command}:`, error);
|
||||
throw new Error('Request timeout - service may be unavailable');
|
||||
}
|
||||
|
||||
console.error(`API call failed for ${command}:`, error);
|
||||
throw error;
|
||||
}
|
||||
|
|
|
@ -7,12 +7,22 @@
|
|||
window.nodeInfo = null;
|
||||
window.peersData = null;
|
||||
let isLoading = false;
|
||||
let isLoadingNodeInfo = false;
|
||||
let isLoadingPeers = false;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load and display node information
|
||||
*/
|
||||
async function loadNodeInfo() {
|
||||
if (isLoadingNodeInfo) {
|
||||
console.log('Node info request already in progress, skipping...');
|
||||
return window.nodeInfo;
|
||||
}
|
||||
|
||||
try {
|
||||
isLoadingNodeInfo = true;
|
||||
const info = await window.yggAPI.getSelf();
|
||||
window.nodeInfo = info;
|
||||
updateNodeInfoDisplay(info);
|
||||
|
@ -21,6 +31,8 @@ async function loadNodeInfo() {
|
|||
console.error('Failed to load node info:', error);
|
||||
showError('Failed to load node information: ' + error.message);
|
||||
throw error;
|
||||
} finally {
|
||||
isLoadingNodeInfo = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +40,13 @@ async function loadNodeInfo() {
|
|||
* Load and display peers information
|
||||
*/
|
||||
async function loadPeers() {
|
||||
if (isLoadingPeers) {
|
||||
console.log('Peers request already in progress, skipping...');
|
||||
return window.peersData;
|
||||
}
|
||||
|
||||
try {
|
||||
isLoadingPeers = true;
|
||||
const data = await window.yggAPI.getPeers();
|
||||
window.peersData = data;
|
||||
updatePeersDisplay(data);
|
||||
|
@ -37,6 +55,8 @@ async function loadPeers() {
|
|||
console.error('Failed to load peers:', error);
|
||||
showError('Failed to load peers information: ' + error.message);
|
||||
throw error;
|
||||
} finally {
|
||||
isLoadingPeers = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,6 +120,8 @@ function updatePeersDisplay(data) {
|
|||
window.updateNodeInfoDisplay = updateNodeInfoDisplay;
|
||||
window.updatePeersDisplay = updatePeersDisplay;
|
||||
|
||||
|
||||
|
||||
// Expose copy functions to window for access from HTML onclick handlers
|
||||
window.copyNodeKey = copyNodeKey;
|
||||
window.copyNodeAddress = copyNodeAddress;
|
||||
|
@ -359,18 +381,23 @@ function copyPeerKey(key) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Auto-refresh data
|
||||
*/
|
||||
function startAutoRefresh() {
|
||||
// Refresh every 30 seconds
|
||||
setInterval(async () => {
|
||||
if (!isLoading) {
|
||||
// Only proceed if individual requests are not already in progress
|
||||
if (!isLoadingNodeInfo && !isLoadingPeers) {
|
||||
try {
|
||||
await Promise.all([loadNodeInfo(), loadPeers()]);
|
||||
} catch (error) {
|
||||
console.error('Auto-refresh failed:', error);
|
||||
}
|
||||
} else {
|
||||
console.log('Skipping auto-refresh - requests already in progress');
|
||||
}
|
||||
}, 30000);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Decorative progress bar -->
|
||||
<div class="progress-timer-container">
|
||||
<div class="progress-timer-bar"></div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<header>
|
||||
<div class="header-content">
|
||||
|
|
|
@ -114,6 +114,16 @@
|
|||
--shadow-heavy: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
/* Dark theme progress bar adjustments */
|
||||
[data-theme="dark"] .progress-timer-container {
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .progress-timer-bar {
|
||||
background: linear-gradient(90deg, #3498db, #27ae60);
|
||||
box-shadow: 0 0 10px rgba(52, 152, 219, 0.3);
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
@ -128,6 +138,24 @@ body {
|
|||
overflow: hidden; /* Prevent body scroll */
|
||||
}
|
||||
|
||||
/* Decorative progress bar */
|
||||
.progress-timer-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.progress-timer-bar {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #3498db, #2ecc71);
|
||||
width: 100%;
|
||||
box-shadow: 0 0 10px rgba(52, 152, 219, 0.5);
|
||||
}
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-columns: 250px 1fr;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue