diff --git a/daemon/src/main.rs b/daemon/src/main.rs index 8ebb37c..429797a 100644 --- a/daemon/src/main.rs +++ b/daemon/src/main.rs @@ -25,7 +25,7 @@ use crate::server::{ ServerState, debug_set_display_state, get_config, get_qmdl, get_zip, serve_static, set_config, test_notification, }; -use crate::stats::{get_qmdl_manifest, get_system_stats}; +use crate::stats::{get_qmdl_manifest, get_route_status, get_system_stats}; use analysis::{ AnalysisCtrlMessage, AnalysisStatus, get_analysis_status, run_analysis_thread, start_analysis, @@ -58,6 +58,7 @@ fn get_router() -> AppRouter { .route("/api/qmdl/{name}", get(get_qmdl)) .route("/api/zip/{name}", get(get_zip)) .route("/api/system-stats", get(get_system_stats)) + .route("/api/route-status", get(get_route_status)) .route("/api/qmdl-manifest", get(get_qmdl_manifest)) .route("/api/log", get(get_log)) .route("/api/start-recording", post(start_recording)) diff --git a/daemon/src/stats.rs b/daemon/src/stats.rs index 5f5842c..fd63a02 100644 --- a/daemon/src/stats.rs +++ b/daemon/src/stats.rs @@ -174,3 +174,25 @@ pub async fn get_log() -> Result { .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string())) } + +#[derive(Debug, Serialize)] +pub struct RouteStatus { + pub has_default_route: bool, +} + +pub async fn get_route_status() -> Json { + let mut cmd = Command::new("busybox"); + cmd.args(["ip", "route"]); + + let has_default_route = match get_cmd_output(cmd).await { + Ok(output) => output.lines().any(|line| line.starts_with("default ")), + Err(err) => { + log::warn!("Failed to check default route: {err}"); + // More likely than not, this is a portability issue. The logic hasn't been fully + // tested on all devices. We shouldn't scare users unnecessarily. + true + } + }; + + Json(RouteStatus { has_default_route }) +} diff --git a/daemon/web/src/lib/components/ActionErrors.svelte b/daemon/web/src/lib/components/ActionErrors.svelte index 1c0994d..47a5d6f 100644 --- a/daemon/web/src/lib/components/ActionErrors.svelte +++ b/daemon/web/src/lib/components/ActionErrors.svelte @@ -1,5 +1,6 @@ + +{#if show_alert} +
+ + + No Default Route Detected + +

+ This device didn't get an IP address from the network operator. Presumably the SIM card + is not inserted or very old. Try a different SIM card. +

+
+ +
+
+{/if} diff --git a/daemon/web/src/lib/components/WarningIcon.svelte b/daemon/web/src/lib/components/WarningIcon.svelte new file mode 100644 index 0000000..29d60f0 --- /dev/null +++ b/daemon/web/src/lib/components/WarningIcon.svelte @@ -0,0 +1,19 @@ + + + diff --git a/daemon/web/src/lib/utils.svelte.ts b/daemon/web/src/lib/utils.svelte.ts index 36cac1a..e4488f7 100644 --- a/daemon/web/src/lib/utils.svelte.ts +++ b/daemon/web/src/lib/utils.svelte.ts @@ -97,3 +97,11 @@ export async function test_notification(): Promise { throw new Error(error); } } + +export interface RouteStatus { + has_default_route: boolean; +} + +export async function get_route_status(): Promise { + return JSON.parse(await req('GET', '/api/route-status')); +} diff --git a/daemon/web/src/routes/+page.svelte b/daemon/web/src/routes/+page.svelte index 06d6b06..afea145 100644 --- a/daemon/web/src/routes/+page.svelte +++ b/daemon/web/src/routes/+page.svelte @@ -10,7 +10,9 @@ import RecordingControls from '$lib/components/RecordingControls.svelte'; import ConfigForm from '$lib/components/ConfigForm.svelte'; import ActionErrors from '$lib/components/ActionErrors.svelte'; + import IPRouteAlert from '$lib/components/IPRouteAlert.svelte'; import LogView from '$lib/components/LogView.svelte'; + import WarningIcon from '$lib/components/WarningIcon.svelte'; let manager: AnalysisManager = new AnalysisManager(); let loaded = $state(false); @@ -156,21 +158,7 @@ class="bg-red-100 border-red-100 drop-shadow p-4 flex flex-col gap-2 border rounded-md flex-1 justify-between" > - + Connection Error {/if} + {#if loaded}
{#if current_entry} @@ -202,21 +191,7 @@ - + WARNING: Not Running diff --git a/daemon/web/vite.config.ts b/daemon/web/vite.config.ts index 9720c43..c10a3cf 100644 --- a/daemon/web/vite.config.ts +++ b/daemon/web/vite.config.ts @@ -5,7 +5,7 @@ export default defineConfig({ server: { proxy: { '/api': { - target: 'http://localhost:8080', + target: process.env.API_TARGET || 'http://localhost:8080', changeOrigin: true, secure: false, configure: (proxy, _options) => {