This commit is contained in:
Christien Rioux
2023-09-01 21:13:05 -04:00
parent c377a59278
commit 246056913e
12 changed files with 172 additions and 52 deletions

View File

@@ -48,6 +48,7 @@ impl VeilidAPI {
}
}
/// Shut down Veilid and terminate the API
#[instrument(skip_all)]
pub async fn shutdown(self) {
let context = { self.inner.lock().context.take() };
@@ -56,6 +57,7 @@ impl VeilidAPI {
}
}
/// Check to see if Veilid is already shut down
pub fn is_shutdown(&self) -> bool {
self.inner.lock().context.is_none()
}
@@ -63,6 +65,7 @@ impl VeilidAPI {
////////////////////////////////////////////////////////////////
// Public Accessors
/// Access the configuration that Veilid was initialized with
pub fn config(&self) -> VeilidAPIResult<VeilidConfig> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
@@ -70,6 +73,8 @@ impl VeilidAPI {
}
Err(VeilidAPIError::NotInitialized)
}
/// Get the cryptosystem manager
pub fn crypto(&self) -> VeilidAPIResult<Crypto> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
@@ -77,6 +82,8 @@ impl VeilidAPI {
}
Err(VeilidAPIError::NotInitialized)
}
/// Get the TableStore manager
pub fn table_store(&self) -> VeilidAPIResult<TableStore> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
@@ -84,6 +91,8 @@ impl VeilidAPI {
}
Err(VeilidAPIError::not_initialized())
}
/// Get the ProtectedStore manager
pub fn protected_store(&self) -> VeilidAPIResult<ProtectedStore> {
let inner = self.inner.lock();
if let Some(context) = &inner.context {
@@ -141,7 +150,7 @@ impl VeilidAPI {
////////////////////////////////////////////////////////////////
// Attach/Detach
/// Get a full copy of the current state
/// Get a full copy of the current state of Veilid
pub async fn get_state(&self) -> VeilidAPIResult<VeilidState> {
let attachment_manager = self.attachment_manager()?;
let network_manager = attachment_manager.network_manager();
@@ -217,6 +226,9 @@ impl VeilidAPI {
/// Allocate a new private route set with default cryptography and network options
/// Returns a route id and a publishable 'blob' with the route encrypted with each crypto kind
/// Those nodes importing the blob will have their choice of which crypto kind to use
///
/// Returns a route id and 'blob' that can be published over some means (DHT or otherwise) to be
/// imported by another Veilid node.
pub async fn new_private_route(&self) -> VeilidAPIResult<(RouteId, Vec<u8>)> {
self.new_custom_private_route(
&VALID_CRYPTO_KINDS,
@@ -226,7 +238,12 @@ impl VeilidAPI {
.await
}
/// Allocate a new private route and specify a specific cryptosystem, stability and sequencing preference
/// Returns a route id and a publishable 'blob' with the route encrypted with each crypto kind
/// Those nodes importing the blob will have their choice of which crypto kind to use
///
/// Returns a route id and 'blob' that can be published over some means (DHT or otherwise) to be
/// imported by another Veilid node.
pub async fn new_custom_private_route(
&self,
crypto_kinds: &[CryptoKind],
@@ -282,12 +299,19 @@ impl VeilidAPI {
Ok((route_id, blob))
}
/// Import a private route blob as a remote private route.
///
/// Returns a route id that can be used to send private messages to the node creating this route.
pub fn import_remote_private_route(&self, blob: Vec<u8>) -> VeilidAPIResult<RouteId> {
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"))
}
/// Release either a locally allocated or remotely imported private route
///
/// This will deactivate the route and free its resources and it can no longer be sent to
/// or received from.
pub fn release_private_route(&self, route_id: RouteId) -> VeilidAPIResult<()> {
let rss = self.routing_table()?.route_spec_store();
if !rss.release_route(route_id) {
@@ -299,6 +323,10 @@ impl VeilidAPI {
////////////////////////////////////////////////////////////////
// App Calls
/// Respond to an AppCall received over a [VeilidUpdate::AppCall].
///
/// * `call_id` - specifies which call to reply to, and it comes from a [VeilidUpdate::AppCall], specifically the [VeilidAppCall::id()] value.
/// * `message` - is an answer blob to be returned by the remote node's [RoutingContext::app_call()] function, and may be up to 32768 bytes
pub async fn app_call_reply(
&self,
call_id: OperationId,

View File

@@ -1363,6 +1363,7 @@ impl VeilidAPI {
}
}
/// Get the help text for 'internal debug' commands
pub async fn debug_help(&self, _args: String) -> VeilidAPIResult<String> {
Ok(r#"buckets [dead|reliable]
dialinfo
@@ -1425,6 +1426,7 @@ record list <local|remote>
.to_owned())
}
/// Execute an 'internal debug command'
pub async fn debug(&self, args: String) -> VeilidAPIResult<String> {
let res = {
let args = args.trim_start();

View File

@@ -2,10 +2,13 @@ use super::*;
///////////////////////////////////////////////////////////////////////////////////////
/// Valid destinations for a message sent over a routing context
#[derive(Clone, Debug)]
pub enum Target {
NodeId(TypedKey), // Node by its public key
PrivateRoute(RouteId), // Remote private route by its id
/// Node by its public key
NodeId(TypedKey),
/// Remote private route by its id
PrivateRoute(RouteId),
}
pub struct RoutingContextInner {}
@@ -24,6 +27,12 @@ impl Drop for RoutingContextInner {
}
}
/// Routing contexts are the way you specify the communication preferences for Veilid.
///
/// By default routing contexts are 'direct' from node to node, offering no privacy. To enable sender
/// privacy, use [RoutingContext::with_privacy()]. To enable receiver privacy, you should send to a private route RouteId that you have
/// imported, rather than directly to a NodeId.
///
#[derive(Clone)]
pub struct RoutingContext {
/// Veilid API handle
@@ -45,6 +54,15 @@ impl RoutingContext {
}
}
/// Turn on sender privacy, enabling the use of safety routes.
///
/// Default values for hop count, stability and sequencing preferences are used.
///
/// * Hop count default is dependent on config, but is set to 1 extra hop.
/// * Stability default is to choose 'low latency' routes, preferring them over long-term reliability.
/// * Sequencing default is to have no preference for ordered vs unordered message delivery
///
/// To modify these defaults, use [RoutingContext::with_custom_privacy()].
pub fn with_privacy(self) -> VeilidAPIResult<Self> {
let config = self.api.config()?;
let c = config.get();
@@ -57,6 +75,7 @@ impl RoutingContext {
}))
}
/// Turn on privacy using a custom [SafetySelection]
pub fn with_custom_privacy(self, safety_selection: SafetySelection) -> VeilidAPIResult<Self> {
Ok(Self {
api: self.api.clone(),
@@ -65,6 +84,7 @@ impl RoutingContext {
})
}
/// Use a specified [Sequencing] preference, with or without privacy
pub fn with_sequencing(self, sequencing: Sequencing) -> Self {
Self {
api: self.api.clone(),
@@ -90,6 +110,7 @@ impl RoutingContext {
}
}
/// Get the [VeilidAPI] object that created this [RoutingContext]
pub fn api(&self) -> VeilidAPI {
self.api.clone()
}
@@ -135,6 +156,14 @@ impl RoutingContext {
////////////////////////////////////////////////////////////////
// App-level Messaging
/// App-level bidirectional call that expects a response to be returned.
///
/// Veilid apps may use this for arbitrary message passing.
///
/// * `target` - can be either a direct node id or a private route
/// * `message` - an arbitrary message blob of up to 32768 bytes
///
/// Returns an answer blob of up to 32768 bytes
pub async fn app_call(&self, target: Target, message: Vec<u8>) -> VeilidAPIResult<Vec<u8>> {
let rpc_processor = self.api.rpc_processor()?;
@@ -162,6 +191,12 @@ impl RoutingContext {
Ok(answer.answer)
}
/// App-level unidirectional message that does not expect any value to be returned.
///
/// Veilid apps may use this for arbitrary message passing.
///
/// * `target` - can be either a direct node id or a private route
/// * `message` - an arbitrary message blob of up to 32768 bytes
pub async fn app_message(&self, target: Target, message: Vec<u8>) -> VeilidAPIResult<()> {
let rpc_processor = self.api.rpc_processor()?;
@@ -192,7 +227,10 @@ impl RoutingContext {
/// DHT Records
/// Creates a new DHT record a specified crypto kind and schema
/// Returns the newly allocated DHT record's key if successful. The records is considered 'open' after the create operation succeeds.
///
/// The record is considered 'open' after the create operation succeeds.
///
/// Returns the newly allocated DHT record's key if successful.
pub async fn create_dht_record(
&self,
schema: DHTSchema,
@@ -206,9 +244,12 @@ impl RoutingContext {
.await
}
/// Opens a DHT record at a specific key. Associates a secret if one is provided to provide writer capability.
/// Opens a DHT record at a specific key
///
/// Associates a secret if one is provided to provide writer capability.
/// Records may only be opened or created. To re-open with a different routing context, first close the value.
///
/// Returns the DHT record descriptor for the opened record if successful
/// Records may only be opened or created . To re-open with a different routing context, first close the value.
pub async fn open_dht_record(
&self,
key: TypedKey,
@@ -222,6 +263,7 @@ impl RoutingContext {
}
/// Closes a DHT record at a specific key that was opened with create_dht_record or open_dht_record.
///
/// Closing a record allows you to re-open it with a different routing context
pub async fn close_dht_record(&self, key: TypedKey) -> VeilidAPIResult<()> {
Crypto::validate_crypto_kind(key.kind)?;
@@ -229,7 +271,9 @@ impl RoutingContext {
storage_manager.close_record(key).await
}
/// Deletes a DHT record at a specific key. If the record is opened, it must be closed before it is deleted.
/// Deletes a DHT record at a specific key
///
/// If the record is opened, it must be closed before it is deleted.
/// Deleting a record does not delete it from the network, but will remove the storage of the record
/// locally, and will prevent its value from being refreshed on the network by this node.
pub async fn delete_dht_record(&self, key: TypedKey) -> VeilidAPIResult<()> {
@@ -239,9 +283,11 @@ impl RoutingContext {
}
/// Gets the latest value of a subkey
///
/// May pull the latest value from the network, but by settings 'force_refresh' you can force a network data refresh
/// Returns None if the value subkey has not yet been set
/// Returns Some(data) if the value subkey has valid data
///
/// Returns `None` if the value subkey has not yet been set
/// Returns `Some(data)` if the value subkey has valid data
pub async fn get_dht_value(
&self,
key: TypedKey,
@@ -254,8 +300,9 @@ impl RoutingContext {
}
/// Pushes a changed subkey value to the network
/// Returns None if the value was successfully put
/// Returns Some(data) if the value put was older than the one available on the network
///
/// Returns `None` if the value was successfully put
/// Returns `Some(data)` if the value put was older than the one available on the network
pub async fn set_dht_value(
&self,
key: TypedKey,
@@ -268,9 +315,11 @@ impl RoutingContext {
}
/// Watches changes to an opened or created value
///
/// Changes to subkeys within the subkey range are returned via a ValueChanged callback
/// If the subkey range is empty, all subkey changes are considered
/// Expiration can be infinite to keep the watch for the maximum amount of time
///
/// Return value upon success is the amount of time allowed for the watch
pub async fn watch_dht_values(
&self,
@@ -287,6 +336,7 @@ impl RoutingContext {
}
/// Cancels a watch early
///
/// This is a convenience function that cancels watching all subkeys in a range
pub async fn cancel_dht_watch(
&self,

View File

@@ -3,15 +3,13 @@ use super::*;
/// Direct statement blob passed to hosting application for processing
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct VeilidAppMessage {
/// Some(sender) if the message was sent directly, None if received via a private/safety route
#[serde(with = "as_human_opt_string")]
#[schemars(with = "Option<String>")]
pub sender: Option<TypedKey>,
sender: Option<TypedKey>,
/// The content of the message to deliver to the application
#[serde(with = "as_human_base64")]
#[schemars(with = "String")]
pub message: Vec<u8>,
message: Vec<u8>,
}
impl VeilidAppMessage {
@@ -19,9 +17,12 @@ impl VeilidAppMessage {
Self { sender, message }
}
/// Some(sender) if the message was sent directly, None if received via a private/safety route
pub fn sender(&self) -> Option<&TypedKey> {
self.sender.as_ref()
}
/// The content of the message to deliver to the application
pub fn message(&self) -> &[u8] {
&self.message
}
@@ -30,17 +31,14 @@ impl VeilidAppMessage {
/// Direct question blob passed to hosting application for processing to send an eventual AppReply
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct VeilidAppCall {
/// Some(sender) if the request was sent directly, None if received via a private/safety route
#[serde(with = "as_human_opt_string")]
#[schemars(with = "Option<String>")]
sender: Option<TypedKey>,
/// The content of the request to deliver to the application
#[serde(with = "as_human_base64")]
#[schemars(with = "String")]
message: Vec<u8>,
/// The id to reply to
#[serde(with = "as_human_string")]
#[schemars(with = "String")]
call_id: OperationId,
@@ -55,12 +53,16 @@ impl VeilidAppCall {
}
}
/// Some(sender) if the request was sent directly, None if received via a private/safety route
pub fn sender(&self) -> Option<&TypedKey> {
self.sender.as_ref()
}
/// The content of the request to deliver to the application
pub fn message(&self) -> &[u8] {
&self.message
}
/// The id to specify as `call_id` in the [VeilidAPI::app_call_reply] function
pub fn id(&self) -> OperationId {
self.call_id
}