Restart when config is set

This commit is contained in:
Markus Unterwaditzer
2025-06-24 01:11:50 +02:00
parent be6f29dcf1
commit a21c9af354
5 changed files with 36 additions and 82 deletions

View File

@@ -4,7 +4,7 @@ use rayhunter::analysis::analyzer::AnalyzerConfig;
use crate::error::RayhunterError;
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(default)]
pub struct Config {
pub qmdl_store_path: String,

View File

@@ -19,7 +19,7 @@ use crate::diag::run_diag_read_thread;
use crate::error::RayhunterError;
use crate::pcap::get_pcap;
use crate::qmdl_store::RecordingStore;
use crate::server::{get_config, get_qmdl, restart_daemon, serve_static, set_config, ServerState};
use crate::server::{get_config, get_qmdl, serve_static, set_config, ServerState};
use crate::stats::{get_qmdl_manifest, get_system_stats};
use analysis::{
@@ -57,7 +57,6 @@ fn get_router() -> AppRouter {
.route("/api/analysis-report/{name}", get(get_analysis_report))
.route("/api/analysis", get(get_analysis_status))
.route("/api/analysis/{name}", post(start_analysis))
.route("/api/restart-daemon", post(restart_daemon))
.route("/api/config", get(get_config))
.route("/api/config", post(set_config))
.route("/", get(|| async { Redirect::permanent("/index.html") }))
@@ -69,14 +68,14 @@ fn get_router() -> AppRouter {
// (i.e. user hit ctrl+c)
async fn run_server(
task_tracker: &TaskTracker,
config: &config::Config,
state: Arc<ServerState>,
server_shutdown_rx: oneshot::Receiver<()>,
) -> JoinHandle<()> {
info!("spinning up server");
let app = get_router().with_state(state);
let addr = SocketAddr::from(([0, 0, 0, 0], config.port));
let addr = SocketAddr::from(([0, 0, 0, 0], state.config.port));
let listener = TcpListener::bind(&addr).await.unwrap();
let app = get_router().with_state(state);
task_tracker.spawn(async move {
info!("The orca is hunting for stingrays...");
axum::serve(listener, app)
@@ -189,7 +188,7 @@ async fn main() -> Result<(), RayhunterError> {
loop {
let config = parse_config(&args.config_path).await?;
if !run_with_config(&args, &config).await? {
if !run_with_config(&args, config).await? {
return Ok(());
}
}
@@ -197,7 +196,7 @@ async fn main() -> Result<(), RayhunterError> {
async fn run_with_config(
args: &config::Args,
config: &config::Config,
config: config::Config,
) -> Result<bool, RayhunterError> {
// TaskTrackers give us an interface to spawn tokio threads, and then
// eventually await all of them ending
@@ -273,15 +272,15 @@ async fn run_with_config(
);
let state = Arc::new(ServerState {
config_path: args.config_path.clone(),
config,
qmdl_store_lock: qmdl_store_lock.clone(),
diag_device_ctrl_sender: diag_tx,
ui_update_sender: ui_update_tx,
debug_mode: config.debug_mode,
analysis_status_lock,
analysis_sender: analysis_tx,
daemon_restart_tx: Arc::new(RwLock::new(Some(daemon_restart_tx))),
});
run_server(&task_tracker, &config, state, server_shutdown_rx).await;
run_server(&task_tracker, state, server_shutdown_rx).await;
task_tracker.close();
task_tracker.wait().await;

View File

@@ -158,7 +158,7 @@ pub fn run_diag_read_thread(
pub async fn start_recording(
State(state): State<Arc<ServerState>>,
) -> Result<(StatusCode, String), (StatusCode, String)> {
if state.debug_mode {
if state.config.debug_mode {
return Err((StatusCode::FORBIDDEN, "server is in debug mode".to_string()));
}
@@ -179,7 +179,7 @@ pub async fn start_recording(
pub async fn stop_recording(
State(state): State<Arc<ServerState>>,
) -> Result<(StatusCode, String), (StatusCode, String)> {
if state.debug_mode {
if state.config.debug_mode {
return Err((StatusCode::FORBIDDEN, "server is in debug mode".to_string()));
}
state
@@ -199,7 +199,7 @@ pub async fn delete_recording(
State(state): State<Arc<ServerState>>,
Path(qmdl_name): Path<String>,
) -> Result<(StatusCode, String), (StatusCode, String)> {
if state.debug_mode {
if state.config.debug_mode {
return Err((StatusCode::FORBIDDEN, "server is in debug mode".to_string()));
}
let mut qmdl_store = state.qmdl_store_lock.write().await;
@@ -244,7 +244,7 @@ pub async fn delete_recording(
pub async fn delete_all_recordings(
State(state): State<Arc<ServerState>>,
) -> Result<(StatusCode, String), (StatusCode, String)> {
if state.debug_mode {
if state.config.debug_mode {
return Err((StatusCode::FORBIDDEN, "server is in debug mode".to_string()));
}
state

View File

@@ -14,19 +14,18 @@ use tokio::sync::{oneshot, RwLock};
use tokio_util::io::ReaderStream;
use crate::analysis::{AnalysisCtrlMessage, AnalysisStatus};
use crate::config::parse_config;
use crate::config::Config;
use crate::qmdl_store::RecordingStore;
use crate::{display, DiagDeviceCtrlMessage};
pub struct ServerState {
pub config_path: String,
pub config: Config,
pub qmdl_store_lock: Arc<RwLock<RecordingStore>>,
pub diag_device_ctrl_sender: Sender<DiagDeviceCtrlMessage>,
pub ui_update_sender: Sender<display::DisplayState>,
pub analysis_status_lock: Arc<RwLock<AnalysisStatus>>,
pub analysis_sender: Sender<AnalysisCtrlMessage>,
pub debug_mode: bool,
pub daemon_restart_tx: Arc<RwLock<Option<oneshot::Sender<()>>>>,
}
@@ -86,38 +85,10 @@ pub async fn serve_static(
}
}
pub async fn restart_daemon(
State(state): State<Arc<ServerState>>,
) -> Result<(StatusCode, String), (StatusCode, String)> {
let mut restart_tx = state.daemon_restart_tx.write().await;
if let Some(sender) = restart_tx.take() {
sender.send(()).map_err(|_| {
(
StatusCode::INTERNAL_SERVER_ERROR,
"couldn't send restart signal".to_string(),
)
})?;
Ok((StatusCode::ACCEPTED, "restart signal sent".to_string()))
} else {
Ok((
StatusCode::ACCEPTED,
"restart already triggered".to_string(),
))
}
}
pub async fn get_config(
State(state): State<Arc<ServerState>>,
) -> Result<Json<Config>, (StatusCode, String)> {
let config = parse_config(&state.config_path).await.map_err(|err| {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("failed to read config file: {}", err),
)
})?;
Ok(Json(config))
Ok(Json(state.config.clone()))
}
pub async fn set_config(
@@ -138,5 +109,23 @@ pub async fn set_config(
)
})?;
Ok((StatusCode::ACCEPTED, "wrote config".to_string()))
// Trigger daemon restart after writing config
let mut restart_tx = state.daemon_restart_tx.write().await;
if let Some(sender) = restart_tx.take() {
sender.send(()).map_err(|_| {
(
StatusCode::INTERNAL_SERVER_ERROR,
"couldn't send restart signal".to_string(),
)
})?;
Ok((
StatusCode::ACCEPTED,
"wrote config and triggered restart".to_string(),
))
} else {
Ok((
StatusCode::ACCEPTED,
"wrote config but restart already triggered".to_string(),
))
}
}