eyre work

This commit is contained in:
John Smith
2022-07-06 23:15:51 -04:00
parent 2f05611170
commit cd0cd78e30
21 changed files with 345 additions and 229 deletions

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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<u8>) -> Result<Self, String> {
pub fn try_from_vec(v: Vec<u8>) -> Result<Self, VeilidAPIError> {
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<Self, String> {
pub fn try_decode(input: &str) -> Result<Self, VeilidAPIError> {
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<String> for $name {
type Error = String;
type Error = VeilidAPIError;
fn try_from(value: String) -> Result<Self, Self::Error> {
$name::try_from(value.as_str())
}
}
impl TryFrom<&str> for $name {
type Error = String;
type Error = VeilidAPIError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
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<DHTSignature, String> {
) -> Result<DHTSignature, VeilidAPIError> {
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(())
}

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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
)
})?
};

View File

@@ -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,
};

View File

@@ -10,17 +10,20 @@ pub enum RPCError {
Internal(String),
}
pub fn rpc_error_internal<T: AsRef<str>>(x: T) -> RPCError {
error!("RPCError Internal: {}", x.as_ref());
RPCError::Internal(x.as_ref().to_owned())
pub fn rpc_error_internal<T: ToString>(x: T) -> RPCError {
let x = x.to_string();
error!("RPCError Internal: {}", x);
RPCError::Internal(x)
}
pub fn rpc_error_invalid_format<T: AsRef<str>>(x: T) -> RPCError {
error!("RPCError Invalid Format: {}", x.as_ref());
RPCError::InvalidFormat(x.as_ref().to_owned())
pub fn rpc_error_invalid_format<T: ToString>(x: T) -> RPCError {
let x = x.to_string();
error!("RPCError Invalid Format: {}", x);
RPCError::InvalidFormat(x)
}
pub fn rpc_error_protocol<T: AsRef<str>>(x: T) -> RPCError {
error!("RPCError Protocol: {}", x.as_ref());
RPCError::Protocol(x.as_ref().to_owned())
pub fn rpc_error_protocol<T: ToString>(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<T: AsRef<str>>(x: T) -> RPCError {
error!("RPCError Unimplemented: {}", x.as_ref());
RPCError::Unimplemented(x.as_ref().to_owned())
pub fn rpc_error_unimplemented<T: ToString>(x: T) -> RPCError {
let x = x.to_string();
error!("RPCError Unimplemented: {}", x);
RPCError::Unimplemented(x)
}
impl fmt::Display for RPCError {

View File

@@ -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)
}
}
}

View File

@@ -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?;

View File

@@ -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<T: ToString>(msg: T) -> Self {
Self::Internal {
message: msg.to_string(),
}
}
pub fn unimplemented<T: ToString>(msg: T) -> Self {
Self::Unimplemented {
message: msg.to_string(),
}
}
pub fn parse_error<T: ToString, S: ToString>(msg: T, value: S) -> Self {
Self::ParseError {
message: msg.to_string(),
value: value.to_string(),
}
}
pub fn invalid_argument<T: ToString, S: ToString, R: ToString>(
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<T: ToString, S: ToString>(context: T, argument: S) -> Self {
Self::MissingArgument {
context: context.to_string(),
argument: argument.to_string(),
}
}
pub fn generic<T: ToString>(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<Self, String> {
let mut node_info_bytes = serde_cbor::to_vec(&node_info).map_err(map_to_string)?;
let mut timestamp_bytes = serde_cbor::to_vec(&timestamp).map_err(map_to_string)?;
) -> Result<Self, VeilidAPIError> {
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(&timestamp)
.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<Self, String> {
) -> Result<Self, VeilidAPIError> {
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(&timestamp).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(&timestamp)
.map_err(mapapierr_parse!("failed to encode timestamp as cbor"))?;
node_info_bytes.append(&mut timestamp_bytes);

View File

@@ -5,11 +5,11 @@ use serde::*;
////////////////////////////////////////////////////////////////////////////////////////////////
cfg_if! {
if #[cfg(target_arch = "wasm32")] {
pub type ConfigCallbackReturn = Result<Box<dyn core::any::Any>, String>;
pub type ConfigCallbackReturn = Result<Box<dyn core::any::Any>, VeilidAPIError>;
pub type ConfigCallback = Arc<dyn Fn(String) -> ConfigCallbackReturn>;
} else {
pub type ConfigCallbackReturn = Result<Box<dyn core::any::Any + Send>, String>;
pub type ConfigCallbackReturn = Result<Box<dyn core::any::Any + Send>, VeilidAPIError>;
pub type ConfigCallback = Arc<dyn Fn(String) -> 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<String, String> {
pub fn get_key_json(&self, key: &str) -> Result<String, VeilidAPIError> {
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;