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.
This commit is contained in:
Benjamin Lee 2024-06-08 12:52:13 -07:00
parent f7d7952f9b
commit 4f041f9153
No known key found for this signature in database
GPG key ID: FB9624E2885D55A4
3 changed files with 36 additions and 11 deletions

View file

@ -1,5 +1,6 @@
use std::{ use std::{
borrow::Cow, borrow::Cow,
fmt::{self, Display},
net::{IpAddr, Ipv4Addr}, net::{IpAddr, Ipv4Addr},
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
@ -96,7 +97,7 @@ pub(crate) struct TlsConfig {
pub(crate) key: String, pub(crate) key: String,
} }
#[derive(Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")] #[serde(tag = "type", rename_all = "snake_case")]
pub(crate) enum ListenConfig { pub(crate) enum ListenConfig {
Tcp { 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 { fn false_fn() -> bool {
false false
} }

View file

@ -4,6 +4,8 @@ use std::{fmt, iter, path::PathBuf};
use thiserror::Error; use thiserror::Error;
use crate::config::ListenConfig;
/// Formats an [`Error`][0] and its [`source`][1]s with a separator /// Formats an [`Error`][0] and its [`source`][1]s with a separator
/// ///
/// [0]: std::error::Error /// [0]: std::error::Error
@ -108,10 +110,10 @@ pub(crate) enum Serve {
NoListeners, NoListeners,
#[error( #[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'" 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:?}")] #[error("failed to read TLS cert and key files at {certs:?} and {key:?}")]
LoadCerts { LoadCerts {
@ -121,6 +123,6 @@ pub(crate) enum Serve {
err: std::io::Error, err: std::io::Error,
}, },
#[error("failed to run request listener")] #[error("failed to run request listener on {1}")]
Listen(#[source] std::io::Error), Listen(#[source] std::io::Error, ListenConfig),
} }

View file

@ -132,6 +132,7 @@ async fn try_main() -> Result<(), error::Main> {
Ok(()) Ok(())
} }
#[allow(clippy::too_many_lines)]
async fn run_server() -> Result<(), error::Serve> { async fn run_server() -> Result<(), error::Serve> {
use error::Serve as Error; use error::Serve as Error;
@ -204,6 +205,7 @@ async fn run_server() -> Result<(), error::Serve> {
} }
for listen in &config.listen { for listen in &config.listen {
info!("Listening for incoming traffic on {listen}");
match listen { match listen {
ListenConfig::Tcp { ListenConfig::Tcp {
address, address,
@ -214,8 +216,9 @@ async fn run_server() -> Result<(), error::Serve> {
let handle = ServerHandle::new(); let handle = ServerHandle::new();
handles.push(handle.clone()); handles.push(handle.clone());
let server = if *tls { let server = if *tls {
let tls_config = let tls_config = tls_config
tls_config.clone().ok_or(Error::NoTlsCerts)?; .clone()
.ok_or_else(|| Error::NoTlsCerts(listen.clone()))?;
bind_rustls(addr, tls_config) bind_rustls(addr, tls_config)
.handle(handle) .handle(handle)
.serve(app.clone()) .serve(app.clone())
@ -223,7 +226,9 @@ async fn run_server() -> Result<(), error::Serve> {
} else { } else {
bind(addr).handle(handle).serve(app.clone()).right_future() 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)); tokio::spawn(shutdown_signal(handles));
while let Some(result) = servers.join_next().await { while let Some(result) = servers.join_next().await {
result let (listen, result) =
.expect("should be able to join server task") result.expect("should be able to join server task");
.map_err(Error::Listen)?; result.map_err(|err| Error::Listen(err, listen))?;
} }
Ok(()) Ok(())