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
118 lines
3.5 KiB
JavaScript
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}`);
|
|
}
|