2022-11-26 16:17:30 -05:00
|
|
|
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() {
|
2022-11-26 21:37:23 -05:00
|
|
|
spawn_detached(api_shutdown(context));
|
2022-11-26 16:17:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-29 16:15:47 -04:00
|
|
|
/// The primary developer entrypoint into `veilid-core` functionality
|
|
|
|
///
|
|
|
|
/// From [VeilidAPI] one can access:
|
|
|
|
///
|
|
|
|
/// * [VeilidConfig] - The Veilid configuration specified by at startup time
|
|
|
|
/// * [Crypto] - The available set of cryptosystems provided by Veilid
|
|
|
|
/// * [TableStore] - The Veilid table-based encrypted persistent key-value store
|
|
|
|
/// * [ProtectedStore] - The Veilid abstract of the device's low-level 'protected secret storage'
|
|
|
|
/// * [VeilidState] - The current state of the Veilid node this API accesses
|
|
|
|
/// * [RoutingContext] - Communication methods between Veilid nodes and private routes
|
|
|
|
/// * Attach and detach from the network
|
|
|
|
/// * Create and import private routes
|
|
|
|
/// * Reply to `AppCall` RPCs
|
2022-11-26 16:17:30 -05:00
|
|
|
#[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()
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
2023-08-29 16:15:47 -04:00
|
|
|
// Public Accessors
|
|
|
|
|
2023-05-29 15:24:57 -04:00
|
|
|
pub fn config(&self) -> VeilidAPIResult<VeilidConfig> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let inner = self.inner.lock();
|
|
|
|
if let Some(context) = &inner.context {
|
|
|
|
return Ok(context.config.clone());
|
|
|
|
}
|
|
|
|
Err(VeilidAPIError::NotInitialized)
|
|
|
|
}
|
2023-05-29 15:24:57 -04:00
|
|
|
pub fn crypto(&self) -> VeilidAPIResult<Crypto> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let inner = self.inner.lock();
|
|
|
|
if let Some(context) = &inner.context {
|
|
|
|
return Ok(context.crypto.clone());
|
|
|
|
}
|
|
|
|
Err(VeilidAPIError::NotInitialized)
|
|
|
|
}
|
2023-05-29 15:24:57 -04:00
|
|
|
pub fn table_store(&self) -> VeilidAPIResult<TableStore> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let inner = self.inner.lock();
|
|
|
|
if let Some(context) = &inner.context {
|
|
|
|
return Ok(context.table_store.clone());
|
|
|
|
}
|
|
|
|
Err(VeilidAPIError::not_initialized())
|
|
|
|
}
|
2023-05-29 15:24:57 -04:00
|
|
|
pub fn protected_store(&self) -> VeilidAPIResult<ProtectedStore> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let inner = self.inner.lock();
|
|
|
|
if let Some(context) = &inner.context {
|
|
|
|
return Ok(context.protected_store.clone());
|
|
|
|
}
|
|
|
|
Err(VeilidAPIError::not_initialized())
|
|
|
|
}
|
2023-08-29 16:15:47 -04:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Internal Accessors
|
|
|
|
pub(crate) fn attachment_manager(&self) -> VeilidAPIResult<AttachmentManager> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let inner = self.inner.lock();
|
|
|
|
if let Some(context) = &inner.context {
|
|
|
|
return Ok(context.attachment_manager.clone());
|
|
|
|
}
|
|
|
|
Err(VeilidAPIError::not_initialized())
|
|
|
|
}
|
2023-08-29 16:15:47 -04:00
|
|
|
pub(crate) fn network_manager(&self) -> VeilidAPIResult<NetworkManager> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let inner = self.inner.lock();
|
|
|
|
if let Some(context) = &inner.context {
|
|
|
|
return Ok(context.attachment_manager.network_manager());
|
|
|
|
}
|
|
|
|
Err(VeilidAPIError::not_initialized())
|
|
|
|
}
|
2023-08-29 16:15:47 -04:00
|
|
|
pub(crate) fn rpc_processor(&self) -> VeilidAPIResult<RPCProcessor> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let inner = self.inner.lock();
|
|
|
|
if let Some(context) = &inner.context {
|
|
|
|
return Ok(context.attachment_manager.network_manager().rpc_processor());
|
|
|
|
}
|
|
|
|
Err(VeilidAPIError::NotInitialized)
|
|
|
|
}
|
2023-08-29 16:15:47 -04:00
|
|
|
pub(crate) fn routing_table(&self) -> VeilidAPIResult<RoutingTable> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let inner = self.inner.lock();
|
|
|
|
if let Some(context) = &inner.context {
|
|
|
|
return Ok(context.attachment_manager.network_manager().routing_table());
|
|
|
|
}
|
|
|
|
Err(VeilidAPIError::NotInitialized)
|
|
|
|
}
|
2023-08-29 16:15:47 -04:00
|
|
|
pub(crate) fn storage_manager(&self) -> VeilidAPIResult<StorageManager> {
|
2023-05-29 15:24:57 -04:00
|
|
|
let inner = self.inner.lock();
|
|
|
|
if let Some(context) = &inner.context {
|
|
|
|
return Ok(context.storage_manager.clone());
|
|
|
|
}
|
|
|
|
Err(VeilidAPIError::NotInitialized)
|
|
|
|
}
|
2023-08-29 16:15:47 -04:00
|
|
|
#[cfg(feature = "unstable-blockstore")]
|
|
|
|
pub(crate) fn block_store(&self) -> VeilidAPIResult<BlockStore> {
|
|
|
|
let inner = self.inner.lock();
|
|
|
|
if let Some(context) = &inner.context {
|
|
|
|
return Ok(context.block_store.clone());
|
|
|
|
}
|
|
|
|
Err(VeilidAPIError::not_initialized())
|
|
|
|
}
|
2022-11-26 16:17:30 -05:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Attach/Detach
|
|
|
|
|
2023-02-17 17:47:21 -05:00
|
|
|
/// Get a full copy of the current state
|
2023-05-29 15:24:57 -04:00
|
|
|
pub async fn get_state(&self) -> VeilidAPIResult<VeilidState> {
|
2022-11-26 16:17:30 -05:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-02-17 17:47:21 -05:00
|
|
|
/// Connect to the network
|
2023-05-29 15:24:57 -04:00
|
|
|
pub async fn attach(&self) -> VeilidAPIResult<()> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let attachment_manager = self.attachment_manager()?;
|
2022-12-26 16:33:48 -05:00
|
|
|
if !attachment_manager.attach().await {
|
|
|
|
apibail_generic!("Already attached");
|
|
|
|
}
|
|
|
|
Ok(())
|
2022-11-26 16:17:30 -05:00
|
|
|
}
|
|
|
|
|
2023-02-17 17:47:21 -05:00
|
|
|
/// Disconnect from the network
|
2023-05-29 15:24:57 -04:00
|
|
|
pub async fn detach(&self) -> VeilidAPIResult<()> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let attachment_manager = self.attachment_manager()?;
|
2022-12-26 16:33:48 -05:00
|
|
|
if !attachment_manager.detach().await {
|
|
|
|
apibail_generic!("Already detached");
|
|
|
|
}
|
|
|
|
Ok(())
|
2022-11-26 16:17:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Routing Context
|
|
|
|
|
2023-08-29 16:15:47 -04:00
|
|
|
/// Get a new `RoutingContext` object to use to send messages over the Veilid network.
|
2022-11-26 16:17:30 -05:00
|
|
|
pub fn routing_context(&self) -> RoutingContext {
|
|
|
|
RoutingContext::new(self.clone())
|
|
|
|
}
|
|
|
|
|
2023-08-29 16:15:47 -04:00
|
|
|
/// Parse a string into a target object that can be used in a [RoutingContext]
|
|
|
|
///
|
|
|
|
/// Strings are in base64url format and can either be a remote route id or a node id.
|
|
|
|
/// Strings may have a [CryptoKind] [FourCC] prefix separated by a colon, such as:
|
|
|
|
/// `VLD0:XmnGyJrjMJBRC5ayJZRPXWTBspdX36-pbLb98H3UMeE` but if the prefix is left off
|
|
|
|
/// `XmnGyJrjMJBRC5ayJZRPXWTBspdX36-pbLb98H3UMeE` will be parsed with the 'best' cryptosystem
|
|
|
|
/// available (at the time of this writing this is `VLD0`)
|
|
|
|
pub async fn parse_as_target<S: AsRef<str>>(&self, s: S) -> VeilidAPIResult<Target> {
|
|
|
|
// Is this a route id?
|
|
|
|
if let Ok(rrid) = RouteId::from_str(s.as_ref()) {
|
|
|
|
let routing_table = self.routing_table()?;
|
|
|
|
let rss = routing_table.route_spec_store();
|
|
|
|
|
|
|
|
// Is this a valid remote route id? (can't target allocated routes)
|
|
|
|
if rss.is_route_id_remote(&rrid) {
|
|
|
|
return Ok(Target::PrivateRoute(rrid));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Is this a node id?
|
|
|
|
if let Ok(nid) = TypedKey::from_str(s.as_ref()) {
|
|
|
|
return Ok(Target::NodeId(nid));
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(VeilidAPIError::invalid_target())
|
|
|
|
}
|
|
|
|
|
2022-11-26 16:17:30 -05:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Private route allocation
|
|
|
|
|
2023-02-17 17:47:21 -05:00
|
|
|
/// Allocate a new private route set with default cryptography and network options
|
2023-02-25 22:02:13 -05:00
|
|
|
/// Returns a route id and a publishable 'blob' with the route encrypted with each crypto kind
|
2023-02-20 20:37:52 -05:00
|
|
|
/// Those nodes importing the blob will have their choice of which crypto kind to use
|
2023-05-29 15:24:57 -04:00
|
|
|
pub async fn new_private_route(&self) -> VeilidAPIResult<(RouteId, Vec<u8>)> {
|
2023-02-15 18:18:08 -05:00
|
|
|
self.new_custom_private_route(
|
|
|
|
&VALID_CRYPTO_KINDS,
|
|
|
|
Stability::default(),
|
|
|
|
Sequencing::default(),
|
|
|
|
)
|
|
|
|
.await
|
2022-11-26 16:17:30 -05:00
|
|
|
}
|
|
|
|
|
2023-02-17 17:47:21 -05:00
|
|
|
///
|
2022-11-26 16:17:30 -05:00
|
|
|
pub async fn new_custom_private_route(
|
|
|
|
&self,
|
2023-02-15 18:18:08 -05:00
|
|
|
crypto_kinds: &[CryptoKind],
|
2022-11-26 16:17:30 -05:00
|
|
|
stability: Stability,
|
|
|
|
sequencing: Sequencing,
|
2023-05-29 15:24:57 -04:00
|
|
|
) -> VeilidAPIResult<(RouteId, Vec<u8>)> {
|
2023-08-05 11:33:27 -04:00
|
|
|
for kind in crypto_kinds {
|
|
|
|
Crypto::validate_crypto_kind(*kind)?;
|
|
|
|
}
|
|
|
|
|
2022-11-26 16:17:30 -05:00
|
|
|
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(
|
2023-02-15 18:18:08 -05:00
|
|
|
&crypto_kinds,
|
2022-11-26 16:17:30 -05:00
|
|
|
stability,
|
|
|
|
sequencing,
|
|
|
|
default_route_hop_count,
|
|
|
|
Direction::Inbound.into(),
|
|
|
|
&[],
|
|
|
|
)
|
|
|
|
.map_err(VeilidAPIError::internal)?;
|
2023-02-25 22:02:13 -05:00
|
|
|
let Some(route_id) = r else {
|
2022-11-26 16:17:30 -05:00
|
|
|
apibail_generic!("unable to allocate route");
|
|
|
|
};
|
|
|
|
if !rss
|
2023-02-25 22:02:13 -05:00
|
|
|
.test_route(route_id.clone())
|
2022-11-26 16:17:30 -05:00
|
|
|
.await
|
|
|
|
.map_err(VeilidAPIError::no_connection)?
|
|
|
|
{
|
2023-02-25 22:02:13 -05:00
|
|
|
rss.release_route(route_id);
|
2022-11-26 16:17:30 -05:00
|
|
|
apibail_generic!("allocated route failed to test");
|
|
|
|
}
|
2023-02-25 22:02:13 -05:00
|
|
|
let private_routes = rss
|
|
|
|
.assemble_private_routes(&route_id, Some(true))
|
2022-11-26 16:17:30 -05:00
|
|
|
.map_err(VeilidAPIError::generic)?;
|
2023-02-25 22:02:13 -05:00
|
|
|
let blob = match RouteSpecStore::private_routes_to_blob(&private_routes) {
|
2022-11-26 16:17:30 -05:00
|
|
|
Ok(v) => v,
|
|
|
|
Err(e) => {
|
2023-02-25 22:02:13 -05:00
|
|
|
rss.release_route(route_id);
|
2022-11-26 16:17:30 -05:00
|
|
|
apibail_internal!(e);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-02-25 22:02:13 -05:00
|
|
|
rss.mark_route_published(&route_id, true)
|
2022-11-26 16:17:30 -05:00
|
|
|
.map_err(VeilidAPIError::internal)?;
|
|
|
|
|
2023-02-25 22:02:13 -05:00
|
|
|
Ok((route_id, blob))
|
2022-11-26 16:17:30 -05:00
|
|
|
}
|
|
|
|
|
2023-05-29 15:24:57 -04:00
|
|
|
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> VeilidAPIResult<RouteId> {
|
2022-11-26 16:17:30 -05:00
|
|
|
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"))
|
|
|
|
}
|
|
|
|
|
2023-05-29 15:24:57 -04:00
|
|
|
pub fn release_private_route(&self, route_id: RouteId) -> VeilidAPIResult<()> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let rss = self.routing_table()?.route_spec_store();
|
2023-02-25 22:02:13 -05:00
|
|
|
if !rss.release_route(route_id) {
|
|
|
|
apibail_invalid_argument!("release_private_route", "key", route_id);
|
2022-11-26 16:17:30 -05:00
|
|
|
}
|
2023-02-25 22:02:13 -05:00
|
|
|
Ok(())
|
2022-11-26 16:17:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// App Calls
|
|
|
|
|
2023-06-16 11:57:55 -04:00
|
|
|
pub async fn app_call_reply(
|
|
|
|
&self,
|
|
|
|
call_id: OperationId,
|
|
|
|
message: Vec<u8>,
|
|
|
|
) -> VeilidAPIResult<()> {
|
2022-11-26 16:17:30 -05:00
|
|
|
let rpc_processor = self.rpc_processor()?;
|
|
|
|
rpc_processor
|
2023-06-16 11:57:55 -04:00
|
|
|
.app_call_reply(call_id, message)
|
2022-11-26 16:17:30 -05:00
|
|
|
.await
|
|
|
|
.map_err(|e| e.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Tunnel Building
|
|
|
|
|
2023-06-03 18:33:27 -04:00
|
|
|
#[cfg(feature = "unstable-tunnels")]
|
2022-11-26 16:17:30 -05:00
|
|
|
pub async fn start_tunnel(
|
|
|
|
&self,
|
|
|
|
_endpoint_mode: TunnelMode,
|
|
|
|
_depth: u8,
|
2023-05-29 15:24:57 -04:00
|
|
|
) -> VeilidAPIResult<PartialTunnel> {
|
2022-11-26 16:17:30 -05:00
|
|
|
panic!("unimplemented");
|
|
|
|
}
|
|
|
|
|
2023-06-03 18:33:27 -04:00
|
|
|
#[cfg(feature = "unstable-tunnels")]
|
2022-11-26 16:17:30 -05:00
|
|
|
pub async fn complete_tunnel(
|
|
|
|
&self,
|
|
|
|
_endpoint_mode: TunnelMode,
|
|
|
|
_depth: u8,
|
|
|
|
_partial_tunnel: PartialTunnel,
|
2023-05-29 15:24:57 -04:00
|
|
|
) -> VeilidAPIResult<FullTunnel> {
|
2022-11-26 16:17:30 -05:00
|
|
|
panic!("unimplemented");
|
|
|
|
}
|
|
|
|
|
2023-06-03 18:33:27 -04:00
|
|
|
#[cfg(feature = "unstable-tunnels")]
|
2023-05-29 15:24:57 -04:00
|
|
|
pub async fn cancel_tunnel(&self, _tunnel_id: TunnelId) -> VeilidAPIResult<bool> {
|
2022-11-26 16:17:30 -05:00
|
|
|
panic!("unimplemented");
|
|
|
|
}
|
|
|
|
}
|