mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2025-08-24 16:05:07 +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 = {}) {
|
async callAdmin(command, args = {}) {
|
||||||
const url = command ? `${this.baseURL}/${command}` : this.baseURL;
|
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 = {
|
const options = {
|
||||||
method: Object.keys(args).length > 0 ? 'POST' : 'GET',
|
method: Object.keys(args).length > 0 ? 'POST' : 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'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) {
|
if (Object.keys(args).length > 0) {
|
||||||
|
@ -29,6 +35,7 @@ class YggdrasilAPI {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url, options);
|
const response = await fetch(url, options);
|
||||||
|
clearTimeout(timeoutId); // Clear timeout on successful response
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
@ -42,6 +49,13 @@ class YggdrasilAPI {
|
||||||
|
|
||||||
return data.response || data.commands;
|
return data.response || data.commands;
|
||||||
} catch (error) {
|
} 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);
|
console.error(`API call failed for ${command}:`, error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,22 @@
|
||||||
window.nodeInfo = null;
|
window.nodeInfo = null;
|
||||||
window.peersData = null;
|
window.peersData = null;
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
|
let isLoadingNodeInfo = false;
|
||||||
|
let isLoadingPeers = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load and display node information
|
* Load and display node information
|
||||||
*/
|
*/
|
||||||
async function loadNodeInfo() {
|
async function loadNodeInfo() {
|
||||||
|
if (isLoadingNodeInfo) {
|
||||||
|
console.log('Node info request already in progress, skipping...');
|
||||||
|
return window.nodeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
isLoadingNodeInfo = true;
|
||||||
const info = await window.yggAPI.getSelf();
|
const info = await window.yggAPI.getSelf();
|
||||||
window.nodeInfo = info;
|
window.nodeInfo = info;
|
||||||
updateNodeInfoDisplay(info);
|
updateNodeInfoDisplay(info);
|
||||||
|
@ -21,6 +31,8 @@ async function loadNodeInfo() {
|
||||||
console.error('Failed to load node info:', error);
|
console.error('Failed to load node info:', error);
|
||||||
showError('Failed to load node information: ' + error.message);
|
showError('Failed to load node information: ' + error.message);
|
||||||
throw error;
|
throw error;
|
||||||
|
} finally {
|
||||||
|
isLoadingNodeInfo = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +40,13 @@ async function loadNodeInfo() {
|
||||||
* Load and display peers information
|
* Load and display peers information
|
||||||
*/
|
*/
|
||||||
async function loadPeers() {
|
async function loadPeers() {
|
||||||
|
if (isLoadingPeers) {
|
||||||
|
console.log('Peers request already in progress, skipping...');
|
||||||
|
return window.peersData;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
isLoadingPeers = true;
|
||||||
const data = await window.yggAPI.getPeers();
|
const data = await window.yggAPI.getPeers();
|
||||||
window.peersData = data;
|
window.peersData = data;
|
||||||
updatePeersDisplay(data);
|
updatePeersDisplay(data);
|
||||||
|
@ -37,6 +55,8 @@ async function loadPeers() {
|
||||||
console.error('Failed to load peers:', error);
|
console.error('Failed to load peers:', error);
|
||||||
showError('Failed to load peers information: ' + error.message);
|
showError('Failed to load peers information: ' + error.message);
|
||||||
throw error;
|
throw error;
|
||||||
|
} finally {
|
||||||
|
isLoadingPeers = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +120,8 @@ function updatePeersDisplay(data) {
|
||||||
window.updateNodeInfoDisplay = updateNodeInfoDisplay;
|
window.updateNodeInfoDisplay = updateNodeInfoDisplay;
|
||||||
window.updatePeersDisplay = updatePeersDisplay;
|
window.updatePeersDisplay = updatePeersDisplay;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Expose copy functions to window for access from HTML onclick handlers
|
// Expose copy functions to window for access from HTML onclick handlers
|
||||||
window.copyNodeKey = copyNodeKey;
|
window.copyNodeKey = copyNodeKey;
|
||||||
window.copyNodeAddress = copyNodeAddress;
|
window.copyNodeAddress = copyNodeAddress;
|
||||||
|
@ -359,18 +381,23 @@ function copyPeerKey(key) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auto-refresh data
|
* Auto-refresh data
|
||||||
*/
|
*/
|
||||||
function startAutoRefresh() {
|
function startAutoRefresh() {
|
||||||
// Refresh every 30 seconds
|
// Refresh every 30 seconds
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
if (!isLoading) {
|
// Only proceed if individual requests are not already in progress
|
||||||
|
if (!isLoadingNodeInfo && !isLoadingPeers) {
|
||||||
try {
|
try {
|
||||||
await Promise.all([loadNodeInfo(), loadPeers()]);
|
await Promise.all([loadNodeInfo(), loadPeers()]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Auto-refresh failed:', error);
|
console.error('Auto-refresh failed:', error);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Skipping auto-refresh - requests already in progress');
|
||||||
}
|
}
|
||||||
}, 30000);
|
}, 30000);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,11 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Decorative progress bar -->
|
||||||
|
<div class="progress-timer-container">
|
||||||
|
<div class="progress-timer-bar"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<header>
|
<header>
|
||||||
<div class="header-content">
|
<div class="header-content">
|
||||||
|
|
|
@ -114,6 +114,16 @@
|
||||||
--shadow-heavy: rgba(0, 0, 0, 0.5);
|
--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;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -128,6 +138,24 @@ body {
|
||||||
overflow: hidden; /* Prevent body scroll */
|
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 {
|
.container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 250px 1fr;
|
grid-template-columns: 250px 1fr;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue