feat: add periodic tray menu refresh and normalize tunnel metrics field names
Add background task to refresh tray menu every 5 seconds to keep status display current. Add RawTunnelMetrics type and normalizeTunnelMetrics helper to handle both snake_case and camelCase field names from backend responses. Update refreshTunnelMetrics to normalize metrics before setting state and explicitly cast active status to boolean.
This commit is contained in:
@@ -665,6 +665,14 @@ pub fn run() {
|
|||||||
});
|
});
|
||||||
refresh_tray_menu(app.handle());
|
refresh_tray_menu(app.handle());
|
||||||
|
|
||||||
|
let app_handle = app.handle().clone();
|
||||||
|
tauri::async_runtime::spawn(async move {
|
||||||
|
loop {
|
||||||
|
refresh_tray_menu(&app_handle);
|
||||||
|
tauri::async_runtime::sleep(std::time::Duration::from_secs(5)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.on_window_event(|window, event| match event {
|
.on_window_event(|window, event| match event {
|
||||||
|
|||||||
@@ -17,6 +17,14 @@ type TunnelMetrics = {
|
|||||||
txBytes: number;
|
txBytes: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type RawTunnelMetrics = {
|
||||||
|
active?: boolean;
|
||||||
|
rxBytes?: number;
|
||||||
|
txBytes?: number;
|
||||||
|
rx_bytes?: number;
|
||||||
|
tx_bytes?: number;
|
||||||
|
};
|
||||||
|
|
||||||
function formatInvokeError(err: unknown, fallback: string) {
|
function formatInvokeError(err: unknown, fallback: string) {
|
||||||
if (typeof err === "string" && err.trim().length > 0) {
|
if (typeof err === "string" && err.trim().length > 0) {
|
||||||
return err;
|
return err;
|
||||||
@@ -67,6 +75,14 @@ function formatDataSize(bytes: number) {
|
|||||||
return `${value >= 100 || unitIndex === 0 ? value.toFixed(0) : value.toFixed(1)} ${units[unitIndex]}`;
|
return `${value >= 100 || unitIndex === 0 ? value.toFixed(0) : value.toFixed(1)} ${units[unitIndex]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeTunnelMetrics(value: RawTunnelMetrics | null | undefined): TunnelMetrics {
|
||||||
|
return {
|
||||||
|
active: Boolean(value?.active),
|
||||||
|
rxBytes: Number(value?.rxBytes ?? value?.rx_bytes ?? 0),
|
||||||
|
txBytes: Number(value?.txBytes ?? value?.tx_bytes ?? 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
const [serverUrl, setServerUrl] = useState("http://localhost");
|
const [serverUrl, setServerUrl] = useState("http://localhost");
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
@@ -84,14 +100,14 @@ export function App() {
|
|||||||
|
|
||||||
async function refreshTunnelMetrics() {
|
async function refreshTunnelMetrics() {
|
||||||
try {
|
try {
|
||||||
const value = await invoke<TunnelMetrics>("tunnel_metrics");
|
const value = normalizeTunnelMetrics(await invoke<RawTunnelMetrics>("tunnel_metrics"));
|
||||||
setMetrics(value);
|
setMetrics(value);
|
||||||
setConnected(value.active);
|
setConnected(value.active);
|
||||||
} catch {
|
} catch {
|
||||||
try {
|
try {
|
||||||
const active = await invoke<boolean>("tunnel_status");
|
const active = await invoke<boolean>("tunnel_status");
|
||||||
setConnected(active);
|
setConnected(active);
|
||||||
setMetrics((current) => ({ ...current, active }));
|
setMetrics((current) => ({ ...current, active: Boolean(active) }));
|
||||||
} catch {
|
} catch {
|
||||||
setMetrics({ active: false, rxBytes: 0, txBytes: 0 });
|
setMetrics({ active: false, rxBytes: 0, txBytes: 0 });
|
||||||
setConnected(false);
|
setConnected(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user