Fix delete all recordings, and panic on server startup

* Delete All Recordings did not work when recording was paused
* Because of the upgrade to axum 0.8, the webserver did not actually
  start but panic.
This commit is contained in:
Markus Unterwaditzer
2025-04-11 21:05:38 +02:00
committed by Cooper Quintin
parent 06c4dd468e
commit 151e186ef9
2 changed files with 51 additions and 16 deletions

View File

@@ -34,6 +34,25 @@ use tokio::net::TcpListener;
use tokio::sync::{RwLock, oneshot}; use tokio::sync::{RwLock, oneshot};
use std::sync::Arc; use std::sync::Arc;
type AppRouter = Router<Arc<ServerState>>;
fn get_router() -> AppRouter {
Router::new()
.route("/api/pcap/{name}", get(get_pcap))
.route("/api/qmdl/{name}", get(get_qmdl))
.route("/api/system-stats", get(get_system_stats))
.route("/api/qmdl-manifest", get(get_qmdl_manifest))
.route("/api/start-recording", post(start_recording))
.route("/api/stop-recording", post(stop_recording))
.route("/api/delete-recording/{name}", post(delete_recording))
.route("/api/delete-all-recordings", post(delete_all_recordings))
.route("/api/analysis-report/{name}", get(get_analysis_report))
.route("/api/analysis", get(get_analysis_status))
.route("/api/analysis/{name}", post(start_analysis))
.route("/", get(|| async { Redirect::permanent("/index.html") }))
.route("/{*path}", get(serve_static))
}
// Runs the axum server, taking all the elements needed to build up our // Runs the axum server, taking all the elements needed to build up our
// ServerState and a oneshot Receiver that'll fire when it's time to shutdown // ServerState and a oneshot Receiver that'll fire when it's time to shutdown
// (i.e. user hit ctrl+c) // (i.e. user hit ctrl+c)
@@ -44,21 +63,7 @@ async fn run_server(
server_shutdown_rx: oneshot::Receiver<()>, server_shutdown_rx: oneshot::Receiver<()>,
) -> JoinHandle<()> { ) -> JoinHandle<()> {
info!("spinning up server"); info!("spinning up server");
let app = Router::new() let app = get_router().with_state(state);
.route("/api/pcap/*name", get(get_pcap))
.route("/api/qmdl/*name", get(get_qmdl))
.route("/api/system-stats", get(get_system_stats))
.route("/api/qmdl-manifest", get(get_qmdl_manifest))
.route("/api/start-recording", post(start_recording))
.route("/api/stop-recording", post(stop_recording))
.route("/api/delete-recording/*name", post(delete_recording))
.route("/api/delete-all-recordings", post(delete_all_recordings))
.route("/api/analysis-report/*name", get(get_analysis_report))
.route("/api/analysis", get(get_analysis_status))
.route("/api/analysis/*name", post(start_analysis))
.route("/", get(|| async { Redirect::permanent("/index.html") }))
.route("/*path", get(serve_static))
.with_state(state);
let addr = SocketAddr::from(([0, 0, 0, 0], config.port)); let addr = SocketAddr::from(([0, 0, 0, 0], config.port));
let listener = TcpListener::bind(&addr).await.unwrap(); let listener = TcpListener::bind(&addr).await.unwrap();
task_tracker.spawn(async move { task_tracker.spawn(async move {
@@ -193,3 +198,14 @@ async fn main() -> Result<(), RayhunterError> {
info!("see you space cowboy..."); info!("see you space cowboy...");
Ok(()) Ok(())
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_get_router() {
// assert that creating the router does not panic from invalid route patterns.
let _ = get_router();
}
}

View File

@@ -300,7 +300,10 @@ impl RecordingStore {
} }
pub async fn delete_all_entries(&mut self) -> Result<(), RecordingStoreError> { pub async fn delete_all_entries(&mut self) -> Result<(), RecordingStoreError> {
if self.current_entry.is_some() {
self.close_current_entry().await?; self.close_current_entry().await?;
}
for entry in &self.manifest.entries { for entry in &self.manifest.entries {
let qmdl_filepath = entry.get_qmdl_filepath(&self.path); let qmdl_filepath = entry.get_qmdl_filepath(&self.path);
let analysis_filepath = entry.get_analysis_filepath(&self.path); let analysis_filepath = entry.get_analysis_filepath(&self.path);
@@ -396,4 +399,20 @@ mod tests {
assert_ne!(entry_index, new_entry_index); assert_ne!(entry_index, new_entry_index);
assert_eq!(store.manifest.entries.len(), 2); assert_eq!(store.manifest.entries.len(), 2);
} }
#[tokio::test]
async fn test_delete_all_entries() {
let dir = make_temp_dir();
let mut store = RecordingStore::create(dir.path()).await.unwrap();
let _ = store.new_entry().await.unwrap();
assert!(store.current_entry.is_some());
store.delete_all_entries().await.unwrap();
assert!(store.current_entry.is_none());
// regression test: deleting all entries should also work when there's no current
// recording.
store.delete_all_entries().await.unwrap();
assert!(store.current_entry.is_none());
}
} }