Files
ospab.network/ostp-gui/ui/app.js
ospab 85a2b01074 feat: Windows stack (daemon, installer, GUI)
Components:
- ostp-daemon: Windows Service with Named Pipe IPC
- ostp-installer: Setup wizard with admin privileges
- ostp-gui: Tauri dark theme UI (450x600)

Features:
- Background service management (OspabGuard)
- IPC commands: CONNECT/DISCONNECT/STATUS
- Firewall rules auto-configuration
- Wintun driver placeholder (download from wintun.net)
- Real-time stats display (upload/download/ping)

Note: Requires wintun.dll download for full functionality
2026-01-02 02:17:15 +03:00

118 lines
3.5 KiB
JavaScript

const { invoke } = window.__TAURI__.core;
let isConnected = false;
// Initialize
document.addEventListener('DOMContentLoaded', async () => {
await loadServers();
await updateStatus();
// Update stats every 2 seconds when connected
setInterval(async () => {
if (isConnected) {
await updateStatus();
}
}, 2000);
});
async function loadServers() {
try {
const servers = await invoke('fetch_servers');
const select = document.getElementById('serverSelect');
select.innerHTML = '';
servers.forEach(server => {
const option = document.createElement('option');
option.value = server;
option.textContent = server;
select.appendChild(option);
});
} catch (error) {
console.error('Failed to load servers:', error);
showError('Failed to load server list');
}
}
async function toggleConnection() {
const button = document.getElementById('connectButton');
const buttonText = document.getElementById('buttonText');
button.disabled = true;
buttonText.textContent = 'Connecting...';
try {
if (!isConnected) {
const response = await invoke('connect_vpn');
console.log('Connect response:', response);
isConnected = true;
updateUI(true);
} else {
const response = await invoke('disconnect_vpn');
console.log('Disconnect response:', response);
isConnected = false;
updateUI(false);
}
} catch (error) {
console.error('Connection error:', error);
showError(error);
} finally {
button.disabled = false;
}
}
function updateUI(connected) {
const button = document.getElementById('connectButton');
const buttonText = document.getElementById('buttonText');
const statusIndicator = document.getElementById('statusIndicator');
const statsGrid = document.getElementById('statsGrid');
if (connected) {
button.classList.add('connected');
buttonText.textContent = 'Disconnect';
statusIndicator.textContent = 'Connected';
statusIndicator.classList.add('connected');
statsGrid.style.display = 'grid';
} else {
button.classList.remove('connected');
buttonText.textContent = 'Connect';
statusIndicator.textContent = 'Disconnected';
statusIndicator.classList.remove('connected');
statsGrid.style.display = 'none';
}
}
async function updateStatus() {
if (!isConnected) return;
try {
const status = await invoke('get_status');
const data = JSON.parse(status);
// Update stats
document.getElementById('uploadSpeed').textContent = formatSpeed(data.upload_speed);
document.getElementById('downloadSpeed').textContent = formatSpeed(data.download_speed);
document.getElementById('ping').textContent = `${data.ping} ms`;
} catch (error) {
console.error('Failed to update status:', error);
}
}
function formatSpeed(bytesPerSecond) {
if (bytesPerSecond < 1024) {
return `${bytesPerSecond} B/s`;
} else if (bytesPerSecond < 1024 * 1024) {
return `${(bytesPerSecond / 1024).toFixed(1)} KB/s`;
} else {
return `${(bytesPerSecond / (1024 * 1024)).toFixed(2)} MB/s`;
}
}
function showSettings() {
alert('Settings panel coming soon!');
}
function showError(message) {
// TODO: Better error UI
alert(`Error: ${message}`);
}