From 4f041f91533c23f889b70aef39410a7c7bb612c0 Mon Sep 17 00:00:00 2001 From: Benjamin Lee Date: Sat, 8 Jun 2024 12:52:13 -0700 Subject: [PATCH] specify listener in error messages and logs The "listening for incoming traffic on ..." log line is new, but something I've wanted even when we only supported one listener. I considered getting rid of `clippy::too_many_lines` by factoring out the construction of `app` to a separate function, but found that specifying it's type (or relevant traits) got quite hairy. --- src/config.rs | 20 +++++++++++++++++++- src/error.rs | 10 ++++++---- src/main.rs | 17 +++++++++++------ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/config.rs b/src/config.rs index bf5de8f9..af01282a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,6 @@ use std::{ borrow::Cow, + fmt::{self, Display}, net::{IpAddr, Ipv4Addr}, path::{Path, PathBuf}, }; @@ -96,7 +97,7 @@ pub(crate) struct TlsConfig { pub(crate) key: String, } -#[derive(Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] pub(crate) enum ListenConfig { Tcp { @@ -109,6 +110,23 @@ pub(crate) enum ListenConfig { }, } +impl Display for ListenConfig { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ListenConfig::Tcp { + address, + port, + tls: false, + } => write!(f, "http://{address}:{port}"), + ListenConfig::Tcp { + address, + port, + tls: true, + } => write!(f, "https://{address}:{port}"), + } + } +} + fn false_fn() -> bool { false } diff --git a/src/error.rs b/src/error.rs index c63f743b..70f0124e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,6 +4,8 @@ use std::{fmt, iter, path::PathBuf}; use thiserror::Error; +use crate::config::ListenConfig; + /// Formats an [`Error`][0] and its [`source`][1]s with a separator /// /// [0]: std::error::Error @@ -108,10 +110,10 @@ pub(crate) enum Serve { NoListeners, #[error( - "listener requested TLS, but no TLS cert was specified in the \ + "listener {0} requested TLS, but no TLS cert was specified in the \ configuration file. Please set 'tls.certs' and 'tls.key'" )] - NoTlsCerts, + NoTlsCerts(ListenConfig), #[error("failed to read TLS cert and key files at {certs:?} and {key:?}")] LoadCerts { @@ -121,6 +123,6 @@ pub(crate) enum Serve { err: std::io::Error, }, - #[error("failed to run request listener")] - Listen(#[source] std::io::Error), + #[error("failed to run request listener on {1}")] + Listen(#[source] std::io::Error, ListenConfig), } diff --git a/src/main.rs b/src/main.rs index 9f732360..33bbed81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -132,6 +132,7 @@ async fn try_main() -> Result<(), error::Main> { Ok(()) } +#[allow(clippy::too_many_lines)] async fn run_server() -> Result<(), error::Serve> { use error::Serve as Error; @@ -204,6 +205,7 @@ async fn run_server() -> Result<(), error::Serve> { } for listen in &config.listen { + info!("Listening for incoming traffic on {listen}"); match listen { ListenConfig::Tcp { address, @@ -214,8 +216,9 @@ async fn run_server() -> Result<(), error::Serve> { let handle = ServerHandle::new(); handles.push(handle.clone()); let server = if *tls { - let tls_config = - tls_config.clone().ok_or(Error::NoTlsCerts)?; + let tls_config = tls_config + .clone() + .ok_or_else(|| Error::NoTlsCerts(listen.clone()))?; bind_rustls(addr, tls_config) .handle(handle) .serve(app.clone()) @@ -223,7 +226,9 @@ async fn run_server() -> Result<(), error::Serve> { } else { bind(addr).handle(handle).serve(app.clone()).right_future() }; - servers.spawn(server); + servers.spawn( + server.then(|result| async { (listen.clone(), result) }), + ); } } } @@ -235,9 +240,9 @@ async fn run_server() -> Result<(), error::Serve> { tokio::spawn(shutdown_signal(handles)); while let Some(result) = servers.join_next().await { - result - .expect("should be able to join server task") - .map_err(Error::Listen)?; + let (listen, result) = + result.expect("should be able to join server task"); + result.map_err(|err| Error::Listen(err, listen))?; } Ok(())