diff options
author | Himbeer <himbeer@disroot.org> | 2024-08-04 23:28:02 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-08-04 23:28:02 +0200 |
commit | 51ca2c8568fa4a239950d0f547f1c6eb49146e0d (patch) | |
tree | cade4d6caae8022936f41198dad808a429c04cb4 | |
parent | 5ae59dedf142b625d8ba19ebbbd23f1645c312f3 (diff) |
Add WAN connection information
-rw-r--r-- | src-tauri/src/main.rs | 157 | ||||
-rw-r--r-- | src/wan.html | 6 | ||||
-rw-r--r-- | src/wan.js | 20 |
3 files changed, 182 insertions, 1 deletions
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 64992e0..77b3a8f 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,6 +1,7 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +use std::net::{Ipv4Addr, Ipv6Addr}; use std::sync::Mutex; use tauri::State; @@ -34,6 +35,75 @@ struct WanCredentialFile { password: String, } +#[derive(Debug, Serialize)] +struct ConnectionStatus { + session: String, + ipv4: String, + ipv6: String, +} + +#[derive(Debug, Default, Deserialize)] +struct ConnectionFile { + v4: Option<Ipv4Connection>, + v6: Option<Ipv6Connection>, +} + +impl ConnectionFile { + fn session_summary(&self) -> String { + if self.v4.is_some() && self.v6.is_some() { + String::from("Einwahlstatus: ✅ Dual Stack") + } else if self.v6.is_some() { + String::from( + r#"Einwahlstatus: ✅ IPv6 | ggf. DS-Lite-Status unter "DHCPv6" überprüfen"#, + ) + } else if self.v4.is_some() { + String::from( + r#"Einwahlstatus: ⚠ IPv4 | Eigene Server nicht von außen erreichbar, kleine Teile des modernen Internets nicht erreichbar. Internetanbieter um Freischaltung von IPv6 (bevorzugt "Dual Stack" bzw. mit öffentlicher IPv4-Adresse <i>und</i> IPv6, aber nicht zwingend nötig) bitten."#, + ) + } else { + String::from("Einwahlstatus: ❌ Keine Einwahl | Router und Modem neu starten. Bei weiterem Bestehen Diagnoseprotokolle konsultieren oder Internetanbieter kontaktieren.") + } + } + + fn ipv4_summary(&self) -> String { + if let Some(v4) = &self.v4 { + format!("IPv4: 🟢 Verbunden | Öffentliche Adresse: {}/32 | Primärer DNS-Server (nicht verwendet): {} | Sekundärer DNS-Server (nicht verwendet): {}",v4.addr,v4.dns1,v4.dns2) + } else if self.v6.is_some() { + String::from( + r#"IPv4: 🟡 Nicht verfügbar (ggf. DS-Lite-Status unter "DHCPv6" überprüfen)"#, + ) + } else { + String::from("IPv4: 🔴 Nicht verbunden") + } + } + + fn ipv6_summary(&self) -> String { + if let Some(v6) = &self.v6 { + format!( + "IPv6: 🟢 Verbunden | Verbindungslokale Adresse: {}/128 | Standardgateway: {}", + v6.laddr, v6.raddr + ) + } else if self.v4.is_some() { + String::from("IPv6: 🟡 Nicht verfügbar | Bitte freischalten lassen (s. oben)") + } else { + String::from("IPv6: 🔴 Nicht verbunden") + } + } +} + +#[derive(Debug, Deserialize)] +struct Ipv4Connection { + addr: Ipv4Addr, + dns1: Ipv4Addr, + dns2: Ipv4Addr, +} + +#[derive(Debug, Deserialize)] +struct Ipv6Connection { + laddr: Ipv6Addr, + raddr: Ipv6Addr, +} + // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command #[tauri::command] async fn connect( @@ -267,6 +337,90 @@ fn handle_kill_response(response: Response) -> String { } } +#[tauri::command] +async fn connection_status(state: State<'_, Mutex<Session>>) -> Result<ConnectionStatus, ()> { + let (client, instance) = { + let state = state.lock().unwrap(); + (state.client.clone(), state.instance.clone()) + }; + let instance = match instance { + Some(instance) => instance, + None => { + return Ok(ConnectionStatus { + session: String::from("❗ Keine Instanz ausgewählt, bitte melden Sie sich neu an!"), + ipv4: String::from("❗ Keine Instanz ausgewählt, bitte melden Sie sich neu an!"), + ipv6: String::from("❗ Keine Instanz ausgewählt, bitte melden Sie sich neu an!"), + }) + } + }; + + let response = client + .get(instance.url.join("/data/read").unwrap()) + .query(&[("path", "/tmp/pppoe.ip_config")]) + .basic_auth("rustkrazy", Some(&instance.password)) + .send(); + + Ok(match response.await { + Ok(response) => handle_connection_status_response(response).await, + Err(e) => ConnectionStatus { + session: format!("❗ Abfrage fehlgeschlagen: {}", e), + ipv4: format!("❗ Abfrage fehlgeschlagen: {}", e), + ipv6: format!("❗ Abfrage fehlgeschlagen: {}", e), + }, + }) +} + +async fn handle_connection_status_response(response: Response) -> ConnectionStatus { + let status = response.status(); + if status.is_success() { + match response.json::<ConnectionFile>().await { + Ok(connection) => ConnectionStatus { + session: connection.session_summary(), + ipv4: connection.ipv4_summary(), + ipv6: connection.ipv6_summary(), + }, + Err(e) => ConnectionStatus { + session: format!("❗ Fehlerhafte Parameterdatei. Fehler: {}", e), + ipv4: format!("❗ Fehlerhafte Parameterdatei. Fehler: {}", e), + ipv6: format!("❗ Fehlerhafte Parameterdatei. Fehler: {}", e), + }, + } + } else if status == StatusCode::UNAUTHORIZED { + ConnectionStatus { + session: String::from( + "❗ Ungültiges Verwaltungspasswort, bitte melden Sie sich neu an!", + ), + ipv4: String::from("❗ Ungültiges Verwaltungspasswort, bitte melden Sie sich neu an!"), + ipv6: String::from("❗ Ungültiges Verwaltungspasswort, bitte melden Sie sich neu an!"), + } + } else if status == StatusCode::NOT_FOUND { + let connection = ConnectionFile::default(); + ConnectionStatus { + session: connection.session_summary(), + ipv4: connection.ipv4_summary(), + ipv6: connection.ipv6_summary(), + } + } else if status.is_client_error() { + ConnectionStatus { + session: format!("❗ Clientseitiger Fehler: {}", status), + ipv4: format!("❗ Clientseitiger Fehler: {}", status), + ipv6: format!("❗ Clientseitiger Fehler: {}", status), + } + } else if status.is_server_error() { + ConnectionStatus { + session: format!("❗ Serverseitiger Fehler: {}", status), + ipv4: format!("❗ Serverseitiger Fehler: {}", status), + ipv6: format!("❗ Serverseitiger Fehler: {}", status), + } + } else { + ConnectionStatus { + session: format!("❗ Unerwarteter Statuscode: {}", status), + ipv4: format!("❗ Unerwarteter Statuscode: {}", status), + ipv6: format!("❗ Unerwarteter Statuscode: {}", status), + } + } +} + fn main() { tauri::Builder::default() .manage(Mutex::new(Session { @@ -281,7 +435,8 @@ fn main() { disconnect, load_wan_credentials, change_wan_credentials, - kill + kill, + connection_status ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/wan.html b/src/wan.html index f52193e..b8b533b 100644 --- a/src/wan.html +++ b/src/wan.html @@ -49,6 +49,12 @@ <fieldset> <legend>Einwahl</legend> + <span class="row" id="connection-status">Einwahlstatus: ❓ Abfrage...</span> + <span class="row" id="connection-ipv4">IPv4: ❓ Abfrage...</span> + <span class="row" id="connection-ipv6">IPv6: ❓ Abfrage...</span> + + <br /> + <div class="row"> <button id="connection-warm-reconnect">🔄 Verbindungsparameter neu synchronisieren</button> <button id="connection-cold-reconnect">☎ Neu einwählen</button> @@ -1,11 +1,23 @@ const { invoke } = window.__TAURI__.tauri; const { ask, message } = window.__TAURI__.dialog; +let connectionStatusEl; +let connectionIpv4El; +let connectionIpv6El; + let credentialsUsernameEl; let credentialsPasswordEl; let credentialsSubmitEl; let credentialsStatusEl; +async function refreshConnectionStatus() { + const connectionStatus = await invoke("connection_status", {}); + + connectionStatusEl.innerText = connectionStatus.session; + connectionIpv4El.innerText = connectionStatus.ipv4; + connectionIpv6El.innerText = connectionStatus.ipv6; +} + async function warmReconnect() { const error = await invoke("kill", { process: "rsdsl_pppoe3", signal: "hup" }); @@ -93,6 +105,12 @@ async function changeCredentials() { } window.addEventListener("DOMContentLoaded", () => { + refreshConnectionStatus(); + + connectionStatusEl = document.querySelector("#connection-status"); + connectionIpv4El = document.querySelector("#connection-ipv4"); + connectionIpv6El = document.querySelector("#connection-ipv6"); + document.querySelector("#connection-warm-reconnect").addEventListener("click", (e) => { e.preventDefault(); warmReconnect(); @@ -123,3 +141,5 @@ window.addEventListener("DOMContentLoaded", () => { loadCredentials(); }); + +setInterval(refreshConnectionStatus, 3000); |