From f6bc2e12830fc588da6afd2e2015bb276a363f45 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Tue, 30 Jul 2024 11:37:47 +0100 Subject: [PATCH] feat: terminate process if config file is invalid --- crates/cli/src/file_watcher.rs | 10 +++++----- crates/cli/src/server/actor/handlers/file_updated.rs | 10 +++------- .../src/server/actor/handlers/receive_server_config.rs | 9 +++------ crates/cli/src/server/actor/mod.rs | 7 +++++++ .../src/server/actor/tests/receive_server_config.rs | 2 +- crates/cli/src/server/mod.rs | 5 ++++- 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/crates/cli/src/file_watcher.rs b/crates/cli/src/file_watcher.rs index ca0156a..c6bfc3d 100644 --- a/crates/cli/src/file_watcher.rs +++ b/crates/cli/src/file_watcher.rs @@ -2,6 +2,7 @@ use actix::prelude::*; use actix::Recipient; +use anyhow::{Context, Result}; use notify::event::ModifyKind; use notify::Watcher; use tracing::error; @@ -19,15 +20,13 @@ pub enum Error { #[error("io")] Io(#[from] std::io::Error), } -pub async fn watch_file(path: PathBuf, recipient: Recipient) { +pub async fn watch_file(path: PathBuf, recipient: Recipient) -> Result<()> { let (tx, rx) = std::sync::mpsc::channel(); - #[allow(clippy::expect_used)] - let mut handler = notify::recommended_watcher(tx).expect("file watcher"); - #[allow(clippy::expect_used)] + let mut handler = notify::recommended_watcher(tx).context("file watcher")?; handler .watch(&path, notify::RecursiveMode::NonRecursive) - .expect("watch file"); + .with_context(|| format!("Watch file: {path:?}"))?; info!("Watching: {:?}", path); async move { loop { @@ -55,4 +54,5 @@ pub async fn watch_file(path: PathBuf, recipient: Recipient) { } } .await; + Ok(()) } diff --git a/crates/cli/src/server/actor/handlers/file_updated.rs b/crates/cli/src/server/actor/handlers/file_updated.rs index 7aa6d49..d5c2af8 100644 --- a/crates/cli/src/server/actor/handlers/file_updated.rs +++ b/crates/cli/src/server/actor/handlers/file_updated.rs @@ -12,13 +12,9 @@ impl Handler for ServerActor { type Result = (); fn handle(&mut self, _msg: FileUpdated, ctx: &mut Self::Context) -> Self::Result { - let server_config = match ServerConfig::load(&self.fs) { - Ok(server_config) => server_config, - Err(err) => { - tracing::error!("Failed to load config file. Error: {}", err); - return; - } + match ServerConfig::load(&self.fs) { + Ok(server_config) => self.do_send(ReceiveServerConfig::new(server_config), ctx), + Err(err) => self.abort(ctx, format!("Failed to load config file. Error: {}", err)), }; - self.do_send(ReceiveServerConfig::new(server_config), ctx); } } diff --git a/crates/cli/src/server/actor/handlers/receive_server_config.rs b/crates/cli/src/server/actor/handlers/receive_server_config.rs index 889f5ed..bddf8ac 100644 --- a/crates/cli/src/server/actor/handlers/receive_server_config.rs +++ b/crates/cli/src/server/actor/handlers/receive_server_config.rs @@ -12,18 +12,15 @@ impl Handler for ServerActor { fn handle(&mut self, msg: ReceiveServerConfig, ctx: &mut Self::Context) -> Self::Result { tracing::info!("recieved server config"); let Ok(socket_addr) = msg.http() else { - tracing::error!("Unable to parse http.addr"); - return; + return self.abort(ctx, "Unable to parse http.addr"); }; let Some(server_storage) = self.server_storage(&msg) else { - tracing::error!("Server storage not available"); - return; + return self.abort(ctx, "Server storage not available"); }; if msg.inbound_webhook().base_url().ends_with('/') { - tracing::error!("webhook.url must not end with a '/'"); - return; + return self.abort(ctx, "webhook.url must not end with a '/'"); } self.do_send( diff --git a/crates/cli/src/server/actor/mod.rs b/crates/cli/src/server/actor/mod.rs index dd4e717..fca7587 100644 --- a/crates/cli/src/server/actor/mod.rs +++ b/crates/cli/src/server/actor/mod.rs @@ -229,6 +229,13 @@ impl ServerActor { Some(server_storage) } + /// Attempts to gracefully shutdown the server before stopping the system. + fn abort(&mut self, ctx: &mut ::Context, message: impl Into) { + tracing::error!("Aborting: {}", message.into()); + self.do_send(crate::server::actor::messages::Shutdown, ctx); + System::current().stop_with_code(1); + } + fn do_send(&mut self, msg: M, _ctx: &mut ::Context) where M: actix::Message + Send + 'static + std::fmt::Debug, diff --git a/crates/cli/src/server/actor/tests/receive_server_config.rs b/crates/cli/src/server/actor/tests/receive_server_config.rs index 4225e94..b82436e 100644 --- a/crates/cli/src/server/actor/tests/receive_server_config.rs +++ b/crates/cli/src/server/actor/tests/receive_server_config.rs @@ -52,5 +52,5 @@ async fn when_webhook_url_has_trailing_slash_should_not_send() { tracing::debug!(?message_log, ""); assert!(message_log.read().iter().any(|log| !log .iter() - .any(|line| line != "send: ReceiveValidServerConfig"))); + .any(|line| line == "send: ReceiveValidServerConfig"))); } diff --git a/crates/cli/src/server/mod.rs b/crates/cli/src/server/mod.rs index 2ec68d4..f2b9673 100644 --- a/crates/cli/src/server/mod.rs +++ b/crates/cli/src/server/mod.rs @@ -46,7 +46,10 @@ pub fn start( server.do_send(FileUpdated); info!("Starting File Watcher..."); - watch_file("git-next-server.toml".into(), server.clone().recipient()).await; + #[allow(clippy::expect_used)] + watch_file("git-next-server.toml".into(), server.clone().recipient()) + .await + .expect("file watcher"); info!("Server running - Press Ctrl-C to stop..."); let _ = actix_rt::signal::ctrl_c().await;