diff --git a/Cargo.lock b/Cargo.lock index ae43417e..9e28534c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5047,6 +5047,7 @@ dependencies = [ "capnpc", "cfg-if 1.0.0", "clap 3.2.8", + "color-eyre", "config", "ctrlc", "daemonize", diff --git a/Cargo.toml b/Cargo.toml index 733f27c0..3ca2a512 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,3 +30,6 @@ rtnetlink = { path = "./external/netlink/rtnetlink" } [profile.release] opt-level = "s" lto = true + +[profile.dev.package.backtrace] +opt-level = 3 \ No newline at end of file diff --git a/veilid-core/src/attachment_manager.rs b/veilid-core/src/attachment_manager.rs index cc142732..48576901 100644 --- a/veilid-core/src/attachment_manager.rs +++ b/veilid-core/src/attachment_manager.rs @@ -222,26 +222,29 @@ impl AttachmentManager { #[instrument(level = "debug", skip(self))] async fn attachment_maintainer(self) { - trace!("attachment starting"); + debug!("attachment starting"); let netman = { let mut inner = self.inner.lock(); inner.attach_timestamp = Some(intf::get_timestamp()); inner.network_manager.clone() }; - let mut started = true; - if let Err(err) = netman.startup().await { - error!("network startup failed: {}", err); - started = false; - } + let mut restart; + loop { + restart = false; + if let Err(err) = netman.startup().await { + error!("network startup failed: {}", err); + netman.shutdown().await; + break; + } - if started { - trace!("started maintaining peers"); + debug!("started maintaining peers"); while self.inner.lock().maintain_peers { // tick network manager if let Err(err) = netman.tick().await { error!("Error in network manager: {}", err); self.inner.lock().maintain_peers = false; + restart = true; break; } @@ -250,10 +253,18 @@ impl AttachmentManager { // sleep should be at the end in case maintain_peers changes state intf::sleep(1000).await; } - trace!("stopped maintaining peers"); + debug!("stopped maintaining peers"); - trace!("stopping network"); + debug!("stopping network"); netman.shutdown().await; + + if !restart { + break; + } + + debug!("completely restarting attachment"); + // chill out for a second first, give network stack time to settle out + intf::sleep(1000).await; } trace!("stopping attachment"); @@ -261,7 +272,7 @@ impl AttachmentManager { let _output = attachment_machine .consume(&AttachmentInput::AttachmentStopped) .await; - trace!("attachment stopped"); + debug!("attachment stopped"); self.inner.lock().attach_timestamp = None; } diff --git a/veilid-core/src/core_context.rs b/veilid-core/src/core_context.rs index 1c0d8f76..7647fb37 100644 --- a/veilid-core/src/core_context.rs +++ b/veilid-core/src/core_context.rs @@ -76,7 +76,7 @@ impl ServicesContext { // Init node id from config now that protected store is set up if let Err(e) = self.config.init_node_id(protected_store.clone()).await { self.shutdown().await; - return Err(VeilidAPIError::Internal { message: e }); + return Err(e); } // Set up tablestore @@ -177,9 +177,7 @@ impl VeilidCoreContext { // Set up config from callback trace!("setup config with callback"); let mut config = VeilidConfig::new(); - if let Err(e) = config.setup(config_callback) { - return Err(VeilidAPIError::Internal { message: e }); - } + config.setup(config_callback)?; Self::new_common(update_callback, config).await } @@ -192,9 +190,7 @@ impl VeilidCoreContext { // Set up config from callback trace!("setup config with json"); let mut config = VeilidConfig::new(); - if let Err(e) = config.setup_from_json(config_json) { - return Err(VeilidAPIError::Internal { message: e }); - } + config.setup_from_json(config_json)?; Self::new_common(update_callback, config).await } diff --git a/veilid-core/src/dht/key.rs b/veilid-core/src/dht/key.rs index 7d3ff345..ea890a5a 100644 --- a/veilid-core/src/dht/key.rs +++ b/veilid-core/src/dht/key.rs @@ -1,17 +1,18 @@ +use crate::veilid_rng::*; use crate::xx::*; +use crate::*; + use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; use core::convert::{TryFrom, TryInto}; use core::fmt; use core::hash::{Hash, Hasher}; -use crate::veilid_rng::*; -use ed25519_dalek::{Keypair, PublicKey, Signature}; -use serde::{Deserialize, Serialize}; - use data_encoding::BASE64URL_NOPAD; use digest::generic_array::typenum::U64; use digest::{Digest, Output}; +use ed25519_dalek::{Keypair, PublicKey, Signature}; use generic_array::GenericArray; +use serde::{Deserialize, Serialize}; ////////////////////////////////////////////////////////////////////// @@ -71,14 +72,14 @@ macro_rules! byte_array_type { Self { bytes, valid: true } } - pub fn try_from_vec(v: Vec) -> Result { + pub fn try_from_vec(v: Vec) -> Result { let mut this = Self { bytes: [0u8; $size], valid: true, }; if v.len() != $size { - return Err(format!( + apibail_generic!(format!( "Expected a Vec of length {} but it was {}", $size, v.len() @@ -139,25 +140,25 @@ macro_rules! byte_array_type { BASE64URL_NOPAD.encode(&self.bytes) } - pub fn try_decode(input: &str) -> Result { + pub fn try_decode(input: &str) -> Result { let mut bytes = [0u8; $size]; let res = BASE64URL_NOPAD.decode_len(input.len()); match res { Ok(v) => { if v != $size { - return Err("Incorrect length in decode".to_owned()); + apibail_generic!("Incorrect length in decode"); } } Err(_) => { - return Err("Failed to decode".to_owned()); + apibail_generic!("Failed to decode"); } } let res = BASE64URL_NOPAD.decode_mut(input.as_bytes(), &mut bytes); match res { Ok(_) => Ok(Self::new(bytes)), - Err(_) => Err("Failed to decode".to_owned()), + Err(_) => apierr_generic!("Failed to decode"), } } } @@ -255,28 +256,28 @@ macro_rules! byte_array_type { } impl TryFrom for $name { - type Error = String; + type Error = VeilidAPIError; fn try_from(value: String) -> Result { $name::try_from(value.as_str()) } } impl TryFrom<&str> for $name { - type Error = String; + type Error = VeilidAPIError; fn try_from(value: &str) -> Result { let mut out = $name::default(); if value == "" { return Ok(out); } if value.len() != ($size * 2) { - return Err(concat!(stringify!($name), " is incorrect length").to_owned()); + apibail_generic!(concat!(stringify!($name), " is incorrect length")); } match hex::decode_to_slice(value, &mut out.bytes) { Ok(_) => { out.valid = true; Ok(out) } - Err(err) => Err(format!("{}", err)), + Err(err) => apierr_generic!(err), } } } @@ -372,7 +373,7 @@ pub fn sign( dht_key: &DHTKey, dht_key_secret: &DHTKeySecret, data: &[u8], -) -> Result { +) -> Result { assert!(dht_key.valid); assert!(dht_key_secret.valid); @@ -381,32 +382,36 @@ pub fn sign( kpb[..DHT_KEY_SECRET_LENGTH].copy_from_slice(&dht_key_secret.bytes); kpb[DHT_KEY_SECRET_LENGTH..].copy_from_slice(&dht_key.bytes); - let keypair = Keypair::from_bytes(&kpb).map_err(|_| "Keypair is invalid".to_owned())?; + let keypair = Keypair::from_bytes(&kpb).map_err(mapapierr_parse!("Keypair is invalid"))?; let mut dig = Blake3Digest512::new(); dig.update(data); let sig = keypair .sign_prehashed(dig, None) - .map_err(|_| "Signature failed".to_owned())?; + .map_err(VeilidAPIError::internal)?; let dht_sig = DHTSignature::new(sig.to_bytes()); Ok(dht_sig) } -pub fn verify(dht_key: &DHTKey, data: &[u8], signature: &DHTSignature) -> Result<(), String> { +pub fn verify( + dht_key: &DHTKey, + data: &[u8], + signature: &DHTSignature, +) -> Result<(), VeilidAPIError> { assert!(dht_key.valid); assert!(signature.valid); let pk = - PublicKey::from_bytes(&dht_key.bytes).map_err(|_| "Public key is invalid".to_owned())?; - let sig = - Signature::from_bytes(&signature.bytes).map_err(|_| "Signature is invalid".to_owned())?; + PublicKey::from_bytes(&dht_key.bytes).map_err(mapapierr_parse!("Public key is invalid"))?; + let sig = Signature::from_bytes(&signature.bytes) + .map_err(mapapierr_parse!("Signature is invalid"))?; let mut dig = Blake3Digest512::new(); dig.update(data); pk.verify_prehashed(dig, None, &sig) - .map_err(|_| "Verification failed".to_owned())?; + .map_err(mapapierr_parse!("Verification failed"))?; Ok(()) } diff --git a/veilid-core/src/dht/tests/test_dht_key.rs b/veilid-core/src/dht/tests/test_dht_key.rs index 643e5c25..0d6eee4e 100644 --- a/veilid-core/src/dht/tests/test_dht_key.rs +++ b/veilid-core/src/dht/tests/test_dht_key.rs @@ -57,14 +57,8 @@ pub async fn test_sign_and_verify() { assert_eq!(key::verify(&dht_key, LOREM_IPSUM.as_bytes(), &a1), Ok(())); assert_eq!(key::verify(&dht_key2, LOREM_IPSUM.as_bytes(), &a2), Ok(())); - assert_eq!( - key::verify(&dht_key, LOREM_IPSUM.as_bytes(), &b1), - Err("Verification failed".to_owned()) - ); - assert_eq!( - key::verify(&dht_key2, LOREM_IPSUM.as_bytes(), &b2), - Err("Verification failed".to_owned()) - ); + assert!(key::verify(&dht_key, LOREM_IPSUM.as_bytes(), &b1).is_err()); + assert!(key::verify(&dht_key2, LOREM_IPSUM.as_bytes(), &b2).is_err()); // Try verifications that should work assert_eq!( @@ -84,22 +78,10 @@ pub async fn test_sign_and_verify() { Ok(()) ); // Try verifications that shouldn't work - assert_eq!( - key::verify(&dht_key2, LOREM_IPSUM.as_bytes(), &dht_sig), - Err("Verification failed".to_owned()) - ); - assert_eq!( - key::verify(&dht_key, LOREM_IPSUM.as_bytes(), &dht_sig2), - Err("Verification failed".to_owned()) - ); - assert_eq!( - key::verify(&dht_key2, CHEEZBURGER.as_bytes(), &dht_sig_c), - Err("Verification failed".to_owned()) - ); - assert_eq!( - key::verify(&dht_key, CHEEZBURGER.as_bytes(), &dht_sig), - Err("Verification failed".to_owned()) - ); + assert!(key::verify(&dht_key2, LOREM_IPSUM.as_bytes(), &dht_sig).is_err()); + assert!(key::verify(&dht_key, LOREM_IPSUM.as_bytes(), &dht_sig2).is_err()); + assert!(key::verify(&dht_key2, CHEEZBURGER.as_bytes(), &dht_sig_c).is_err()); + assert!(key::verify(&dht_key, CHEEZBURGER.as_bytes(), &dht_sig).is_err()); } pub async fn test_key_conversions() { @@ -214,9 +196,9 @@ pub async fn test_encode_decode() { // Failures let f1 = key::DHTKeySecret::try_decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); - assert_eq!(f1, Err("Incorrect length in decode".to_owned())); + assert!(f1.is_err()); let f2 = key::DHTKeySecret::try_decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&"); - assert_eq!(f2, Err("Failed to decode".to_owned())); + assert!(f2.is_err()); } async fn test_hash() { diff --git a/veilid-core/src/lib.rs b/veilid-core/src/lib.rs index c861d556..4820c9dc 100644 --- a/veilid-core/src/lib.rs +++ b/veilid-core/src/lib.rs @@ -29,6 +29,7 @@ mod receipt_manager; mod routing_table; mod rpc_processor; mod veilid_api; +#[macro_use] mod veilid_config; mod veilid_layer_filter; mod veilid_rng; diff --git a/veilid-core/src/network_manager/mod.rs b/veilid-core/src/network_manager/mod.rs index 3668630e..c945ed08 100644 --- a/veilid-core/src/network_manager/mod.rs +++ b/veilid-core/src/network_manager/mod.rs @@ -1227,8 +1227,8 @@ impl NetworkManager { // pinging this node regularly to keep itself in the routing table routing_table.lookup_node_ref(recipient_id).ok_or_else(|| { format!( - "Inbound relay asked for recipient not in routing table: {}", - recipient_id + "Inbound relay asked for recipient not in routing table: sender_id={:?} recipient={:?}", + sender_id, recipient_id ) })? }; diff --git a/veilid-core/src/routing_table/stats_accounting.rs b/veilid-core/src/routing_table/stats_accounting.rs index c99b7327..7ef69bd6 100644 --- a/veilid-core/src/routing_table/stats_accounting.rs +++ b/veilid-core/src/routing_table/stats_accounting.rs @@ -98,7 +98,7 @@ impl LatencyStatsAccounting { self.rolling_latencies.push_back(latency); let mut ls = LatencyStats { - fastest: 0, + fastest: u64::MAX, average: 0, slowest: 0, }; diff --git a/veilid-core/src/rpc_processor/debug.rs b/veilid-core/src/rpc_processor/debug.rs index 62766d5e..27780e1c 100644 --- a/veilid-core/src/rpc_processor/debug.rs +++ b/veilid-core/src/rpc_processor/debug.rs @@ -10,17 +10,20 @@ pub enum RPCError { Internal(String), } -pub fn rpc_error_internal>(x: T) -> RPCError { - error!("RPCError Internal: {}", x.as_ref()); - RPCError::Internal(x.as_ref().to_owned()) +pub fn rpc_error_internal(x: T) -> RPCError { + let x = x.to_string(); + error!("RPCError Internal: {}", x); + RPCError::Internal(x) } -pub fn rpc_error_invalid_format>(x: T) -> RPCError { - error!("RPCError Invalid Format: {}", x.as_ref()); - RPCError::InvalidFormat(x.as_ref().to_owned()) +pub fn rpc_error_invalid_format(x: T) -> RPCError { + let x = x.to_string(); + error!("RPCError Invalid Format: {}", x); + RPCError::InvalidFormat(x) } -pub fn rpc_error_protocol>(x: T) -> RPCError { - error!("RPCError Protocol: {}", x.as_ref()); - RPCError::Protocol(x.as_ref().to_owned()) +pub fn rpc_error_protocol(x: T) -> RPCError { + let x = x.to_string(); + error!("RPCError Protocol: {}", x); + RPCError::Protocol(x) } pub fn rpc_error_capnp_error(e: capnp::Error) -> RPCError { error!("RPCError Protocol: capnp error: {}", &e.description); @@ -30,9 +33,10 @@ pub fn rpc_error_capnp_notinschema(e: capnp::NotInSchema) -> RPCError { error!("RPCError Protocol: not in schema: {}", &e.0); RPCError::Protocol(format!("not in schema: {}", &e.0)) } -pub fn rpc_error_unimplemented>(x: T) -> RPCError { - error!("RPCError Unimplemented: {}", x.as_ref()); - RPCError::Unimplemented(x.as_ref().to_owned()) +pub fn rpc_error_unimplemented(x: T) -> RPCError { + let x = x.to_string(); + error!("RPCError Unimplemented: {}", x); + RPCError::Unimplemented(x) } impl fmt::Display for RPCError { diff --git a/veilid-core/src/tests/common/test_veilid_config.rs b/veilid-core/src/tests/common/test_veilid_config.rs index 3abf45c4..9b88206f 100644 --- a/veilid-core/src/tests/common/test_veilid_config.rs +++ b/veilid-core/src/tests/common/test_veilid_config.rs @@ -260,7 +260,7 @@ fn config_callback(key: String) -> ConfigCallbackReturn { _ => { let err = format!("config key '{}' doesn't exist", key); debug!("{}", err); - Err(err) + apierr_internal!(err) } } } diff --git a/veilid-core/src/veilid_api/debug.rs b/veilid-core/src/veilid_api/debug.rs index f24b8d52..259f6947 100644 --- a/veilid-core/src/veilid_api/debug.rs +++ b/veilid-core/src/veilid_api/debug.rs @@ -135,18 +135,14 @@ impl VeilidAPI { let config = self.config()?; let args = args.trim_start(); if args.is_empty() { - return config - .get_key_json("") - .map_err(|e| VeilidAPIError::Internal { message: e }); + return config.get_key_json(""); } let (arg, rest) = args.split_once(' ').unwrap_or((args, "")); let rest = rest.trim_start().to_owned(); // One argument is 'config get' if rest.is_empty() { - return config - .get_key_json(arg) - .map_err(|e| VeilidAPIError::Internal { message: e }); + return config.get_key_json(arg); } // More than one argument is 'config set' @@ -156,15 +152,11 @@ impl VeilidAPI { self.get_state().await?.attachment.state, AttachmentState::Detached ) { - return Err(VeilidAPIError::Internal { - message: "Must be detached to change config".to_owned(), - }); + apibail_internal!("Must be detached to change config"); } // Change the config key - config - .set_key_json(arg, &rest) - .map_err(|e| VeilidAPIError::Internal { message: e })?; + config.set_key_json(arg, &rest)?; Ok("Config value set".to_owned()) } @@ -177,9 +169,7 @@ impl VeilidAPI { self.get_state().await?.attachment.state, AttachmentState::Detached | AttachmentState::Detaching ) { - return Err(VeilidAPIError::Internal { - message: "Must be detached to purge".to_owned(), - }); + apibail_internal!("Must be detached to purge"); } self.network_manager()?.routing_table().purge(); Ok("Buckets purged".to_owned()) @@ -203,10 +193,8 @@ impl VeilidAPI { self.get_state().await?.attachment.state, AttachmentState::Detached ) { - return Err(VeilidAPIError::Internal { - message: "Not detached".to_owned(), - }); - }; + apibail_internal!("Not detached"); + } self.attach().await?; @@ -218,9 +206,7 @@ impl VeilidAPI { self.get_state().await?.attachment.state, AttachmentState::Detaching ) { - return Err(VeilidAPIError::Internal { - message: "Not attached".to_owned(), - }); + apibail_internal!("Not attached"); }; self.detach().await?; diff --git a/veilid-core/src/veilid_api/mod.rs b/veilid-core/src/veilid_api/mod.rs index 59903d7d..025c5852 100644 --- a/veilid-core/src/veilid_api/mod.rs +++ b/veilid-core/src/veilid_api/mod.rs @@ -31,6 +31,62 @@ use xx::*; ///////////////////////////////////////////////////////////////////////////////////////////////////// +#[allow(unused_macros)] +#[macro_export] +macro_rules! apierr_generic { + ($x:expr) => { + Err(VeilidAPIError::generic($x)) + }; +} + +#[allow(unused_macros)] +#[macro_export] +macro_rules! apierr_internal { + ($x:expr) => { + Err(VeilidAPIError::internal($x)) + }; +} + +#[allow(unused_macros)] +#[macro_export] +macro_rules! apierr_parse { + ($x:expr, $y:expr) => { + Err(VeilidAPIError::parse_error($x, $y)) + }; +} + +#[allow(unused_macros)] +#[macro_export] +macro_rules! mapapierr_parse { + ($x:expr) => { + |e| VeilidAPIError::parse_error($x, e) + }; +} + +#[allow(unused_macros)] +#[macro_export] +macro_rules! apibail_generic { + ($x:expr) => { + return Err(VeilidAPIError::generic($x)); + }; +} + +#[allow(unused_macros)] +#[macro_export] +macro_rules! apibail_internal { + ($x:expr) => { + return Err(VeilidAPIError::internal($x)); + }; +} + +#[allow(unused_macros)] +#[macro_export] +macro_rules! apibail_parse { + ($x:expr, $y:expr) => { + return Err(VeilidAPIError::parse_error($x, $y)); + }; +} + #[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Serialize, Deserialize)] #[serde(tag = "kind")] pub enum VeilidAPIError { @@ -66,8 +122,63 @@ pub enum VeilidAPIError { context: String, argument: String, }, + Generic { + message: String, + }, } +impl VeilidAPIError { + pub fn node_not_found(node_id: NodeId) -> Self { + Self::NodeNotFound { node_id } + } + pub fn no_dial_info(node_id: NodeId) -> Self { + Self::NoDialInfo { node_id } + } + pub fn no_peer_info(node_id: NodeId) -> Self { + Self::NoPeerInfo { node_id } + } + pub fn internal(msg: T) -> Self { + Self::Internal { + message: msg.to_string(), + } + } + pub fn unimplemented(msg: T) -> Self { + Self::Unimplemented { + message: msg.to_string(), + } + } + pub fn parse_error(msg: T, value: S) -> Self { + Self::ParseError { + message: msg.to_string(), + value: value.to_string(), + } + } + pub fn invalid_argument( + context: T, + argument: S, + value: R, + ) -> Self { + Self::InvalidArgument { + context: context.to_string(), + argument: argument.to_string(), + value: value.to_string(), + } + } + pub fn missing_argument(context: T, argument: S) -> Self { + Self::MissingArgument { + context: context.to_string(), + argument: argument.to_string(), + } + } + pub fn generic(msg: T) -> Self { + Self::Generic { + message: msg.to_string(), + } + } +} + +impl std::error::Error for VeilidAPIError {} + impl fmt::Display for VeilidAPIError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match self { @@ -111,6 +222,9 @@ impl fmt::Display for VeilidAPIError { context, argument ) } + VeilidAPIError::Generic { message } => { + write!(f, "VeilidAPIError::Generic({})", message) + } } } } @@ -1321,9 +1435,11 @@ impl SignedNodeInfo { node_id: NodeId, signature: DHTSignature, timestamp: u64, - ) -> Result { - let mut node_info_bytes = serde_cbor::to_vec(&node_info).map_err(map_to_string)?; - let mut timestamp_bytes = serde_cbor::to_vec(×tamp).map_err(map_to_string)?; + ) -> Result { + let mut node_info_bytes = serde_cbor::to_vec(&node_info) + .map_err(mapapierr_parse!("failed to encode node info as cbor"))?; + let mut timestamp_bytes = serde_cbor::to_vec(×tamp) + .map_err(mapapierr_parse!("failed to encode timestamp as cbor"))?; node_info_bytes.append(&mut timestamp_bytes); @@ -1339,11 +1455,13 @@ impl SignedNodeInfo { node_info: NodeInfo, node_id: NodeId, secret: &DHTKeySecret, - ) -> Result { + ) -> Result { let timestamp = intf::get_timestamp(); - let mut node_info_bytes = serde_cbor::to_vec(&node_info).map_err(map_to_string)?; - let mut timestamp_bytes = serde_cbor::to_vec(×tamp).map_err(map_to_string)?; + let mut node_info_bytes = serde_cbor::to_vec(&node_info) + .map_err(mapapierr_parse!("failed to encode node info as cbor"))?; + let mut timestamp_bytes = serde_cbor::to_vec(×tamp) + .map_err(mapapierr_parse!("failed to encode timestamp as cbor"))?; node_info_bytes.append(&mut timestamp_bytes); diff --git a/veilid-core/src/veilid_config.rs b/veilid-core/src/veilid_config.rs index 3132cb79..304cb51c 100644 --- a/veilid-core/src/veilid_config.rs +++ b/veilid-core/src/veilid_config.rs @@ -5,11 +5,11 @@ use serde::*; //////////////////////////////////////////////////////////////////////////////////////////////// cfg_if! { if #[cfg(target_arch = "wasm32")] { - pub type ConfigCallbackReturn = Result, String>; + pub type ConfigCallbackReturn = Result, VeilidAPIError>; pub type ConfigCallback = Arc ConfigCallbackReturn>; } else { - pub type ConfigCallbackReturn = Result, String>; + pub type ConfigCallbackReturn = Result, VeilidAPIError>; pub type ConfigCallback = Arc ConfigCallbackReturn + Send + Sync>; } } @@ -281,10 +281,10 @@ impl VeilidConfig { } } - pub fn setup_from_json(&mut self, config: String) -> Result<(), String> { + pub fn setup_from_json(&mut self, config: String) -> Result<(), VeilidAPIError> { { let mut inner = self.inner.write(); - *inner = serde_json::from_str(&config).map_err(map_to_string)?; + *inner = serde_json::from_str(&config).map_err(VeilidAPIError::generic)?; } // Validate settings @@ -293,14 +293,14 @@ impl VeilidConfig { Ok(()) } - pub fn setup(&mut self, cb: ConfigCallback) -> Result<(), String> { + pub fn setup(&mut self, cb: ConfigCallback) -> Result<(), VeilidAPIError> { macro_rules! get_config { ($key:expr) => { let keyname = &stringify!($key)[6..]; $key = *cb(keyname.to_owned())?.downcast().map_err(|_| { - let err = format!("incorrect type for key: {}", keyname); + let err = format!("incorrect type for key {}", keyname); debug!("{}", err); - err + VeilidAPIError::generic(err) })?; }; } @@ -411,12 +411,12 @@ impl VeilidConfig { self.inner.write() } - pub fn get_key_json(&self, key: &str) -> Result { + pub fn get_key_json(&self, key: &str) -> Result { let c = self.get(); // Generate json from whole config - let jc = serde_json::to_string(&*c).map_err(map_to_string)?; - let jvc = json::parse(&jc).map_err(map_to_string)?; + let jc = serde_json::to_string(&*c).map_err(VeilidAPIError::generic)?; + let jvc = json::parse(&jc).map_err(VeilidAPIError::generic)?; // Find requested subkey if key.is_empty() { @@ -427,25 +427,25 @@ impl VeilidConfig { let mut out = &jvc; for k in keypath { if !out.has_key(k) { - return Err(format!("invalid subkey '{}' in key '{}'", k, key)); + apibail_parse!(format!("invalid subkey in key '{}'", key), k); } out = &out[k]; } Ok(out.to_string()) } } - pub fn set_key_json(&self, key: &str, value: &str) -> Result<(), String> { + pub fn set_key_json(&self, key: &str, value: &str) -> Result<(), VeilidAPIError> { let mut c = self.get_mut(); // Split key into path parts let keypath: Vec<&str> = key.split('.').collect(); // Convert value into jsonvalue - let newval = json::parse(value).map_err(map_to_string)?; + let newval = json::parse(value).map_err(VeilidAPIError::generic)?; // Generate json from whole config - let jc = serde_json::to_string(&*c).map_err(map_to_string)?; - let mut jvc = json::parse(&jc).map_err(map_to_string)?; + let jc = serde_json::to_string(&*c).map_err(VeilidAPIError::generic)?; + let mut jvc = json::parse(&jc).map_err(VeilidAPIError::generic)?; // Find requested subkey let newconfigstring = if let Some((objkeyname, objkeypath)) = keypath.split_last() { @@ -453,12 +453,12 @@ impl VeilidConfig { let mut out = &mut jvc; for k in objkeypath { if !out.has_key(*k) { - return Err(format!("invalid subkey '{}' in key '{}'", *k, key)); + apibail_parse!(format!("invalid subkey in key '{}'", key), k); } out = &mut out[*k]; } if !out.has_key(objkeyname) { - return Err(format!("invalid subkey '{}' in key '{}'", objkeyname, key)); + apibail_parse!(format!("invalid subkey in key '{}'", key), objkeyname); } out[*objkeyname] = newval; jvc.to_string() @@ -473,11 +473,11 @@ impl VeilidConfig { Ok(()) } - fn validate(&self) -> Result<(), String> { + fn validate(&self) -> Result<(), VeilidAPIError> { let inner = self.inner.read(); if inner.program_name.is_empty() { - return Err("Program name must not be empty in 'program_name'".to_owned()); + apibail_generic!("Program name must not be empty in 'program_name'"); } // if inner.network.protocol.udp.enabled { @@ -486,29 +486,29 @@ impl VeilidConfig { if inner.network.protocol.tcp.listen { // Validate TCP settings if inner.network.protocol.tcp.max_connections == 0 { - return Err("TCP max connections must be > 0 in config key 'network.protocol.tcp.max_connections'".to_owned()); + apibail_generic!("TCP max connections must be > 0 in config key 'network.protocol.tcp.max_connections'"); } } if inner.network.protocol.ws.listen { // Validate WS settings if inner.network.protocol.ws.max_connections == 0 { - return Err("WS max connections must be > 0 in config key 'network.protocol.ws.max_connections'".to_owned()); + apibail_generic!("WS max connections must be > 0 in config key 'network.protocol.ws.max_connections'"); } if inner.network.application.https.enabled && inner.network.application.https.path == inner.network.protocol.ws.path { - return Err("WS path conflicts with HTTPS application path in config key 'network.protocol.ws.path'".to_owned()); + apibail_generic!("WS path conflicts with HTTPS application path in config key 'network.protocol.ws.path'"); } if inner.network.application.http.enabled && inner.network.application.http.path == inner.network.protocol.ws.path { - return Err("WS path conflicts with HTTP application path in config key 'network.protocol.ws.path'".to_owned()); + apibail_generic!("WS path conflicts with HTTP application path in config key 'network.protocol.ws.path'"); } } if inner.network.protocol.wss.listen { // Validate WSS settings if inner.network.protocol.wss.max_connections == 0 { - return Err("WSS max connections must be > 0 in config key 'network.protocol.wss.max_connections'".to_owned()); + apibail_generic!("WSS max connections must be > 0 in config key 'network.protocol.wss.max_connections'"); } if inner .network @@ -519,19 +519,19 @@ impl VeilidConfig { .map(|u| u.is_empty()) .unwrap_or_default() { - return Err( - "WSS URL must be specified in config key 'network.protocol.wss.url'".to_owned(), + apibail_generic!( + "WSS URL must be specified in config key 'network.protocol.wss.url'" ); } if inner.network.application.https.enabled && inner.network.application.https.path == inner.network.protocol.wss.path { - return Err("WSS path conflicts with HTTPS application path in config key 'network.protocol.ws.path'".to_owned()); + apibail_generic!("WSS path conflicts with HTTPS application path in config key 'network.protocol.ws.path'"); } if inner.network.application.http.enabled && inner.network.application.http.path == inner.network.protocol.wss.path { - return Err("WSS path conflicts with HTTP application path in config key 'network.protocol.ws.path'".to_owned()); + apibail_generic!("WSS path conflicts with HTTP application path in config key 'network.protocol.ws.path'"); } } if inner.network.application.https.enabled { @@ -545,9 +545,8 @@ impl VeilidConfig { .map(|u| u.is_empty()) .unwrap_or_default() { - return Err( + apibail_generic!( "HTTPS URL must be specified in config key 'network.application.https.url'" - .to_owned(), ); } } @@ -556,15 +555,22 @@ impl VeilidConfig { // Get the node id from config if one is specified // Must be done -after- protected store startup - pub async fn init_node_id(&self, protected_store: intf::ProtectedStore) -> Result<(), String> { + pub async fn init_node_id( + &self, + protected_store: intf::ProtectedStore, + ) -> Result<(), VeilidAPIError> { let mut node_id = self.inner.read().network.node_id; let mut node_id_secret = self.inner.read().network.node_id_secret; // See if node id was previously stored in the protected store if !node_id.valid { debug!("pulling node id from storage"); - if let Some(s) = protected_store.load_user_secret_string("node_id").await? { + if let Some(s) = protected_store + .load_user_secret_string("node_id") + .await + .map_err(VeilidAPIError::internal)? + { debug!("node id found in storage"); - node_id = DHTKey::try_decode(s.as_str())? + node_id = DHTKey::try_decode(s.as_str()).map_err(VeilidAPIError::internal)? } else { debug!("node id not found in storage"); } @@ -575,10 +581,12 @@ impl VeilidConfig { debug!("pulling node id secret from storage"); if let Some(s) = protected_store .load_user_secret_string("node_id_secret") - .await? + .await + .map_err(VeilidAPIError::internal)? { debug!("node id secret found in storage"); - node_id_secret = DHTKeySecret::try_decode(s.as_str())? + node_id_secret = + DHTKeySecret::try_decode(s.as_str()).map_err(VeilidAPIError::internal)? } else { debug!("node id secret not found in storage"); } @@ -588,7 +596,7 @@ impl VeilidConfig { if node_id.valid && node_id_secret.valid { // Validate node id if !dht::validate_key(&node_id, &node_id_secret) { - return Err("node id secret and node id key don't match".to_owned()); + apibail_generic!("node id secret and node id key don't match"); } } @@ -605,10 +613,12 @@ impl VeilidConfig { // Save the node id / secret in storage protected_store .save_user_secret_string("node_id", node_id.encode().as_str()) - .await?; + .await + .map_err(VeilidAPIError::internal)?; protected_store .save_user_secret_string("node_id_secret", node_id_secret.encode().as_str()) - .await?; + .await + .map_err(VeilidAPIError::internal)?; self.inner.write().network.node_id = node_id; self.inner.write().network.node_id_secret = node_id_secret; diff --git a/veilid-server/Cargo.toml b/veilid-server/Cargo.toml index 49871349..b93f2afd 100644 --- a/veilid-server/Cargo.toml +++ b/veilid-server/Cargo.toml @@ -30,6 +30,7 @@ tokio = { version = "^1", features = ["full"], optional = true } tokio-stream = { version = "^0", features = ["net"], optional = true } tokio-util = { version = "^0", features = ["compat"], optional = true} async-tungstenite = { version = "^0", features = ["async-tls"] } +color-eyre = "^0.6" clap = "^3" directories = "^4" capnp = "^0" diff --git a/veilid-server/src/cmdline.rs b/veilid-server/src/cmdline.rs index c6a6a32b..f7617e11 100644 --- a/veilid-server/src/cmdline.rs +++ b/veilid-server/src/cmdline.rs @@ -1,4 +1,5 @@ use crate::settings::*; +use crate::*; use clap::{Arg, ArgMatches, Command}; use std::ffi::OsStr; use std::path::Path; @@ -145,11 +146,11 @@ fn do_clap_matches(default_config_path: &OsStr) -> Result Result<(Settings, ArgMatches), String> { +pub fn process_command_line() -> EyreResult<(Settings, ArgMatches)> { // Get command line options let default_config_path = Settings::get_default_config_path(); let matches = do_clap_matches(default_config_path.as_os_str()) - .map_err(|e| format!("failed to parse command line: {}", e))?; + .wrap_err("failed to parse command line: {}")?; // Check for one-off commands #[cfg(debug_assertions)] @@ -169,8 +170,7 @@ pub fn process_command_line() -> Result<(Settings, ArgMatches), String> { None }; - let settings = - Settings::new(settings_path).map_err(|e| format!("configuration is invalid: {}", e))?; + let settings = Settings::new(settings_path).wrap_err("configuration is invalid")?; // write lock the settings let mut settingsrw = settings.write(); @@ -185,15 +185,13 @@ pub fn process_command_line() -> Result<(Settings, ArgMatches), String> { } if matches.occurrences_of("subnode-index") != 0 { let subnode_index = match matches.value_of("subnode-index") { - Some(x) => x - .parse() - .map_err(|e| format!("couldn't parse subnode index: {}", e))?, + Some(x) => x.parse().wrap_err("couldn't parse subnode index")?, None => { - return Err("value not specified for subnode-index".to_owned()); + bail!("value not specified for subnode-index"); } }; if subnode_index == 0 { - return Err("value of subnode_index should be between 1 and 65535".to_owned()); + bail!("value of subnode_index should be between 1 and 65535"); } settingsrw.testing.subnode_index = subnode_index; } @@ -214,7 +212,7 @@ pub fn process_command_line() -> Result<(Settings, ArgMatches), String> { .expect("should not be null because of default missing value") .to_string(), ) - .map_err(|e| format!("failed to parse OTLP address: {}", e))?; + .wrap_err("failed to parse OTLP address")?; settingsrw.logging.otlp.level = LogLevel::Trace; } if matches.is_present("attach") { @@ -242,13 +240,13 @@ pub fn process_command_line() -> Result<(Settings, ArgMatches), String> { // Split or get secret let (k, s) = if let Some((k, s)) = v.split_once(':') { - let k = DHTKey::try_decode(k)?; + let k = DHTKey::try_decode(k).wrap_err("failed to decode node id from command line")?; let s = DHTKeySecret::try_decode(s)?; (k, s) } else { let k = DHTKey::try_decode(v)?; let buffer = rpassword::prompt_password("Enter secret key (will not echo): ") - .map_err(|e| e.to_string())?; + .wrap_err("invalid secret key")?; let buffer = buffer.trim().to_string(); let s = DHTKeySecret::try_decode(&buffer)?; (k, s) @@ -270,7 +268,7 @@ pub fn process_command_line() -> Result<(Settings, ArgMatches), String> { out } None => { - return Err("value not specified for bootstrap".to_owned()); + bail!("value not specified for bootstrap"); } }; settingsrw.core.network.bootstrap = bootstrap_list; @@ -284,17 +282,15 @@ pub fn process_command_line() -> Result<(Settings, ArgMatches), String> { for x in x.split(',') { let x = x.trim(); println!(" {}", x); - out.push(ParsedNodeDialInfo::from_str(x).map_err(|e| { - format!( - "unable to parse dial info in bootstrap node list: {} for {}", - e, x - ) - })?); + out.push( + ParsedNodeDialInfo::from_str(x) + .wrap_err("unable to parse dial info in bootstrap node list")?, + ); } out } None => { - return Err("value not specified for bootstrap node list".to_owned()); + bail!("value not specified for bootstrap node list"); } }; settingsrw.core.network.bootstrap_nodes = bootstrap_list; @@ -315,7 +311,7 @@ pub fn process_command_line() -> Result<(Settings, ArgMatches), String> { // Apply subnode index if we're testing settings .apply_subnode_index() - .map_err(|_| "failed to apply subnode index".to_owned())?; + .wrap_err("failed to apply subnode index")?; Ok((settings, matches)) } diff --git a/veilid-server/src/main.rs b/veilid-server/src/main.rs index be0e6d12..a99b6033 100644 --- a/veilid-server/src/main.rs +++ b/veilid-server/src/main.rs @@ -14,6 +14,8 @@ mod veilid_logs; mod windows; use cfg_if::*; +#[allow(unused_imports)] +use color_eyre::eyre::{bail, ensure, eyre, Result as EyreResult, WrapErr}; use server::*; use tools::*; use tracing::*; @@ -25,16 +27,17 @@ pub mod veilid_client_capnp { } #[instrument(err)] -fn main() -> Result<(), String> { +fn main() -> EyreResult<()> { #[cfg(windows)] let _ = ansi_term::enable_ansi_support(); + color_eyre::install()?; let (settings, matches) = cmdline::process_command_line()?; // --- Dump Config --- if matches.occurrences_of("dump-config") != 0 { return serde_yaml::to_writer(std::io::stdout(), &*settings.read()) - .map_err(|e| e.to_string()); + .wrap_err("failed to write yaml"); } // --- Generate DHT Key --- diff --git a/veilid-server/src/server.rs b/veilid-server/src/server.rs index b035deda..bb807bb4 100644 --- a/veilid-server/src/server.rs +++ b/veilid-server/src/server.rs @@ -2,6 +2,7 @@ use crate::client_api; use crate::settings::*; use crate::tools::*; use crate::veilid_logs::*; +use crate::*; use flume::{unbounded, Receiver, Sender}; use lazy_static::*; use parking_lot::Mutex; @@ -34,16 +35,16 @@ pub async fn run_veilid_server( settings: Settings, server_mode: ServerMode, veilid_logs: VeilidLogs, -) -> Result<(), String> { +) -> EyreResult<()> { run_veilid_server_internal(settings, server_mode, veilid_logs).await } -#[instrument(err, skip_all)] +//#[instrument(err, skip_all)] pub async fn run_veilid_server_internal( settings: Settings, server_mode: ServerMode, veilid_logs: VeilidLogs, -) -> Result<(), String> { +) -> EyreResult<()> { trace!(?settings, ?server_mode); let settingsr = settings.read(); @@ -65,7 +66,7 @@ pub async fn run_veilid_server_internal( // Start Veilid Core and get API let veilid_api = veilid_core::api_startup(update_callback, config_callback) .await - .map_err(|e| format!("VeilidCore startup failed: {}", e))?; + .wrap_err("VeilidCore startup failed")?; // Start client api if one is requested let mut capi = if settingsr.client_api.enabled && matches!(server_mode, ServerMode::Normal) { @@ -98,9 +99,10 @@ pub async fn run_veilid_server_internal( if auto_attach { info!("Auto-attach to the Veilid network"); if let Err(e) = veilid_api.attach().await { - let outerr = format!("Auto-attaching to the Veilid network failed: {:?}", e); - error!("{}", outerr); - out = Err(outerr); + out = Err(eyre!( + "Auto-attaching to the Veilid network failed: {:?}", + e + )); shutdown(); } } @@ -116,9 +118,7 @@ pub async fn run_veilid_server_internal( } } Err(e) => { - let outerr = format!("Getting state failed: {:?}", e); - error!("{}", outerr); - out = Err(outerr); + out = Err(eyre!("Getting state failed: {:?}", e)); break; } } @@ -129,9 +129,7 @@ pub async fn run_veilid_server_internal( print!("{}", v); } Err(e) => { - let outerr = format!("Getting TXT record failed: {:?}", e); - error!("{}", outerr); - out = Err(outerr); + out = Err(eyre!("Getting TXT record failed: {:?}", e)); } }; shutdown(); diff --git a/veilid-server/src/settings.rs b/veilid-server/src/settings.rs index 1174be44..5ede034c 100644 --- a/veilid-server/src/settings.rs +++ b/veilid-server/src/settings.rs @@ -1,5 +1,7 @@ #![allow(clippy::bool_assert_comparison)] +use crate::*; + use directories::*; use parking_lot::*; @@ -11,8 +13,9 @@ use std::str::FromStr; use std::sync::Arc; use url::Url; use veilid_core::xx::*; +use veilid_core::*; -pub fn load_default_config() -> Result { +pub fn load_default_config() -> EyreResult { let default_config = String::from( r#"--- daemon: @@ -172,21 +175,18 @@ core: config::FileFormat::Yaml, )) .build() + .wrap_err("failed to parse default config") } -pub fn load_config( - cfg: config::Config, - config_file: &Path, -) -> Result { +pub fn load_config(cfg: config::Config, config_file: &Path) -> EyreResult { if let Some(config_file_str) = config_file.to_str() { config::Config::builder() .add_source(cfg) .add_source(config::File::new(config_file_str, config::FileFormat::Yaml)) .build() + .wrap_err("failed to load config") } else { - Err(config::ConfigError::Message( - "config file path is not valid UTF-8".to_owned(), - )) + bail!("config file path is not valid UTF-8") } } @@ -254,9 +254,11 @@ pub struct ParsedUrl { } impl ParsedUrl { - pub fn offset_port(&mut self, offset: u16) -> Result<(), ()> { + pub fn offset_port(&mut self, offset: u16) -> EyreResult<()> { // Bump port on url - self.url.set_port(Some(self.url.port().unwrap() + offset))?; + self.url + .set_port(Some(self.url.port().unwrap() + offset)) + .map_err(|_| eyre!("failed to set port on url"))?; self.urlstring = self.url.to_string(); Ok(()) } @@ -388,16 +390,16 @@ impl serde::Serialize for NamedSocketAddrs { } impl NamedSocketAddrs { - pub fn offset_port(&mut self, offset: u16) -> Result<(), ()> { + pub fn offset_port(&mut self, offset: u16) -> EyreResult<()> { // Bump port on name if let Some(split) = self.name.rfind(':') { let hoststr = &self.name[0..split]; let portstr = &self.name[split + 1..]; - let port: u16 = portstr.parse::().map_err(drop)? + offset; + let port: u16 = portstr.parse::().wrap_err("failed to parse port")? + offset; self.name = format!("{}:{}", hoststr, port); } else { - return Err(()); + bail!("no port specified to offset"); } // Bump port on addresses @@ -655,7 +657,7 @@ pub struct Settings { } impl Settings { - pub fn new(config_file: Option<&OsStr>) -> Result { + pub fn new(config_file: Option<&OsStr>) -> EyreResult { // Load the default config let mut cfg = load_default_config()?; @@ -681,7 +683,7 @@ impl Settings { self.inner.write() } - pub fn apply_subnode_index(&self) -> Result<(), ()> { + pub fn apply_subnode_index(&self) -> EyreResult<()> { let mut settingsrw = self.write(); let idx = settingsrw.testing.subnode_index; if idx == 0 { @@ -869,7 +871,7 @@ impl Settings { pk_path } - pub fn set(&self, key: &str, value: &str) -> Result<(), String> { + pub fn set(&self, key: &str, value: &str) -> EyreResult<()> { let mut inner = self.inner.write(); macro_rules! set_config_value { @@ -882,9 +884,11 @@ impl Settings { return Ok(()); } Err(e) => { - return Err(format!( + return Err(eyre!( "invalid type for key {}, value: {}: {}", - key, value, e + key, + value, + e )) } } @@ -1005,7 +1009,7 @@ impl Settings { set_config_value!(inner.core.network.protocol.wss.listen_address, value); set_config_value!(inner.core.network.protocol.wss.path, value); set_config_value!(inner.core.network.protocol.wss.url, value); - Err("settings key not found".to_owned()) + Err(eyre!("settings key not found")) } pub fn get_core_config_callback(&self) -> veilid_core::ConfigCallback { @@ -1013,7 +1017,7 @@ impl Settings { Arc::new(move |key: String| { let inner = inner.read(); - let out: Result, String> = match key.as_str() { + let out: ConfigCallbackReturn = match key.as_str() { "program_name" => Ok(Box::new("veilid-server".to_owned())), "namespace" => Ok(Box::new(if inner.testing.subnode_index == 0 { "".to_owned() @@ -1365,7 +1369,10 @@ impl Settings { .as_ref() .map(|a| a.urlstring.clone()), )), - _ => Err(format!("config key '{}' doesn't exist", key)), + _ => Err(VeilidAPIError::generic(format!( + "config key '{}' doesn't exist", + key + ))), }; out }) diff --git a/veilid-server/src/unix.rs b/veilid-server/src/unix.rs index 5ba7fa5b..f3374823 100644 --- a/veilid-server/src/unix.rs +++ b/veilid-server/src/unix.rs @@ -2,6 +2,7 @@ use crate::server::*; use crate::settings::Settings; use crate::tools::*; use crate::veilid_logs::*; +use crate::*; use clap::ArgMatches; use futures_util::StreamExt; use signal_hook::consts::signal::*; @@ -26,7 +27,7 @@ async fn handle_signals(mut signals: Signals) { } #[instrument(err)] -pub fn run_daemon(settings: Settings, _matches: ArgMatches) -> Result<(), String> { +pub fn run_daemon(settings: Settings, _matches: ArgMatches) -> EyreResult<()> { let daemon = { let mut daemon = daemonize::Daemonize::new(); let s = settings.read(); @@ -64,10 +65,7 @@ pub fn run_daemon(settings: Settings, _matches: ArgMatches) -> Result<(), String } let stdout_file = if let Some(stdout_file) = &s.daemon.stdout_file { - Some( - std::fs::File::create(stdout_file) - .map_err(|e| format!("Failed to create stdio file: {}", e))?, - ) + Some(std::fs::File::create(stdout_file).wrap_err("Failed to create stdio file")?) } else { None }; @@ -79,12 +77,11 @@ pub fn run_daemon(settings: Settings, _matches: ArgMatches) -> Result<(), String .as_ref() .unwrap() .try_clone() - .map_err(|e| format!("Failed to clone stdout file: {}", e))?, + .wrap_err("Failed to clone stdout file")?, ); } else { daemon = daemon.stderr( - std::fs::File::create(stderr_file) - .map_err(|e| format!("Failed to create stderr file: {}", e))?, + std::fs::File::create(stderr_file).wrap_err("Failed to create stderr file")?, ); } } @@ -101,13 +98,11 @@ pub fn run_daemon(settings: Settings, _matches: ArgMatches) -> Result<(), String let veilid_logs = VeilidLogs::setup(settings.clone())?; // Daemonize - daemon - .start() - .map_err(|e| format!("Failed to daemonize: {}", e))?; + daemon.start().wrap_err("Failed to daemonize")?; // Catch signals - let signals = Signals::new(&[SIGHUP, SIGTERM, SIGINT, SIGQUIT]) - .map_err(|e| format!("failed to init signals: {}", e))?; + let signals = + Signals::new(&[SIGHUP, SIGTERM, SIGINT, SIGQUIT]).wrap_err("failed to init signals")?; let handle = signals.handle(); let signals_task = spawn(handle_signals(signals)); diff --git a/veilid-server/src/veilid_logs.rs b/veilid-server/src/veilid_logs.rs index 9bfaaa15..aa8b2962 100644 --- a/veilid-server/src/veilid_logs.rs +++ b/veilid-server/src/veilid_logs.rs @@ -1,4 +1,5 @@ use crate::settings::*; +use crate::*; use cfg_if::*; use opentelemetry::sdk::*; use opentelemetry::*; @@ -22,7 +23,7 @@ pub struct VeilidLogs { } impl VeilidLogs { - pub fn setup(settings: Settings) -> Result { + pub fn setup(settings: Settings) -> EyreResult { let settingsr = settings.read(); // Set up subscriber and layers @@ -77,7 +78,7 @@ impl VeilidLogs { )]), )) .install_batch(batch) - .map_err(|e| format!("failed to install OpenTelemetry tracer: {}", e))?; + .wrap_err("failed to install OpenTelemetry tracer")?; let filter = veilid_core::VeilidLayerFilter::new( convert_loglevel(settingsr.logging.otlp.level), @@ -101,13 +102,11 @@ impl VeilidLogs { .parent() .unwrap_or(Path::new(&MAIN_SEPARATOR.to_string())) .canonicalize() - .map_err(|e| { - format!( - "File log path parent does not exist: {} ({})", - settingsr.logging.file.path, e - ) - })?; - let log_filename = full_path.file_name().ok_or(format!( + .wrap_err(format!( + "File log path parent does not exist: {}", + settingsr.logging.file.path + ))?; + let log_filename = full_path.file_name().ok_or(eyre!( "File log filename not specified in path: {}", settingsr.logging.file.path ))?; @@ -149,7 +148,7 @@ impl VeilidLogs { convert_loglevel(settingsr.logging.system.level), None, ); - let layer =tracing_journald::layer().map_err(|e| format!("failed to set up journald logging: {}", e))? + let layer =tracing_journald::layer().wrap_err("failed to set up journald logging")? .with_filter(filter.clone()); filters.insert("system", filter); layers.push(layer.boxed()); @@ -160,7 +159,7 @@ impl VeilidLogs { let subscriber = subscriber.with(layers); subscriber .try_init() - .map_err(|e| format!("failed to initialize logging: {}", e))?; + .wrap_err("failed to initialize logging")?; Ok(VeilidLogs { inner: Arc::new(Mutex::new(VeilidLogsInner {