This commit is contained in:
John Smith
2022-11-26 16:17:30 -05:00
parent 25ace50d45
commit 5df46aecae
76 changed files with 3107 additions and 3127 deletions

View File

@@ -0,0 +1,284 @@
use super::*;
/////////////////////////////////////////////////////////////////////////////////////////////////////
struct VeilidAPIInner {
context: Option<VeilidCoreContext>,
}
impl fmt::Debug for VeilidAPIInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "VeilidAPIInner")
}
}
impl Drop for VeilidAPIInner {
fn drop(&mut self) {
if let Some(context) = self.context.take() {
intf::spawn_detached(api_shutdown(context));
}
}
}
#[derive(Clone, Debug)]
pub struct VeilidAPI {
inner: Arc<Mutex<VeilidAPIInner>>,
}
impl VeilidAPI {
#[instrument(skip_all)]
pub(crate) fn new(context: VeilidCoreContext) -> Self {
Self {
inner: Arc::new(Mutex::new(VeilidAPIInner {
context: Some(context),
})),
}
}
#[instrument(skip_all)]
pub async fn shutdown(self) {
let context = { self.inner.lock().context.take() };
if let Some(context) = context {
api_shutdown(context).await;
}
}
pub fn is_shutdown(&self) -> bool {
self.inner.lock().context.is_none()
}
////////////////////////////////////////////////////////////////
// Accessors
pub fn config(&self) -> Result<VeilidConfig, VeilidAPIError> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
return Ok(context.config.clone());
}
Err(VeilidAPIError::NotInitialized)
}
pub fn crypto(&self) -> Result<Crypto, VeilidAPIError> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
return Ok(context.crypto.clone());
}
Err(VeilidAPIError::NotInitialized)
}
pub fn table_store(&self) -> Result<TableStore, VeilidAPIError> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
return Ok(context.table_store.clone());
}
Err(VeilidAPIError::not_initialized())
}
pub fn block_store(&self) -> Result<BlockStore, VeilidAPIError> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
return Ok(context.block_store.clone());
}
Err(VeilidAPIError::not_initialized())
}
pub fn protected_store(&self) -> Result<ProtectedStore, VeilidAPIError> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
return Ok(context.protected_store.clone());
}
Err(VeilidAPIError::not_initialized())
}
pub fn attachment_manager(&self) -> Result<AttachmentManager, VeilidAPIError> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
return Ok(context.attachment_manager.clone());
}
Err(VeilidAPIError::not_initialized())
}
pub fn network_manager(&self) -> Result<NetworkManager, VeilidAPIError> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
return Ok(context.attachment_manager.network_manager());
}
Err(VeilidAPIError::not_initialized())
}
pub fn rpc_processor(&self) -> Result<RPCProcessor, VeilidAPIError> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
return Ok(context.attachment_manager.network_manager().rpc_processor());
}
Err(VeilidAPIError::NotInitialized)
}
pub fn routing_table(&self) -> Result<RoutingTable, VeilidAPIError> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
return Ok(context.attachment_manager.network_manager().routing_table());
}
Err(VeilidAPIError::NotInitialized)
}
////////////////////////////////////////////////////////////////
// Attach/Detach
// get a full copy of the current state
pub async fn get_state(&self) -> Result<VeilidState, VeilidAPIError> {
let attachment_manager = self.attachment_manager()?;
let network_manager = attachment_manager.network_manager();
let config = self.config()?;
let attachment = attachment_manager.get_veilid_state();
let network = network_manager.get_veilid_state();
let config = config.get_veilid_state();
Ok(VeilidState {
attachment,
network,
config,
})
}
// get network connectedness
// connect to the network
#[instrument(level = "debug", err, skip_all)]
pub async fn attach(&self) -> Result<(), VeilidAPIError> {
let attachment_manager = self.attachment_manager()?;
attachment_manager
.request_attach()
.await
.map_err(|e| VeilidAPIError::internal(e))
}
// disconnect from the network
#[instrument(level = "debug", err, skip_all)]
pub async fn detach(&self) -> Result<(), VeilidAPIError> {
let attachment_manager = self.attachment_manager()?;
attachment_manager
.request_detach()
.await
.map_err(|e| VeilidAPIError::internal(e))
}
////////////////////////////////////////////////////////////////
// Routing Context
#[instrument(level = "debug", skip(self))]
pub fn routing_context(&self) -> RoutingContext {
RoutingContext::new(self.clone())
}
////////////////////////////////////////////////////////////////
// Private route allocation
#[instrument(level = "debug", skip(self))]
pub async fn new_private_route(&self) -> Result<(DHTKey, Vec<u8>), VeilidAPIError> {
self.new_custom_private_route(Stability::default(), Sequencing::default())
.await
}
#[instrument(level = "debug", skip(self))]
pub async fn new_custom_private_route(
&self,
stability: Stability,
sequencing: Sequencing,
) -> Result<(DHTKey, Vec<u8>), VeilidAPIError> {
let default_route_hop_count: usize = {
let config = self.config()?;
let c = config.get();
c.network.rpc.default_route_hop_count.into()
};
let rss = self.routing_table()?.route_spec_store();
let r = rss
.allocate_route(
stability,
sequencing,
default_route_hop_count,
Direction::Inbound.into(),
&[],
)
.map_err(VeilidAPIError::internal)?;
let Some(pr_pubkey) = r else {
apibail_generic!("unable to allocate route");
};
if !rss
.test_route(&pr_pubkey)
.await
.map_err(VeilidAPIError::no_connection)?
{
rss.release_route(&pr_pubkey);
apibail_generic!("allocated route failed to test");
}
let private_route = rss
.assemble_private_route(&pr_pubkey, Some(true))
.map_err(VeilidAPIError::generic)?;
let blob = match RouteSpecStore::private_route_to_blob(&private_route) {
Ok(v) => v,
Err(e) => {
rss.release_route(&pr_pubkey);
apibail_internal!(e);
}
};
rss.mark_route_published(&pr_pubkey, true)
.map_err(VeilidAPIError::internal)?;
Ok((pr_pubkey, blob))
}
#[instrument(level = "debug", skip(self))]
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> Result<DHTKey, VeilidAPIError> {
let rss = self.routing_table()?.route_spec_store();
rss.import_remote_private_route(blob)
.map_err(|e| VeilidAPIError::invalid_argument(e, "blob", "private route blob"))
}
#[instrument(level = "debug", skip(self))]
pub fn release_private_route(&self, key: &DHTKey) -> Result<(), VeilidAPIError> {
let rss = self.routing_table()?.route_spec_store();
if rss.release_route(key) {
Ok(())
} else {
Err(VeilidAPIError::invalid_argument(
"release_private_route",
"key",
key,
))
}
}
////////////////////////////////////////////////////////////////
// App Calls
#[instrument(level = "debug", skip(self))]
pub async fn app_call_reply(&self, id: u64, message: Vec<u8>) -> Result<(), VeilidAPIError> {
let rpc_processor = self.rpc_processor()?;
rpc_processor
.app_call_reply(id, message)
.await
.map_err(|e| e.into())
}
////////////////////////////////////////////////////////////////
// Tunnel Building
#[instrument(level = "debug", err, skip(self))]
pub async fn start_tunnel(
&self,
_endpoint_mode: TunnelMode,
_depth: u8,
) -> Result<PartialTunnel, VeilidAPIError> {
panic!("unimplemented");
}
#[instrument(level = "debug", err, skip(self))]
pub async fn complete_tunnel(
&self,
_endpoint_mode: TunnelMode,
_depth: u8,
_partial_tunnel: PartialTunnel,
) -> Result<FullTunnel, VeilidAPIError> {
panic!("unimplemented");
}
#[instrument(level = "debug", err, skip(self))]
pub async fn cancel_tunnel(&self, _tunnel_id: TunnelId) -> Result<bool, VeilidAPIError> {
panic!("unimplemented");
}
}

