// Application state and configuration
const App = {
apiBase: "/api",
elements: {
connectionList: document.getElementById('connections__container'),
statusArea: document.getElementById('status__container'),
messageArea: document.getElementById('notifications__container')
}
};
// Utility functions
const Utils = {
// Show message to user
renderError(element, message) {
Utils.renderMessage(element, message, "error");
},
renderWarning(element, message) {
Utils.renderMessage(element, message, "warning");
},
renderSuccess(element, message) {
Utils.renderMessage(element, message, "success");
},
renderMessage(element, message, type = '') {
element.innerHTML = `
${message}
`;
},
// Make API calls with proper error handling
async apiCall(endpoint, options = {}) {
try {
const response = await fetch(`${App.apiBase}${endpoint}`, {
headers: {
'Content-Type': 'application/json',
...options.headers
},
...options
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || `HTTP ${response.status}`);
}
if (!data.success) {
throw new Error(data.error || 'API request failed');
}
return data.data;
} catch (error) {
console.error('API call failed:', error);
throw error;
}
}
};
// Connection management
const ConnectionManager = {
// Load and display all connections
async loadConnections() {
try {
const connections = await Utils.apiCall('/connections');
this.renderConnections(connections);
} catch (error) {
Utils.renderError(App.elements.connectionList,
`Failed to load connections: ${error.message}`);
}
},
// Render connections to the DOM
renderConnections(connections) {
if (!connections || connections.length === 0) {
Utils.renderWarning(App.elements.connectionList,
"No WireGuard connections found in /etc/wireguard/");
return;
}
const html = connections.map(conn => `
`).join('');
App.elements.connectionList.innerHTML = html;
},
// Toggle connection state
async toggleConnection(name) {
const connection = document.querySelector(`[data-connection="${name}"]`);
try {
connection.disabled = true;
connection.textContent = 'Processing...';
connection.className = "connection loading"
await Utils.apiCall('/connections/toggle', {
method: 'POST',
body: JSON.stringify({ name })
});
await this.loadConnections(); // Refresh the list
await StatusManager.loadStatus(); // Refresh the status
Utils.renderSuccess(App.elements.messageArea, `No Errors Found.`);
} catch (error) {
Utils.renderError(App.elements.messageArea, `Failed to toggle ${name}: ${error.message}`);
connection.disabled = false;
connection.textContent = name;
connection.className = "connection"
}
}
};
// Status management
const StatusManager = {
intervalId: null,
// Load and display WireGuard status
async loadStatus() {
try {
const statusData = await Utils.apiCall('/status');
const statusText = statusData.status;
if (statusText) {
Utils.renderSuccess(App.elements.statusArea, statusText);
} else {
Utils.renderWarning(App.elements.statusArea, "No active connections.");
}
} catch (error) {
Utils.renderError(App.elements.statusArea, error.message);
}
},
startAutoRefresh() {
// Clear any existing interval first
this.stopAutoRefresh();
// Start new interval
this.intervalId = setInterval(() => this.loadStatus(), 5000);
},
stopAutoRefresh() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
};
// Initialize the application
document.addEventListener('DOMContentLoaded', () => {
StatusManager.loadStatus();
ConnectionManager.loadConnections();
StatusManager.startAutoRefresh();
});
// Pause when tab is hidden, resume when visible
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
StatusManager.stopAutoRefresh();
} else {
StatusManager.loadStatus(); // Immediate refresh when back
StatusManager.startAutoRefresh();
}
});