View File

@@ -276,15 +276,10 @@ fn get_debug_argument<T, G: FnOnce(&str) -> Option<T>>(
argument: &str,
getter: G,
) -> Result<T, VeilidAPIError> {
if let Some(val) = getter(value) {
Ok(val)
} else {
Err(VeilidAPIError::InvalidArgument {
context: context.to_owned(),
argument: argument.to_owned(),
value: value.to_owned(),
})
}
let Some(val) = getter(value) else {
apibail_invalid_argument!(context, argument, value);
};
Ok(val)
}
fn get_debug_argument_at<T, G: FnOnce(&str) -> Option<T>>(
debug_args: &[String],
@@ -294,21 +289,13 @@ fn get_debug_argument_at<T, G: FnOnce(&str) -> Option<T>>(
getter: G,
) -> Result<T, VeilidAPIError> {
if pos >= debug_args.len() {
return Err(VeilidAPIError::MissingArgument {
context: context.to_owned(),
argument: argument.to_owned(),
});
apibail_missing_argument!(context, argument);
}
let value = &debug_args[pos];
if let Some(val) = getter(value) {
Ok(val)
} else {
Err(VeilidAPIError::InvalidArgument {
context: context.to_owned(),
argument: argument.to_owned(),
value: value.to_owned(),
})
}
let Some(val) = getter(value) else {
apibail_invalid_argument!(context, argument, value);
};
Ok(val)
}
impl VeilidAPI {
@@ -351,11 +338,7 @@ impl VeilidAPI {
} else if let Some(lim) = get_number(&arg) {
limit = lim;
} else {
return Err(VeilidAPIError::InvalidArgument {
context: "debug_entries".to_owned(),
argument: "unknown".to_owned(),
value: arg,
});
apibail_invalid_argument!("debug_entries", "unknown", arg);
}
}
@@ -412,7 +395,7 @@ impl VeilidAPI {
async fn debug_restart(&self, args: String) -> Result<String, VeilidAPIError> {
let args = args.trim_start();
if args.is_empty() {
return Err(VeilidAPIError::missing_argument("debug_restart", "arg_0"));
apibail_missing_argument!("debug_restart", "arg_0");
}
let (arg, _rest) = args.split_once(' ').unwrap_or((args, ""));
// let rest = rest.trim_start().to_owned();
@@ -431,11 +414,7 @@ impl VeilidAPI {
Ok("Network restarted".to_owned())
} else {
Err(VeilidAPIError::invalid_argument(
"debug_restart",
"arg_1",
arg,
))
apibail_invalid_argument!("debug_restart", "arg_1", arg);
}
}
@@ -654,11 +633,7 @@ impl VeilidAPI {
if full_val == "full" {
true
} else {
return Err(VeilidAPIError::invalid_argument(
"debug_route",
"full",
full_val,
));
apibail_invalid_argument!("debug_route", "full", full_val);
}
} else {
false

View File

@@ -0,0 +1,186 @@
use super::*;
#[allow(unused_macros)]
#[macro_export]
macro_rules! apibail_timeout {
() => {
return Err(VeilidAPIError::timeout())
};
}
#[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_error {
($x:expr, $y:expr) => {
return Err(VeilidAPIError::parse_error($x, $y))
};
}
#[allow(unused_macros)]
#[macro_export]
macro_rules! apibail_missing_argument {
($x:expr, $y:expr) => {
return Err(VeilidAPIError::missing_argument($x, $y))
};
}
#[allow(unused_macros)]
#[macro_export]
macro_rules! apibail_invalid_argument {
($x:expr, $y:expr, $z:expr) => {
return Err(VeilidAPIError::invalid_argument($x, $y, $z))
};
}
#[allow(unused_macros)]
#[macro_export]
macro_rules! apibail_no_connection {
($x:expr) => {
return Err(VeilidAPIError::no_connection($x))
};
}
#[allow(unused_macros)]
#[macro_export]
macro_rules! apibail_key_not_found {
($x:expr) => {
return Err(VeilidAPIError::key_not_found($x))
};
}
#[allow(unused_macros)]
#[macro_export]
macro_rules! apibail_already_initialized {
() => {
return Err(VeilidAPIError::already_initialized())
};
}
#[derive(
ThisError,
Clone,
Debug,
PartialOrd,
PartialEq,
Eq,
Ord,
Serialize,
Deserialize,
RkyvArchive,
RkyvSerialize,
RkyvDeserialize,
)]
#[archive_attr(repr(u8), derive(CheckBytes))]
#[serde(tag = "kind")]
pub enum VeilidAPIError {
#[error("Not initialized")]
NotInitialized,
#[error("Already initialized")]
AlreadyInitialized,
#[error("Timeout")]
Timeout,
#[error("Shutdown")]
Shutdown,
#[error("Key not found: {key}")]
KeyNotFound { key: DHTKey },
#[error("No connection: {message}")]
NoConnection { message: String },
#[error("No peer info: {node_id}")]
NoPeerInfo { node_id: NodeId },
#[error("Internal: {message}")]
Internal { message: String },
#[error("Unimplemented: {message}")]
Unimplemented { message: String },
#[error("Parse error: '{message}' with value '{value}'")]
ParseError { message: String, value: String },
#[error("Invalid argument: '{argument}' for '{context}' with value '{value}'")]
InvalidArgument {
context: String,
argument: String,
value: String,
},
#[error("Missing argument: '{argument}' for '{context}'")]
MissingArgument { context: String, argument: String },
#[error("Generic: {message}")]
Generic { message: String },
}
impl VeilidAPIError {
pub fn not_initialized() -> Self {
Self::NotInitialized
}
pub fn already_initialized() -> Self {
Self::AlreadyInitialized
}
pub fn timeout() -> Self {
Self::Timeout
}
pub fn shutdown() -> Self {
Self::Shutdown
}
pub fn key_not_found(key: DHTKey) -> Self {
Self::KeyNotFound { key }
}
pub fn no_connection<T: ToString>(msg: T) -> Self {
Self::NoConnection {
message: msg.to_string(),
}
}
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(),
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
use super::*;
///////////////////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug)]
@@ -106,7 +107,7 @@ impl RoutingContext {
// Resolve node
let mut nr = match rpc_processor.resolve_node(node_id.key).await {
Ok(Some(nr)) => nr,
Ok(None) => return Err(VeilidAPIError::KeyNotFound { key: node_id.key }),
Ok(None) => apibail_key_not_found!(node_id.key),
Err(e) => return Err(e.into()),
};
// Apply sequencing to match safety selection
@@ -123,7 +124,7 @@ impl RoutingContext {
let Some(private_route) = rss
.get_remote_private_route(&pr)
else {
return Err(VeilidAPIError::KeyNotFound { key: pr });
apibail_key_not_found!(pr);
};
Ok(rpc_processor::Destination::PrivateRoute {
@@ -151,15 +152,13 @@ impl RoutingContext {
// Send app message
let answer = match rpc_processor.rpc_call_app_call(dest, request).await {
Ok(NetworkResult::Value(v)) => v,
Ok(NetworkResult::Timeout) => return Err(VeilidAPIError::Timeout),
Ok(NetworkResult::Timeout) => apibail_timeout!(),
Ok(NetworkResult::NoConnection(e)) | Ok(NetworkResult::AlreadyExists(e)) => {
return Err(VeilidAPIError::NoConnection {
message: e.to_string(),
})
apibail_no_connection!(e);
}
Ok(NetworkResult::InvalidMessage(message)) => {
return Err(VeilidAPIError::Generic { message })
apibail_generic!(message);
}
Err(e) => return Err(e.into()),
};
@@ -181,14 +180,12 @@ impl RoutingContext {
// Send app message
match rpc_processor.rpc_call_app_message(dest, message).await {
Ok(NetworkResult::Value(())) => {}
Ok(NetworkResult::Timeout) => return Err(VeilidAPIError::Timeout),
Ok(NetworkResult::Timeout) => apibail_timeout!(),
Ok(NetworkResult::NoConnection(e)) | Ok(NetworkResult::AlreadyExists(e)) => {
return Err(VeilidAPIError::NoConnection {
message: e.to_string(),
})
apibail_no_connection!(e);
}
Ok(NetworkResult::InvalidMessage(message)) => {
return Err(VeilidAPIError::Generic { message })
apibail_generic!(message);
}
Err(e) => return Err(e.into()),
};

File diff suppressed because it is too large Load Diff