This commit is contained in:
John Smith 2022-02-06 21:18:42 -05:00
parent d660d86884
commit 70960fa592
53 changed files with 2062 additions and 2316 deletions

104
Cargo.lock generated
View File

@ -125,15 +125,6 @@ dependencies = [
"log", "log",
] ]
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.53" version = "1.0.53"
@ -707,13 +698,9 @@ version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [ dependencies = [
"ansi_term",
"atty",
"bitflags", "bitflags",
"strsim 0.8.0",
"textwrap 0.11.0", "textwrap 0.11.0",
"unicode-width", "unicode-width",
"vec_map",
] ]
[[package]] [[package]]
@ -726,7 +713,7 @@ dependencies = [
"bitflags", "bitflags",
"indexmap", "indexmap",
"os_str_bytes", "os_str_bytes",
"strsim 0.10.0", "strsim",
"termcolor", "termcolor",
"textwrap 0.14.2", "textwrap 0.14.2",
] ]
@ -1148,7 +1135,7 @@ dependencies = [
"ident_case", "ident_case",
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim 0.10.0", "strsim",
"syn", "syn",
] ]
@ -1399,6 +1386,16 @@ dependencies = [
"instant", "instant",
] ]
[[package]]
name = "ffi-support"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27838c6815cfe9de2d3aeb145ffd19e565f577414b33f3bdbf42fe040e9e0ff6"
dependencies = [
"lazy_static",
"log",
]
[[package]] [[package]]
name = "fixed-hash" name = "fixed-hash"
version = "0.7.0" version = "0.7.0"
@ -1427,26 +1424,6 @@ dependencies = [
"yansi", "yansi",
] ]
[[package]]
name = "flutter_rust_bridge"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ad509fe9fd3ac5a4d10a30a7de9224b74192c65c22338cc958ab0f93f0c834"
dependencies = [
"allo-isolate",
"anyhow",
"flutter_rust_bridge_macros",
"lazy_static",
"parking_lot 0.11.2",
"threadpool",
]
[[package]]
name = "flutter_rust_bridge_macros"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99a2555456c9c12c5982543c61d79267327d522eaa1490ef4914f5ed87b16fe1"
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@ -1900,8 +1877,8 @@ dependencies = [
"android_logger", "android_logger",
"backtrace", "backtrace",
"byteorder", "byteorder",
"cfg-if 0.1.10", "cfg-if 1.0.0",
"clap 2.34.0", "clap 3.0.13",
"core-foundation 0.9.2", "core-foundation 0.9.2",
"core-foundation-sys 0.8.3", "core-foundation-sys 0.8.3",
"directories", "directories",
@ -1912,7 +1889,6 @@ dependencies = [
"log", "log",
"ndk", "ndk",
"ndk-glue", "ndk-glue",
"owning_ref",
"rpassword", "rpassword",
"secret-service", "secret-service",
"security-framework", "security-framework",
@ -3518,12 +3494,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" version = "0.10.0"
@ -3644,15 +3614,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "threadpool"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
dependencies = [
"num_cpus",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.43" version = "0.1.43"
@ -3871,12 +3832,6 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]] [[package]]
name = "veilid-cli" name = "veilid-cli"
version = "0.1.0" version = "0.1.0"
@ -3990,13 +3945,26 @@ dependencies = [
name = "veilid-flutter" name = "veilid-flutter"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"allo-isolate",
"anyhow", "anyhow",
"async-std", "async-std",
"backtrace",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"flutter_rust_bridge", "console_error_panic_hook",
"ffi-support",
"futures",
"js-sys",
"lazy_static",
"log", "log",
"parking_lot 0.12.0", "parking_lot 0.12.0",
"serde 1.0.136",
"serde_json",
"veilid-core", "veilid-core",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-test",
"wasm-logger",
"wee_alloc",
] ]
[[package]] [[package]]
@ -4030,6 +3998,22 @@ dependencies = [
"windows-service", "windows-service",
] ]
[[package]]
name = "veilid-wasm"
version = "0.1.0"
dependencies = [
"cfg-if 1.0.0",
"console_error_panic_hook",
"js-sys",
"log",
"veilid-core",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-test",
"wasm-logger",
"wee_alloc",
]
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.4" version = "0.9.4"

View File

@ -4,7 +4,8 @@ members = [
"veilid-core", "veilid-core",
"veilid-server", "veilid-server",
"veilid-cli", "veilid-cli",
"veilid-flutter/rust" "veilid-flutter/rust",
"veilid-wasm",
] ]
exclude = [ "./external/keyring-rs", "./external/netlink", "./external/cursive" ] exclude = [ "./external/keyring-rs", "./external/netlink", "./external/cursive" ]

@ -1 +1 @@
Subproject commit 3713e10599c6078e058aab785ef46594420dc11b Subproject commit 935ca957d7e223ef560a0b20b656730a325e0ba7

View File

@ -1,6 +1,6 @@
use crate::core_context::*;
use crate::intf::*; use crate::intf::*;
use crate::veilid_api::*; use crate::veilid_api::*;
use crate::veilid_core::*;
use crate::xx::*; use crate::xx::*;
use log::{set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record}; use log::{set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
@ -23,20 +23,12 @@ impl ApiLogger {
fn new_inner(level: LevelFilter, update_callback: UpdateCallback) -> ApiLoggerInner { fn new_inner(level: LevelFilter, update_callback: UpdateCallback) -> ApiLoggerInner {
let (tx, rx) = async_channel::unbounded::<(VeilidLogLevel, String)>(); let (tx, rx) = async_channel::unbounded::<(VeilidLogLevel, String)>();
let _join_handle: JoinHandle<()> = spawn(async move { let _join_handle: JoinHandle<()> = spawn(async move {
loop { while let Ok(v) = rx.recv().await {
match rx.recv().await { (update_callback)(VeilidUpdate::Log {
Ok(v) => { log_level: v.0,
(update_callback)(VeilidUpdate::Log { message: v.1,
log_level: v.0, })
message: v.1, .await;
})
.await;
}
Err(_) => {
// Nothing to be done here...
break;
}
}
} }
}); });
ApiLoggerInner { ApiLoggerInner {

View File

@ -6,9 +6,10 @@ use crate::xx::*;
use crate::*; use crate::*;
use core::convert::TryFrom; use core::convert::TryFrom;
use core::fmt; use core::fmt;
use serde::*;
state_machine! { state_machine! {
derive(Debug, PartialEq, Eq, Clone, Copy) derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)
pub Attachment(Detached) pub Attachment(Detached)
//--- //---
Detached(AttachRequested) => Attaching [StartAttachment], Detached(AttachRequested) => Attaching [StartAttachment],
@ -102,8 +103,6 @@ impl TryFrom<String> for AttachmentState {
pub struct AttachmentManagerInner { pub struct AttachmentManagerInner {
config: VeilidConfig, config: VeilidConfig,
table_store: TableStore,
crypto: Crypto,
attachment_machine: CallbackStateMachine<Attachment>, attachment_machine: CallbackStateMachine<Attachment>,
network_manager: NetworkManager, network_manager: NetworkManager,
maintain_peers: bool, maintain_peers: bool,
@ -125,8 +124,6 @@ impl AttachmentManager {
) -> AttachmentManagerInner { ) -> AttachmentManagerInner {
AttachmentManagerInner { AttachmentManagerInner {
config: config.clone(), config: config.clone(),
table_store: table_store.clone(),
crypto: crypto.clone(),
attachment_machine: CallbackStateMachine::new(), attachment_machine: CallbackStateMachine::new(),
network_manager: NetworkManager::new(config, table_store, crypto), network_manager: NetworkManager::new(config, table_store, crypto),
maintain_peers: false, maintain_peers: false,
@ -145,14 +142,6 @@ impl AttachmentManager {
self.inner.lock().config.clone() self.inner.lock().config.clone()
} }
pub fn table_store(&self) -> TableStore {
self.inner.lock().table_store.clone()
}
pub fn crypto(&self) -> Crypto {
self.inner.lock().crypto.clone()
}
pub fn network_manager(&self) -> NetworkManager { pub fn network_manager(&self) -> NetworkManager {
self.inner.lock().network_manager.clone() self.inner.lock().network_manager.clone()
} }
@ -274,20 +263,26 @@ impl AttachmentManager {
&self, &self,
state_change_callback: StateChangeCallback<Attachment>, state_change_callback: StateChangeCallback<Attachment>,
) -> Result<(), String> { ) -> Result<(), String> {
let inner = self.inner.lock(); let network_manager = {
inner let inner = self.inner.lock();
.attachment_machine inner
.set_state_change_callback(state_change_callback); .attachment_machine
.set_state_change_callback(state_change_callback);
inner.network_manager.clone()
};
inner.network_manager.init().await?; network_manager.init().await?;
Ok(()) Ok(())
} }
pub async fn terminate(&self) { pub async fn terminate(&self) {
// Ensure we detached // Ensure we detached
self.detach().await; self.detach().await;
let inner = self.inner.lock(); let network_manager = {
inner.network_manager.terminate().await; let inner = self.inner.lock();
inner.network_manager.clone()
};
network_manager.terminate().await;
} }
fn attach(&self) { fn attach(&self) {

View File

@ -0,0 +1,197 @@
use crate::api_logger::*;
use crate::attachment_manager::*;
use crate::dht::crypto::Crypto;
use crate::intf::*;
use crate::veilid_api::*;
use crate::veilid_config::*;
use crate::xx::*;
cfg_if! {
if #[cfg(target_arch = "wasm32")] {
pub type UpdateCallback = Arc<dyn Fn(VeilidUpdate) -> SystemPinBoxFuture<()>>;
} else {
pub type UpdateCallback = Arc<dyn Fn(VeilidUpdate) -> SystemPinBoxFuture<()> + Send + Sync>;
}
}
pub struct VeilidCoreSetup {
pub update_callback: UpdateCallback,
pub config_callback: ConfigCallback,
}
pub struct VeilidCoreContext {
pub config: VeilidConfig,
pub protected_store: ProtectedStore,
pub table_store: TableStore,
pub block_store: BlockStore,
pub crypto: Crypto,
pub attachment_manager: AttachmentManager,
}
impl VeilidCoreContext {
async fn new(setup: VeilidCoreSetup) -> Result<VeilidCoreContext, VeilidAPIError> {
// Start up api logging early if it's in the config
let api_log_level: VeilidConfigLogLevel =
*(setup.config_callback)("api_log_level".to_owned())
.map_err(|e| VeilidAPIError::ParseError {
message: "Failed to get api_log_level".to_owned(),
value: e,
})?
.downcast()
.map_err(|e| VeilidAPIError::ParseError {
message: "Incorrect type for key 'api_log_level'".to_owned(),
value: format!("Invalid type: {:?}", e.type_id()),
})?;
if api_log_level != VeilidConfigLogLevel::Off {
ApiLogger::init(
api_log_level.to_level_filter(),
setup.update_callback.clone(),
);
for ig in crate::DEFAULT_LOG_IGNORE_LIST {
ApiLogger::add_filter_ignore_str(ig);
}
}
trace!("VeilidCoreContext::new starting");
cfg_if! {
if #[cfg(target_os = "android")] {
if utils::android::ANDROID_GLOBALS.lock().is_none() {
error!("Android globals are not set up");
return Err("Android globals are not set up".to_owned());
}
}
}
// Set up config
trace!("VeilidCoreContext::new init config");
let mut config = VeilidConfig::new();
if let Err(e) = config.init(setup.config_callback).await {
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Set up protected store
trace!("VeilidCoreContext::new init protected store");
let protected_store = ProtectedStore::new(config.clone());
if let Err(e) = protected_store.init().await {
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Init node id from config now that protected store is set up
if let Err(e) = config.init_node_id(protected_store.clone()).await {
protected_store.terminate().await;
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Set up tablestore
trace!("VeilidCoreContext::new init table store");
let table_store = TableStore::new(config.clone());
if let Err(e) = table_store.init().await {
protected_store.terminate().await;
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Set up crypto
trace!("VeilidCoreContext::new init crypto");
let crypto = Crypto::new(config.clone(), table_store.clone());
if let Err(e) = crypto.init().await {
table_store.terminate().await;
protected_store.terminate().await;
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Set up block store
trace!("VeilidCoreContext::new init block store");
let block_store = BlockStore::new(config.clone());
if let Err(e) = block_store.init().await {
crypto.terminate().await;
table_store.terminate().await;
protected_store.terminate().await;
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
// Set up attachment manager
trace!("VeilidCoreContext::new init attachment manager");
let cb = setup.update_callback;
let attachment_manager =
AttachmentManager::new(config.clone(), table_store.clone(), crypto.clone());
if let Err(e) = attachment_manager
.init(Arc::new(
move |_old_state: AttachmentState, new_state: AttachmentState| {
cb(VeilidUpdate::Attachment(new_state))
},
))
.await
{
block_store.terminate().await;
crypto.terminate().await;
table_store.terminate().await;
protected_store.terminate().await;
config.terminate().await;
ApiLogger::terminate();
return Err(VeilidAPIError::Internal(e));
}
Ok(VeilidCoreContext {
config,
protected_store,
table_store,
block_store,
crypto,
attachment_manager,
})
}
async fn shutdown(self) {
trace!("VeilidCoreContext::terminate_core_context starting");
self.attachment_manager.terminate().await;
self.block_store.terminate().await;
self.crypto.terminate().await;
self.table_store.terminate().await;
self.protected_store.terminate().await;
self.config.terminate().await;
trace!("VeilidCoreContext::shutdown complete");
ApiLogger::terminate();
}
}
/////////////////////////////////////////////////////////////////////////////
static INITIALIZED: AsyncMutex<bool> = AsyncMutex::new(false);
pub async fn api_startup(setup: VeilidCoreSetup) -> Result<VeilidAPI, VeilidAPIError> {
// See if we have an API started up already
let mut initialized_lock = INITIALIZED.lock().await;
if *initialized_lock {
return Err(VeilidAPIError::AlreadyInitialized);
}
// Create core context
let context = VeilidCoreContext::new(setup).await?;
// Return an API object around our context
let veilid_api = VeilidAPI::new(context);
*initialized_lock = true;
Ok(veilid_api)
}
pub async fn api_shutdown(context: VeilidCoreContext) {
let mut initialized_lock = INITIALIZED.lock().await;
context.shutdown().await;
*initialized_lock = false;
}

View File

@ -94,38 +94,43 @@ impl Crypto {
trace!("Crypto::init"); trace!("Crypto::init");
// make local copy of node id for easy access // make local copy of node id for easy access
let mut inner = self.inner.lock(); let (table_store, node_id) = {
let c = self.config.get(); let mut inner = self.inner.lock();
inner.node_id = c.network.node_id; let c = self.config.get();
inner.node_id_secret = c.network.node_id_secret; inner.node_id = c.network.node_id;
inner.node_id_secret = c.network.node_id_secret;
(inner.table_store.clone(), c.network.node_id)
};
// load caches if they are valid for this node id // load caches if they are valid for this node id
let mut db = inner.table_store.open("crypto_caches", 1).await?; let mut db = table_store.open("crypto_caches", 1).await?;
let caches_valid = match db.load(0, b"node_id").await? { let caches_valid = match db.load(0, b"node_id").await? {
Some(v) => v.as_slice() == inner.node_id.bytes, Some(v) => v.as_slice() == node_id.bytes,
None => false, None => false,
}; };
if caches_valid { if caches_valid {
if let Some(b) = db.load(0, b"dh_cache").await? { if let Some(b) = db.load(0, b"dh_cache").await? {
let mut inner = self.inner.lock();
bytes_to_cache(&b, &mut inner.dh_cache); bytes_to_cache(&b, &mut inner.dh_cache);
} }
} else { } else {
drop(db); drop(db);
inner.table_store.delete("crypto_caches").await?; table_store.delete("crypto_caches").await?;
db = inner.table_store.open("crypto_caches", 1).await?; db = table_store.open("crypto_caches", 1).await?;
db.store(0, b"node_id", &inner.node_id.bytes).await?; db.store(0, b"node_id", &node_id.bytes).await?;
} }
// Schedule flushing // Schedule flushing
let this = self.clone(); let this = self.clone();
inner.flush_future = Some(Box::pin(interval(60000, move || { let flush_future = interval(60000, move || {
let this = this.clone(); let this = this.clone();
async move { async move {
if let Err(e) = this.flush().await { if let Err(e) = this.flush().await {
warn!("flush failed: {}", e); warn!("flush failed: {}", e);
} }
} }
}))); });
self.inner.lock().flush_future = Some(flush_future);
Ok(()) Ok(())
} }
@ -161,21 +166,23 @@ impl Crypto {
}; };
} }
fn ed25519_to_x25519_pk(key: &ed::PublicKey) -> Result<xd::PublicKey, ()> { fn ed25519_to_x25519_pk(key: &ed::PublicKey) -> Result<xd::PublicKey, String> {
let bytes = key.to_bytes(); let bytes = key.to_bytes();
let compressed = cd::edwards::CompressedEdwardsY(bytes); let compressed = cd::edwards::CompressedEdwardsY(bytes);
let point = compressed.decompress().ok_or(())?; let point = compressed
.decompress()
.ok_or_else(fn_string!("ed25519_to_x25519_pk failed"))?;
let mp = point.to_montgomery(); let mp = point.to_montgomery();
Ok(xd::PublicKey::from(mp.to_bytes())) Ok(xd::PublicKey::from(mp.to_bytes()))
} }
fn ed25519_to_x25519_sk(key: &ed::SecretKey) -> Result<xd::StaticSecret, ()> { fn ed25519_to_x25519_sk(key: &ed::SecretKey) -> Result<xd::StaticSecret, String> {
let exp = ed::ExpandedSecretKey::from(key); let exp = ed::ExpandedSecretKey::from(key);
let bytes: [u8; ed::EXPANDED_SECRET_KEY_LENGTH] = exp.to_bytes(); let bytes: [u8; ed::EXPANDED_SECRET_KEY_LENGTH] = exp.to_bytes();
let lowbytes: [u8; 32] = bytes[0..32].try_into().map_err(drop)?; let lowbytes: [u8; 32] = bytes[0..32].try_into().map_err(map_to_string)?;
Ok(xd::StaticSecret::from(lowbytes)) Ok(xd::StaticSecret::from(lowbytes))
} }
pub fn cached_dh(&self, key: &DHTKey, secret: &DHTKeySecret) -> Result<SharedSecret, ()> { pub fn cached_dh(&self, key: &DHTKey, secret: &DHTKeySecret) -> Result<SharedSecret, String> {
if let Some(c) = self if let Some(c) = self
.inner .inner
.lock() .lock()
@ -197,24 +204,12 @@ impl Crypto {
/////////// ///////////
// These are safe to use regardless of initialization status // These are safe to use regardless of initialization status
pub fn compute_dh(key: &DHTKey, secret: &DHTKeySecret) -> Result<SharedSecret, ()> { pub fn compute_dh(key: &DHTKey, secret: &DHTKeySecret) -> Result<SharedSecret, String> {
assert!(key.valid); assert!(key.valid);
assert!(secret.valid); assert!(secret.valid);
let pk_ed = match ed::PublicKey::from_bytes(&key.bytes) { let pk_ed = ed::PublicKey::from_bytes(&key.bytes).map_err(map_to_string)?;
Ok(v) => v,
Err(e) => {
trace!("compute_dh error: {:?}", e);
return Err(());
}
};
let pk_xd = Self::ed25519_to_x25519_pk(&pk_ed)?; let pk_xd = Self::ed25519_to_x25519_pk(&pk_ed)?;
let sk_ed = match ed::SecretKey::from_bytes(&secret.bytes) { let sk_ed = ed::SecretKey::from_bytes(&secret.bytes).map_err(map_to_string)?;
Ok(v) => v,
Err(e) => {
trace!("compute_dh error: {:?}", e);
return Err(());
}
};
let sk_xd = Self::ed25519_to_x25519_sk(&sk_ed)?; let sk_xd = Self::ed25519_to_x25519_sk(&sk_ed)?;
Ok(sk_xd.diffie_hellman(&pk_xd).to_bytes()) Ok(sk_xd.diffie_hellman(&pk_xd).to_bytes())
} }
@ -236,12 +231,13 @@ impl Crypto {
nonce: &Nonce, nonce: &Nonce,
shared_secret: &SharedSecret, shared_secret: &SharedSecret,
associated_data: Option<&[u8]>, associated_data: Option<&[u8]>,
) -> Result<(), ()> { ) -> Result<(), String> {
let key = ch::Key::from(*shared_secret); let key = ch::Key::from(*shared_secret);
let xnonce = ch::XNonce::from(*nonce); let xnonce = ch::XNonce::from(*nonce);
let aead = ch::XChaCha20Poly1305::new(&key); let aead = ch::XChaCha20Poly1305::new(&key);
aead.decrypt_in_place(&xnonce, associated_data.unwrap_or(b""), body) aead.decrypt_in_place(&xnonce, associated_data.unwrap_or(b""), body)
.map_err(|e| trace!("decryption failure: {}", e)) .map_err(map_to_string)
.map_err(logthru_crypto!())
} }
pub fn decrypt( pub fn decrypt(
@ -249,9 +245,11 @@ impl Crypto {
nonce: &Nonce, nonce: &Nonce,
shared_secret: &SharedSecret, shared_secret: &SharedSecret,
associated_data: Option<&[u8]>, associated_data: Option<&[u8]>,
) -> Result<Vec<u8>, ()> { ) -> Result<Vec<u8>, String> {
let mut out = body.to_vec(); let mut out = body.to_vec();
Self::decrypt_in_place(&mut out, nonce, shared_secret, associated_data)?; Self::decrypt_in_place(&mut out, nonce, shared_secret, associated_data)
.map_err(map_to_string)
.map_err(logthru_crypto!())?;
Ok(out) Ok(out)
} }
@ -260,13 +258,14 @@ impl Crypto {
nonce: &Nonce, nonce: &Nonce,
shared_secret: &SharedSecret, shared_secret: &SharedSecret,
associated_data: Option<&[u8]>, associated_data: Option<&[u8]>,
) -> Result<(), ()> { ) -> Result<(), String> {
let key = ch::Key::from(*shared_secret); let key = ch::Key::from(*shared_secret);
let xnonce = ch::XNonce::from(*nonce); let xnonce = ch::XNonce::from(*nonce);
let aead = ch::XChaCha20Poly1305::new(&key); let aead = ch::XChaCha20Poly1305::new(&key);
aead.encrypt_in_place(&xnonce, associated_data.unwrap_or(b""), body) aead.encrypt_in_place(&xnonce, associated_data.unwrap_or(b""), body)
.map_err(|e| trace!("encryption failure: {}", e)) .map_err(map_to_string)
.map_err(logthru_crypto!())
} }
pub fn encrypt( pub fn encrypt(
@ -274,9 +273,11 @@ impl Crypto {
nonce: &Nonce, nonce: &Nonce,
shared_secret: &SharedSecret, shared_secret: &SharedSecret,
associated_data: Option<&[u8]>, associated_data: Option<&[u8]>,
) -> Result<Vec<u8>, ()> { ) -> Result<Vec<u8>, String> {
let mut out = body.to_vec(); let mut out = body.to_vec();
Self::encrypt_in_place(&mut out, nonce, shared_secret, associated_data)?; Self::encrypt_in_place(&mut out, nonce, shared_secret, associated_data)
.map_err(map_to_string)
.map_err(logthru_crypto!())?;
Ok(out) Ok(out)
} }
} }

View File

@ -172,7 +172,7 @@ impl Envelope {
crypto: Crypto, crypto: Crypto,
data: &[u8], data: &[u8],
node_id_secret: &DHTKeySecret, node_id_secret: &DHTKeySecret,
) -> Result<Vec<u8>, ()> { ) -> Result<Vec<u8>, String> {
// Get DH secret // Get DH secret
let dh_secret = crypto.cached_dh(&self.sender_id, node_id_secret)?; let dh_secret = crypto.cached_dh(&self.sender_id, node_id_secret)?;

View File

@ -1,2 +1,30 @@
//use crate::intf::*; use crate::intf::*;
//use crate::xx::*; use crate::*;
struct BlockStoreInner {
//
}
#[derive(Clone)]
pub struct BlockStore {
config: VeilidConfig,
inner: Arc<Mutex<BlockStoreInner>>,
}
impl BlockStore {
fn new_inner() -> BlockStoreInner {
BlockStoreInner {}
}
pub fn new(config: VeilidConfig) -> Self {
Self {
config,
inner: Arc::new(Mutex::new(Self::new_inner())),
}
}
pub async fn init(&self) -> Result<(), String> {
Ok(())
}
pub async fn terminate(&self) {}
}

View File

@ -2,7 +2,7 @@ mod block_store;
mod network; mod network;
mod protected_store; mod protected_store;
mod system; mod system;
pub mod table_store; mod table_store;
pub mod utils; pub mod utils;
pub use block_store::*; pub use block_store::*;

View File

@ -44,8 +44,8 @@ impl ProtectedStore {
} }
pub async fn init(&self) -> Result<(), String> { pub async fn init(&self) -> Result<(), String> {
let c = self.config.get(); let delete = {
{ let c = self.config.get();
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
if !c.protected_store.always_use_insecure_storage { if !c.protected_store.always_use_insecure_storage {
cfg_if! { cfg_if! {
@ -74,9 +74,10 @@ impl ProtectedStore {
if inner.keyring_manager.is_none() { if inner.keyring_manager.is_none() {
return Err("Could not initialize the protected store.".to_owned()); return Err("Could not initialize the protected store.".to_owned());
} }
} c.protected_store.delete
};
if c.protected_store.delete { if delete {
self.delete_all().await?; self.delete_all().await?;
} }

View File

@ -24,29 +24,6 @@ lazy_static! {
} }
pub fn veilid_core_setup_android_no_log<'a>(env: JNIEnv<'a>, ctx: JObject<'a>) { pub fn veilid_core_setup_android_no_log<'a>(env: JNIEnv<'a>, ctx: JObject<'a>) {
panic::set_hook(Box::new(|panic_info| {
let bt = Backtrace::new();
if let Some(location) = panic_info.location() {
error!(
"panic occurred in file '{}' at line {}",
location.file(),
location.line(),
);
} else {
error!("panic occurred but can't get location information...");
}
if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
error!("panic payload: {:?}", s);
} else if let Some(s) = panic_info.payload().downcast_ref::<String>() {
error!("panic payload: {:?}", s);
} else if let Some(a) = panic_info.payload().downcast_ref::<std::fmt::Arguments>() {
error!("panic payload: {:?}", a);
} else {
error!("no panic payload");
}
error!("Backtrace:\n{:?}", bt);
}));
*ANDROID_GLOBALS.lock() = Some(AndroidGlobals { *ANDROID_GLOBALS.lock() = Some(AndroidGlobals {
vm: env.get_java_vm().unwrap(), vm: env.get_java_vm().unwrap(),
ctx: env.new_global_ref(ctx).unwrap(), ctx: env.new_global_ref(ctx).unwrap(),
@ -70,6 +47,29 @@ pub fn veilid_core_setup_android<'a>(
), ),
); );
panic::set_hook(Box::new(|panic_info| {
let bt = Backtrace::new();
if let Some(location) = panic_info.location() {
error!(
"panic occurred in file '{}' at line {}",
location.file(),
location.line(),
);
} else {
error!("panic occurred but can't get location information...");
}
if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
error!("panic payload: {:?}", s);
} else if let Some(s) = panic_info.payload().downcast_ref::<String>() {
error!("panic payload: {:?}", s);
} else if let Some(a) = panic_info.payload().downcast_ref::<std::fmt::Arguments>() {
error!("panic payload: {:?}", a);
} else {
error!("no panic payload");
}
error!("Backtrace:\n{:?}", bt);
}));
veilid_core_setup_android_no_log(env, ctx); veilid_core_setup_android_no_log(env, ctx);
} }

View File

@ -1 +1,31 @@
use crate::intf::*;
use crate::*;
struct BlockStoreInner {
//
}
#[derive(Clone)]
pub struct BlockStore {
config: VeilidConfig,
inner: Arc<Mutex<BlockStoreInner>>,
}
impl BlockStore {
fn new_inner() -> BlockStoreInner {
BlockStoreInner {}
}
pub fn new(config: VeilidConfig) -> Self {
Self {
config,
inner: Arc::new(Mutex::new(Self::new_inner())),
}
}
pub async fn init(&self) -> Result<(), String> {
Ok(())
}
pub async fn terminate(&self) {}
}

View File

@ -78,7 +78,7 @@ impl WebsocketProtocolHandler {
assert!(local_address.is_none()); assert!(local_address.is_none());
// Split dial info up // Split dial info up
let (tls, scheme) = match &dial_info { let (_tls, scheme) = match &dial_info {
DialInfo::WS(_) => (false, "ws"), DialInfo::WS(_) => (false, "ws"),
DialInfo::WSS(_) => (true, "wss"), DialInfo::WSS(_) => (true, "wss"),
_ => panic!("invalid dialinfo for WS/WSS protocol"), _ => panic!("invalid dialinfo for WS/WSS protocol"),

View File

@ -9,6 +9,7 @@ mod attachment_manager;
mod callback_state_machine; mod callback_state_machine;
mod connection_manager; mod connection_manager;
mod connection_table; mod connection_table;
mod core_context;
mod dht; mod dht;
mod intf; mod intf;
mod lease_manager; mod lease_manager;
@ -19,16 +20,15 @@ mod routing_table;
mod rpc_processor; mod rpc_processor;
mod veilid_api; mod veilid_api;
mod veilid_config; mod veilid_config;
mod veilid_core;
mod veilid_rng; mod veilid_rng;
#[macro_use] #[macro_use]
pub mod xx; pub mod xx;
pub use self::attachment_manager::AttachmentState; pub use self::attachment_manager::AttachmentState;
pub use self::core_context::{api_startup, VeilidCoreSetup};
pub use self::veilid_api::*; pub use self::veilid_api::*;
pub use self::veilid_config::*; pub use self::veilid_config::*;
pub use self::veilid_core::{VeilidCore, VeilidCoreSetup};
pub mod veilid_capnp { pub mod veilid_capnp {
include!(concat!(env!("OUT_DIR"), "/proto/veilid_capnp.rs")); include!(concat!(env!("OUT_DIR"), "/proto/veilid_capnp.rs"));
@ -47,7 +47,7 @@ pub fn veilid_version() -> (u32, u32, u32) {
) )
} }
pub static DEFAULT_LOG_IGNORE_LIST: [&'static str; 8] = [ pub static DEFAULT_LOG_IGNORE_LIST: [&str; 8] = [
"async_std", "async_std",
"async_io", "async_io",
"polling", "polling",

View File

@ -170,10 +170,12 @@ impl NetworkManager {
Ok(()) Ok(())
} }
pub async fn terminate(&self) { pub async fn terminate(&self) {
let mut inner = self.inner.lock(); let routing_table = {
if let Some(routing_table) = &inner.routing_table { let mut inner = self.inner.lock();
inner.routing_table.take()
};
if let Some(routing_table) = routing_table {
routing_table.terminate().await; routing_table.terminate().await;
inner.routing_table = None;
} }
} }

View File

@ -19,10 +19,9 @@ fn setup_veilid_core() -> VeilidCoreSetup {
} }
} }
async fn startup(core: VeilidCore) -> VeilidAPI { async fn startup() -> VeilidAPI {
trace!("test_table_store: starting"); trace!("test_table_store: starting");
let api = core let api = api_startup(setup_veilid_core())
.startup(setup_veilid_core())
.await .await
.expect("startup failed"); .expect("startup failed");
api api
@ -130,9 +129,8 @@ pub async fn test_dh(crypto: Crypto) {
} }
pub async fn test_all() { pub async fn test_all() {
let core = VeilidCore::new(); let api = startup().await;
let api = startup(core.clone()).await; let crypto = api.crypto().unwrap();
let crypto = core.crypto();
test_enc_dec().await; test_enc_dec().await;
test_dh(crypto).await; test_dh(crypto).await;
shutdown(api.clone()).await; shutdown(api.clone()).await;

View File

@ -8,13 +8,12 @@ use crate::*;
pub async fn test_envelope_round_trip() { pub async fn test_envelope_round_trip() {
info!("--- test envelope round trip ---"); info!("--- test envelope round trip ---");
let veilid_core = VeilidCore::new(); let api = api_startup(setup_veilid_core())
let api = veilid_core
.startup(setup_veilid_core())
.await .await
.expect("startup failed"); .expect("startup failed");
// Get crypto // Get crypto
let crypto = veilid_core.crypto(); let crypto = api.crypto().unwrap();
// Create envelope // Create envelope
let ts = 0x12345678ABCDEF69u64; let ts = 0x12345678ABCDEF69u64;

View File

@ -16,9 +16,9 @@ fn setup_veilid_core() -> VeilidCoreSetup {
} }
} }
async fn startup(core: VeilidCore) -> VeilidAPI { async fn startup() -> VeilidAPI {
trace!("test_table_store: starting"); trace!("test_table_store: starting");
core.startup(setup_veilid_core()) api_startup(setup_veilid_core())
.await .await
.expect("startup failed") .expect("startup failed")
} }
@ -93,10 +93,8 @@ pub async fn test_protected_store(ps: ProtectedStore) {
} }
pub async fn test_all() { pub async fn test_all() {
let core = VeilidCore::new(); let api = startup().await;
let api = startup(core.clone()).await; let ps = api.protected_store().unwrap();
let ps = core.protected_store();
test_protected_store(ps.clone()).await; test_protected_store(ps.clone()).await;
shutdown(api).await; shutdown(api).await;

View File

@ -17,9 +17,9 @@ fn setup_veilid_core() -> VeilidCoreSetup {
} }
} }
async fn startup(core: VeilidCore) -> VeilidAPI { async fn startup() -> VeilidAPI {
trace!("test_table_store: starting"); trace!("test_table_store: starting");
core.startup(setup_veilid_core()) api_startup(setup_veilid_core())
.await .await
.expect("startup failed") .expect("startup failed")
} }
@ -169,10 +169,8 @@ pub async fn test_cbor(ts: TableStore) {
} }
pub async fn test_all() { pub async fn test_all() {
let core = VeilidCore::new(); let api = startup().await;
let api = startup(core.clone()).await; let ts = api.table_store().unwrap();
let ts = core.table_store();
test_delete_open_delete(ts.clone()).await; test_delete_open_delete(ts.clone()).await;
test_store_delete_load(ts.clone()).await; test_store_delete_load(ts.clone()).await;
test_cbor(ts.clone()).await; test_cbor(ts.clone()).await;

View File

@ -4,9 +4,7 @@ use crate::*;
pub async fn test_startup_shutdown() { pub async fn test_startup_shutdown() {
trace!("test_startup_shutdown: starting"); trace!("test_startup_shutdown: starting");
let veilid_core = VeilidCore::new(); let api = api_startup(setup_veilid_core())
let api = veilid_core
.startup(setup_veilid_core())
.await .await
.expect("startup failed"); .expect("startup failed");
trace!("test_startup_shutdown: shutting down"); trace!("test_startup_shutdown: shutting down");
@ -15,11 +13,8 @@ pub async fn test_startup_shutdown() {
} }
pub async fn test_attach_detach() { pub async fn test_attach_detach() {
let veilid_core = VeilidCore::new();
info!("--- test normal order ---"); info!("--- test normal order ---");
let api = veilid_core let api = api_startup(setup_veilid_core())
.startup(setup_veilid_core())
.await .await
.expect("startup failed"); .expect("startup failed");
api.attach().await.unwrap(); api.attach().await.unwrap();
@ -31,8 +26,7 @@ pub async fn test_attach_detach() {
api.shutdown().await; api.shutdown().await;
info!("--- test auto detach ---"); info!("--- test auto detach ---");
let api = veilid_core let api = api_startup(setup_veilid_core())
.startup(setup_veilid_core())
.await .await
.expect("startup failed"); .expect("startup failed");
api.attach().await.unwrap(); api.attach().await.unwrap();
@ -40,8 +34,7 @@ pub async fn test_attach_detach() {
api.shutdown().await; api.shutdown().await;
info!("--- test detach without attach ---"); info!("--- test detach without attach ---");
let api = veilid_core let api = api_startup(setup_veilid_core())
.startup(setup_veilid_core())
.await .await
.expect("startup failed"); .expect("startup failed");
api.detach().await.unwrap(); api.detach().await.unwrap();

View File

@ -2,6 +2,7 @@
// Debugging // Debugging
use super::*; use super::*;
use routing_table::*;
fn get_bucket_entry_state(text: &str) -> Option<BucketEntryState> { fn get_bucket_entry_state(text: &str) -> Option<BucketEntryState> {
if text == "dead" { if text == "dead" {

View File

@ -3,28 +3,38 @@
mod debug; mod debug;
pub use debug::*; pub use debug::*;
pub use crate::rpc_processor::InfoAnswer;
use crate::*; use crate::*;
use api_logger::*;
use attachment_manager::*;
use core::fmt;
use network_manager::NetworkManager;
use routing_table::*;
use rpc_processor::{RPCError, RPCProcessor};
use xx::*;
pub use crate::dht::key::{generate_secret, DHTKey, DHTKeySecret};
pub use crate::xx::{ pub use crate::xx::{
IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, SystemPinBoxFuture, IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, SystemPinBoxFuture,
ToSocketAddrs, ToSocketAddrs,
}; };
pub use alloc::string::ToString; pub use alloc::string::ToString;
pub use attachment_manager::AttachmentManager;
pub use core::str::FromStr; pub use core::str::FromStr;
pub use dht::crypto::Crypto;
pub use dht::key::{generate_secret, DHTKey, DHTKeySecret};
pub use intf::BlockStore;
pub use intf::ProtectedStore;
pub use intf::TableStore;
pub use network_manager::NetworkManager;
pub use routing_table::RoutingTable;
pub use rpc_processor::InfoAnswer;
use api_logger::*;
use core::fmt;
use core_context::{api_shutdown, VeilidCoreContext};
use rpc_processor::{RPCError, RPCProcessor};
use serde::*;
use xx::*;
///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)] #[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Serialize, Deserialize)]
#[serde(tag = "kind")]
pub enum VeilidAPIError { pub enum VeilidAPIError {
NotInitialized,
AlreadyInitialized,
Timeout, Timeout,
Shutdown, Shutdown,
NodeNotFound(NodeId), NodeNotFound(NodeId),
@ -49,6 +59,8 @@ pub enum VeilidAPIError {
impl fmt::Display for VeilidAPIError { impl fmt::Display for VeilidAPIError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self { match self {
VeilidAPIError::NotInitialized => write!(f, "VeilidAPIError::NotInitialized"),
VeilidAPIError::AlreadyInitialized => write!(f, "VeilidAPIError::AlreadyInitialized"),
VeilidAPIError::Timeout => write!(f, "VeilidAPIError::Timeout"), VeilidAPIError::Timeout => write!(f, "VeilidAPIError::Timeout"),
VeilidAPIError::Shutdown => write!(f, "VeilidAPIError::Shutdown"), VeilidAPIError::Shutdown => write!(f, "VeilidAPIError::Shutdown"),
VeilidAPIError::NodeNotFound(ni) => write!(f, "VeilidAPIError::NodeNotFound({})", ni), VeilidAPIError::NodeNotFound(ni) => write!(f, "VeilidAPIError::NodeNotFound({})", ni),
@ -107,7 +119,7 @@ macro_rules! parse_error {
///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum VeilidLogLevel { pub enum VeilidLogLevel {
Error = 1, Error = 1,
Warn, Warn,
@ -128,7 +140,8 @@ impl VeilidLogLevel {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind")]
pub enum VeilidUpdate { pub enum VeilidUpdate {
Log { Log {
log_level: VeilidLogLevel, log_level: VeilidLogLevel,
@ -137,14 +150,14 @@ pub enum VeilidUpdate {
Attachment(AttachmentState), Attachment(AttachmentState),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VeilidState { pub struct VeilidState {
pub attachment: AttachmentState, pub attachment: AttachmentState,
} }
///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////
/// ///
#[derive(Clone, Debug, Default, PartialOrd, PartialEq, Eq, Ord)] #[derive(Clone, Debug, Default, PartialOrd, PartialEq, Eq, Ord, Serialize, Deserialize)]
pub struct NodeId { pub struct NodeId {
pub key: DHTKey, pub key: DHTKey,
} }
@ -160,7 +173,7 @@ impl fmt::Display for NodeId {
} }
} }
#[derive(Clone, Debug, Default, PartialOrd, PartialEq, Eq, Ord)] #[derive(Clone, Debug, Default, PartialOrd, PartialEq, Eq, Ord, Serialize, Deserialize)]
pub struct ValueKey { pub struct ValueKey {
pub key: DHTKey, pub key: DHTKey,
pub subkey: Option<String>, pub subkey: Option<String>,
@ -181,7 +194,7 @@ impl ValueKey {
} }
} }
#[derive(Clone, Debug, Default, PartialOrd, PartialEq, Eq, Ord)] #[derive(Clone, Debug, Default, PartialOrd, PartialEq, Eq, Ord, Serialize, Deserialize)]
pub struct BlockId { pub struct BlockId {
pub key: DHTKey, pub key: DHTKey,
} }
@ -193,12 +206,12 @@ impl BlockId {
///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default)] #[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Default, Serialize, Deserialize)]
pub struct SenderInfo { pub struct SenderInfo {
pub socket_address: Option<SocketAddress>, pub socket_address: Option<SocketAddress>,
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct NodeInfo { pub struct NodeInfo {
pub can_route: bool, pub can_route: bool,
pub will_route: bool, pub will_route: bool,
@ -212,7 +225,7 @@ pub struct NodeInfo {
pub will_validate_dial_info: bool, pub will_validate_dial_info: bool,
} }
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
// The derived ordering here is the order of preference, lower is preferred for connections // The derived ordering here is the order of preference, lower is preferred for connections
// Must match DialInfo order // Must match DialInfo order
pub enum ProtocolType { pub enum ProtocolType {
@ -222,13 +235,13 @@ pub enum ProtocolType {
WSS, WSS,
} }
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
pub enum AddressType { pub enum AddressType {
IPV4, IPV4,
IPV6, IPV6,
} }
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
pub enum Address { pub enum Address {
IPV4(Ipv4Addr), IPV4(Ipv4Addr),
IPV6(Ipv6Addr), IPV6(Ipv6Addr),
@ -310,7 +323,9 @@ impl FromStr for Address {
} }
} }
#[derive(Copy, Default, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] #[derive(
Copy, Default, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize,
)]
pub struct SocketAddress { pub struct SocketAddress {
address: Address, address: Address,
port: u16, port: u16,
@ -366,7 +381,7 @@ impl FromStr for SocketAddress {
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct DialInfoFilter { pub struct DialInfoFilter {
pub peer_scope: PeerScope, pub peer_scope: PeerScope,
pub protocol_type: Option<ProtocolType>, pub protocol_type: Option<ProtocolType>,
@ -435,29 +450,30 @@ pub trait MatchesDialInfoFilter {
fn matches_filter(&self, filter: &DialInfoFilter) -> bool; fn matches_filter(&self, filter: &DialInfoFilter) -> bool;
} }
#[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq)] #[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize)]
pub struct DialInfoUDP { pub struct DialInfoUDP {
pub socket_address: SocketAddress, pub socket_address: SocketAddress,
} }
#[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq)] #[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize)]
pub struct DialInfoTCP { pub struct DialInfoTCP {
pub socket_address: SocketAddress, pub socket_address: SocketAddress,
} }
#[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq)] #[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize)]
pub struct DialInfoWS { pub struct DialInfoWS {
pub socket_address: SocketAddress, pub socket_address: SocketAddress,
pub request: String, pub request: String,
} }
#[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq)] #[derive(Clone, Default, Debug, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize)]
pub struct DialInfoWSS { pub struct DialInfoWSS {
pub socket_address: SocketAddress, pub socket_address: SocketAddress,
pub request: String, pub request: String,
} }
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)] #[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize)]
#[serde(tag = "kind")]
// The derived ordering here is the order of preference, lower is preferred for connections // The derived ordering here is the order of preference, lower is preferred for connections
// Must match ProtocolType order // Must match ProtocolType order
pub enum DialInfo { pub enum DialInfo {
@ -706,7 +722,7 @@ impl MatchesDialInfoFilter for DialInfo {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub enum PeerScope { pub enum PeerScope {
All, All,
Global, Global,
@ -718,13 +734,13 @@ impl Default for PeerScope {
} }
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct PeerInfo { pub struct PeerInfo {
pub node_id: NodeId, pub node_id: NodeId,
pub dial_infos: Vec<DialInfo>, pub dial_infos: Vec<DialInfo>,
} }
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)] #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
pub struct PeerAddress { pub struct PeerAddress {
pub socket_address: SocketAddress, pub socket_address: SocketAddress,
pub protocol_type: ProtocolType, pub protocol_type: ProtocolType,
@ -747,7 +763,7 @@ impl PeerAddress {
} }
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct ConnectionDescriptor { pub struct ConnectionDescriptor {
pub remote: PeerAddress, pub remote: PeerAddress,
pub local: Option<SocketAddress>, pub local: Option<SocketAddress>,
@ -802,7 +818,7 @@ impl MatchesDialInfoFilter for ConnectionDescriptor {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct NodeDialInfo { pub struct NodeDialInfo {
pub node_id: NodeId, pub node_id: NodeId,
pub dial_info: DialInfo, pub dial_info: DialInfo,
@ -837,20 +853,20 @@ impl FromStr for NodeDialInfo {
} }
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct LatencyStats { pub struct LatencyStats {
pub fastest: u64, // fastest latency in the ROLLING_LATENCIES_SIZE last latencies pub fastest: u64, // fastest latency in the ROLLING_LATENCIES_SIZE last latencies
pub average: u64, // average latency over the ROLLING_LATENCIES_SIZE last latencies pub average: u64, // average latency over the ROLLING_LATENCIES_SIZE last latencies
pub slowest: u64, // slowest latency in the ROLLING_LATENCIES_SIZE last latencies pub slowest: u64, // slowest latency in the ROLLING_LATENCIES_SIZE last latencies
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct TransferStatsDownUp { pub struct TransferStatsDownUp {
pub down: TransferStats, pub down: TransferStats,
pub up: TransferStats, pub up: TransferStats,
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct TransferStats { pub struct TransferStats {
pub total: u64, // total amount transferred ever pub total: u64, // total amount transferred ever
pub maximum: u64, // maximum rate over the ROLLING_TRANSFERS_SIZE last amounts pub maximum: u64, // maximum rate over the ROLLING_TRANSFERS_SIZE last amounts
@ -858,7 +874,7 @@ pub struct TransferStats {
pub minimum: u64, // minimum rate over the ROLLING_TRANSFERS_SIZE last amounts pub minimum: u64, // minimum rate over the ROLLING_TRANSFERS_SIZE last amounts
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct PingStats { pub struct PingStats {
pub in_flight: u32, // number of pings issued that have yet to be answered pub in_flight: u32, // number of pings issued that have yet to be answered
pub total_sent: u32, // number of pings that have been sent in the total_time range pub total_sent: u32, // number of pings that have been sent in the total_time range
@ -869,7 +885,7 @@ pub struct PingStats {
pub recent_lost_pings: u32, // number of pings that have been lost since we lost reliability pub recent_lost_pings: u32, // number of pings that have been lost since we lost reliability
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct PeerStats { pub struct PeerStats {
pub time_added: u64, // when the peer was added to the routing table pub time_added: u64, // when the peer was added to the routing table
pub last_seen: Option<u64>, // when the peer was last seen for any reason, including when we first attempted to reach out to it pub last_seen: Option<u64>, // when the peer was last seen for any reason, including when we first attempted to reach out to it
@ -889,7 +905,7 @@ cfg_if! {
} }
} }
#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord)] #[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Serialize, Deserialize)]
pub enum TunnelMode { pub enum TunnelMode {
Raw, Raw,
Turn, Turn,
@ -897,7 +913,7 @@ pub enum TunnelMode {
type TunnelId = u64; type TunnelId = u64;
#[derive(Clone, Debug)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TunnelEndpoint { pub struct TunnelEndpoint {
pub node_id: NodeId, // the node id of the tunnel endpoint pub node_id: NodeId, // the node id of the tunnel endpoint
pub dial_info: Vec<DialInfo>, // multiple ways of how to get to the node pub dial_info: Vec<DialInfo>, // multiple ways of how to get to the node
@ -914,7 +930,7 @@ impl Default for TunnelEndpoint {
} }
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct FullTunnel { pub struct FullTunnel {
pub id: TunnelId, pub id: TunnelId,
pub timeout: u64, pub timeout: u64,
@ -922,7 +938,7 @@ pub struct FullTunnel {
pub remote: TunnelEndpoint, pub remote: TunnelEndpoint,
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct PartialTunnel { pub struct PartialTunnel {
pub id: TunnelId, pub id: TunnelId,
pub timeout: u64, pub timeout: u64,
@ -931,12 +947,12 @@ pub struct PartialTunnel {
///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct RouteHopSpec { pub struct RouteHopSpec {
pub dial_info: NodeDialInfo, pub dial_info: NodeDialInfo,
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct PrivateRouteSpec { pub struct PrivateRouteSpec {
// //
pub public_key: DHTKey, pub public_key: DHTKey,
@ -944,7 +960,7 @@ pub struct PrivateRouteSpec {
pub hops: Vec<RouteHopSpec>, pub hops: Vec<RouteHopSpec>,
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct SafetyRouteSpec { pub struct SafetyRouteSpec {
pub public_key: DHTKey, pub public_key: DHTKey,
pub secret_key: DHTKeySecret, pub secret_key: DHTKeySecret,
@ -962,7 +978,7 @@ impl SafetyRouteSpec {
} }
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct RoutingContextOptions { pub struct RoutingContextOptions {
pub safety_route_spec: Option<SafetyRouteSpec>, pub safety_route_spec: Option<SafetyRouteSpec>,
pub private_route_spec: Option<PrivateRouteSpec>, pub private_route_spec: Option<PrivateRouteSpec>,
@ -970,7 +986,7 @@ pub struct RoutingContextOptions {
///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct SearchDHTAnswer { pub struct SearchDHTAnswer {
pub node_id: NodeId, pub node_id: NodeId,
pub dial_info: Vec<DialInfo>, pub dial_info: Vec<DialInfo>,
@ -1051,26 +1067,19 @@ impl RoutingContext {
///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////
struct VeilidAPIInner { struct VeilidAPIInner {
core: Option<VeilidCore>, context: Option<VeilidCoreContext>,
} }
impl fmt::Debug for VeilidAPIInner { impl fmt::Debug for VeilidAPIInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(f, "VeilidAPIInner")
f,
"VeilidAPIInner: {}",
match self.core {
Some(_) => "active",
None => "shutdown",
}
)
} }
} }
impl Drop for VeilidAPIInner { impl Drop for VeilidAPIInner {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(core) = self.core.take() { if let Some(context) = self.context.take() {
intf::spawn_local(core.shutdown()).detach(); intf::spawn_local(api_shutdown(context)).detach();
} }
} }
} }
@ -1080,59 +1089,83 @@ pub struct VeilidAPI {
inner: Arc<Mutex<VeilidAPIInner>>, inner: Arc<Mutex<VeilidAPIInner>>,
} }
#[derive(Clone, Debug, Default)]
pub struct VeilidAPIWeak {
inner: Weak<Mutex<VeilidAPIInner>>,
}
impl VeilidAPIWeak {
pub fn upgrade(&self) -> Option<VeilidAPI> {
self.inner.upgrade().map(|v| VeilidAPI { inner: v })
}
}
impl VeilidAPI { impl VeilidAPI {
pub(crate) fn new(core: VeilidCore) -> Self { pub(crate) fn new(context: VeilidCoreContext) -> Self {
Self { Self {
inner: Arc::new(Mutex::new(VeilidAPIInner { core: Some(core) })), inner: Arc::new(Mutex::new(VeilidAPIInner {
context: Some(context),
})),
} }
} }
pub fn weak(&self) -> VeilidAPIWeak {
VeilidAPIWeak {
inner: Arc::downgrade(&self.inner),
}
}
fn core(&self) -> Result<VeilidCore, VeilidAPIError> {
Ok(self
.inner
.lock()
.core
.as_ref()
.ok_or(VeilidAPIError::Shutdown)?
.clone())
}
fn config(&self) -> Result<VeilidConfig, VeilidAPIError> {
Ok(self.core()?.config())
}
fn attachment_manager(&self) -> Result<AttachmentManager, VeilidAPIError> {
Ok(self.core()?.attachment_manager())
}
fn network_manager(&self) -> Result<NetworkManager, VeilidAPIError> {
Ok(self.attachment_manager()?.network_manager())
}
fn rpc_processor(&self) -> Result<RPCProcessor, VeilidAPIError> {
Ok(self.network_manager()?.rpc_processor())
}
pub async fn shutdown(self) { pub async fn shutdown(self) {
let core = { self.inner.lock().core.take() }; let context = { self.inner.lock().context.take() };
if let Some(core) = core { if let Some(context) = context {
core.shutdown().await; api_shutdown(context).await;
} }
} }
pub fn is_shutdown(&self) -> bool { pub fn is_shutdown(&self) -> bool {
self.inner.lock().core.is_none() 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::NotInitialized)
}
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::NotInitialized)
}
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::NotInitialized)
}
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::NotInitialized)
}
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::NotInitialized)
}
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)
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////

View File

@ -2,6 +2,8 @@ use crate::dht::key;
use crate::intf; use crate::intf;
use crate::xx::*; use crate::xx::*;
use serde::*;
cfg_if! { cfg_if! {
if #[cfg(target_arch = "wasm32")] { if #[cfg(target_arch = "wasm32")] {
pub type ConfigCallbackReturn = Result<Box<dyn core::any::Any>, String>; pub type ConfigCallbackReturn = Result<Box<dyn core::any::Any>, String>;
@ -9,7 +11,7 @@ cfg_if! {
} else { } else {
pub type ConfigCallbackReturn = Result<Box<dyn core::any::Any + Send>, String>; pub type ConfigCallbackReturn = Result<Box<dyn core::any::Any + Send>, String>;
pub type ConfigCallback = Arc<dyn Fn(String) -> ConfigCallbackReturn + Send>; pub type ConfigCallback = Arc<dyn Fn(String) -> ConfigCallbackReturn + Send + Sync>;
} }
} }
@ -172,7 +174,7 @@ pub struct VeilidConfigCapabilities {
pub protocol_accept_wss: bool, pub protocol_accept_wss: bool,
} }
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub enum VeilidConfigLogLevel { pub enum VeilidConfigLogLevel {
Off, Off,
Error, Error,

View File

@ -1,241 +0,0 @@
use crate::api_logger::*;
use crate::attachment_manager::*;
use crate::dht::crypto::Crypto;
use crate::intf::*;
use crate::veilid_api::*;
use crate::veilid_config::*;
use crate::xx::*;
cfg_if! {
if #[cfg(target_arch = "wasm32")] {
pub type UpdateCallback = Arc<dyn Fn(VeilidUpdate) -> SystemPinBoxFuture<()>>;
} else {
pub type UpdateCallback = Arc<dyn Fn(VeilidUpdate) -> SystemPinBoxFuture<()> + Send + Sync>;
}
}
pub struct VeilidCoreSetup {
pub update_callback: UpdateCallback,
pub config_callback: ConfigCallback,
}
struct VeilidCoreInner {
config: Option<VeilidConfig>,
protected_store: Option<ProtectedStore>,
table_store: Option<TableStore>,
crypto: Option<Crypto>,
attachment_manager: Option<AttachmentManager>,
api: VeilidAPIWeak,
}
#[derive(Clone)]
pub struct VeilidCore {
inner: Arc<Mutex<VeilidCoreInner>>,
}
impl Default for VeilidCore {
fn default() -> Self {
Self::new()
}
}
impl VeilidCore {
fn new_inner() -> VeilidCoreInner {
VeilidCoreInner {
config: None,
table_store: None,
protected_store: None,
crypto: None,
attachment_manager: None,
api: VeilidAPIWeak::default(),
}
}
pub fn new() -> Self {
Self {
inner: Arc::new(Mutex::new(Self::new_inner())),
}
}
pub(crate) fn config(&self) -> VeilidConfig {
self.inner.lock().config.as_ref().unwrap().clone()
}
pub(crate) fn table_store(&self) -> TableStore {
self.inner.lock().table_store.as_ref().unwrap().clone()
}
pub(crate) fn protected_store(&self) -> ProtectedStore {
self.inner.lock().protected_store.as_ref().unwrap().clone()
}
pub(crate) fn crypto(&self) -> Crypto {
self.inner.lock().crypto.as_ref().unwrap().clone()
}
pub(crate) fn attachment_manager(&self) -> AttachmentManager {
self.inner
.lock()
.attachment_manager
.as_ref()
.unwrap()
.clone()
}
// internal startup
async fn internal_startup(
&self,
inner: &mut VeilidCoreInner,
setup: VeilidCoreSetup,
) -> Result<VeilidAPI, String> {
// Start up api logging early if it's in the config
let api_log_level: VeilidConfigLogLevel =
*(setup.config_callback)("api_log_level".to_owned())?
.downcast()
.map_err(|_| "incorrect type for key 'api_log_level'".to_owned())?;
if api_log_level != VeilidConfigLogLevel::Off {
ApiLogger::init(
api_log_level.to_level_filter(),
setup.update_callback.clone(),
);
for ig in crate::DEFAULT_LOG_IGNORE_LIST {
ApiLogger::add_filter_ignore_str(ig);
}
}
trace!("VeilidCore::internal_startup starting");
cfg_if! {
if #[cfg(target_os = "android")] {
if utils::android::ANDROID_GLOBALS.lock().is_none() {
error!("Android globals are not set up");
return Err("Android globals are not set up".to_owned());
}
}
}
// Set up config
trace!("VeilidCore::internal_startup init config");
let mut config = VeilidConfig::new();
config.init(setup.config_callback).await?;
inner.config = Some(config.clone());
// Set up protected store
trace!("VeilidCore::internal_startup init protected store");
let protected_store = ProtectedStore::new(config.clone());
protected_store.init().await?;
inner.protected_store = Some(protected_store.clone());
// Init node id from config now that protected store is set up
config.init_node_id(protected_store).await?;
// Set up tablestore
trace!("VeilidCore::internal_startup init table store");
let table_store = TableStore::new(config.clone());
table_store.init().await?;
inner.table_store = Some(table_store.clone());
// Set up crypto
trace!("VeilidCore::internal_startup init crypto");
let crypto = Crypto::new(config.clone(), table_store.clone());
crypto.init().await?;
inner.crypto = Some(crypto.clone());
// Set up block store
// trace!("VeilidCore::internal_startup init block store");
// let block_store = BlockStore::new(config.clone());
// block_store.init().await?;
// inner.block_store = Some(block_store.clone();)
// Set up attachment manager
trace!("VeilidCore::internal_startup init attachment manager");
let cb = setup.update_callback;
let attachment_manager =
AttachmentManager::new(config.clone(), table_store.clone(), crypto.clone());
attachment_manager
.init(Arc::new(
move |_old_state: AttachmentState, new_state: AttachmentState| {
cb(VeilidUpdate::Attachment(new_state))
},
))
.await?;
inner.attachment_manager = Some(attachment_manager.clone());
// Set up the API
trace!("VeilidCore::internal_startup init API");
let this = self.clone();
let veilid_api = VeilidAPI::new(this);
inner.api = veilid_api.weak();
trace!("VeilidCore::internal_startup complete");
Ok(veilid_api)
}
// called once at the beginning to start the node
pub async fn startup(&self, setup: VeilidCoreSetup) -> Result<VeilidAPI, String> {
// See if we have an API started up already
let mut inner = self.inner.lock();
if inner.api.upgrade().is_some() {
// If so, return an error because we shouldn't try to do this more than once
return Err("Veilid API is started".to_owned());
}
// Ensure we never end up partially initialized
match self.internal_startup(&mut *inner, setup).await {
Ok(v) => Ok(v),
Err(e) => {
Self::internal_shutdown(&mut *inner).await;
Err(e)
}
}
}
async fn internal_shutdown(inner: &mut VeilidCoreInner) {
trace!("VeilidCore::internal_shutdown starting");
// Detach the API object
inner.api = VeilidAPIWeak::default();
// Shut down up attachment manager
if let Some(attachment_manager) = &inner.attachment_manager {
attachment_manager.terminate().await;
inner.attachment_manager = None;
}
// Shut down crypto
if let Some(crypto) = &inner.crypto {
crypto.terminate().await;
inner.crypto = None;
}
// Shut down table store
if let Some(table_store) = &inner.table_store {
table_store.terminate().await;
inner.table_store = None;
}
// Shut down protected store
if let Some(protected_store) = &inner.protected_store {
protected_store.terminate().await;
inner.protected_store = None;
}
// Shut down config
if let Some(config) = &inner.config {
config.terminate().await;
inner.config = None;
}
trace!("VeilidCore::shutdown complete");
ApiLogger::terminate();
}
// stop the node gracefully because the veilid api was dropped
pub(crate) async fn shutdown(self) {
let mut inner = self.inner.lock();
Self::internal_shutdown(&mut *inner).await;
}
//
}

View File

@ -158,6 +158,18 @@ macro_rules! logthru_pstore {
logthru!($($level)? "pstore", $fmt, $($arg),+) logthru!($($level)? "pstore", $fmt, $($arg),+)
} }
} }
#[macro_export]
macro_rules! logthru_crypto {
($($level:ident)?) => {
logthru!($($level)? "crypto")
};
($($level:ident)? $text:literal) => {
logthru!($($level)? "crypto", $text)
};
($($level:ident)? $fmt:literal, $($arg:expr),+) => {
logthru!($($level)? "crypto", $fmt, $($arg),+)
}
}
#[macro_export] #[macro_export]
macro_rules! logthru { macro_rules! logthru {

View File

@ -1,7 +1,7 @@
package com.veilid.veilid package com.veilid.veilid
import androidx.annotation.NonNull import androidx.annotation.NonNull
import android.content.Context
import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
@ -10,32 +10,23 @@ import io.flutter.plugin.common.MethodChannel.Result
/** VeilidPlugin */ /** VeilidPlugin */
class VeilidPlugin: FlutterPlugin, MethodCallHandler { class VeilidPlugin: FlutterPlugin, MethodCallHandler {
/// The MethodChannel that will the communication between Flutter and native Android
/// class object {
/// This local reference serves to register the plugin with the Flutter Engine and unregister it {
/// when the Flutter Engine is detached from the Activity System.loadLibrary("veilid_flutter");
// private lateinit var channel : MethodChannel }
}
// static { native fun init_android(ctx: Context)
// System.loadLibrary("veilid_flutter");
// }
// xxx get main activity
// private static native void init_android(Context context);
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
// channel = MethodChannel(flutterPluginBinding.binaryMessenger, "veilid") init_android(flutterPluginBinding.getApplicationContext())
// channel.setMethodCallHandler(this)
} }
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
// if (call.method == "getPlatformVersion") {
// result.success("Android ${android.os.Build.VERSION.RELEASE}")
// } else {
result.notImplemented() result.notImplemented()
// }
} }
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
// channel.setMethodCallHandler(null)
} }
} }

View File

@ -50,6 +50,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
equatable:
dependency: transitive
description:
name: equatable
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -121,6 +128,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.11" version: "0.12.11"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
meta: meta:
dependency: transitive dependency: transitive
description: description:
@ -128,6 +142,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.7.0" version: "1.7.0"
oxidized:
dependency: transitive
description:
name: oxidized
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -181,7 +202,7 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.3" version: "0.4.8"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:

View File

@ -1,367 +0,0 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
part of 'bridge_generated.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
/// @nodoc
class _$VeilidUpdateTearOff {
const _$VeilidUpdateTearOff();
Log log({required VeilidLogLevel logLevel, required String message}) {
return Log(
logLevel: logLevel,
message: message,
);
}
Attachment attachment(AttachmentState field0) {
return Attachment(
field0,
);
}
}
/// @nodoc
const $VeilidUpdate = _$VeilidUpdateTearOff();
/// @nodoc
mixin _$VeilidUpdate {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(VeilidLogLevel logLevel, String message) log,
required TResult Function(AttachmentState field0) attachment,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function(VeilidLogLevel logLevel, String message)? log,
TResult Function(AttachmentState field0)? attachment,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(VeilidLogLevel logLevel, String message)? log,
TResult Function(AttachmentState field0)? attachment,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Log value) log,
required TResult Function(Attachment value) attachment,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(Log value)? log,
TResult Function(Attachment value)? attachment,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Log value)? log,
TResult Function(Attachment value)? attachment,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $VeilidUpdateCopyWith<$Res> {
factory $VeilidUpdateCopyWith(
VeilidUpdate value, $Res Function(VeilidUpdate) then) =
_$VeilidUpdateCopyWithImpl<$Res>;
}
/// @nodoc
class _$VeilidUpdateCopyWithImpl<$Res> implements $VeilidUpdateCopyWith<$Res> {
_$VeilidUpdateCopyWithImpl(this._value, this._then);
final VeilidUpdate _value;
// ignore: unused_field
final $Res Function(VeilidUpdate) _then;
}
/// @nodoc
abstract class $LogCopyWith<$Res> {
factory $LogCopyWith(Log value, $Res Function(Log) then) =
_$LogCopyWithImpl<$Res>;
$Res call({VeilidLogLevel logLevel, String message});
}
/// @nodoc
class _$LogCopyWithImpl<$Res> extends _$VeilidUpdateCopyWithImpl<$Res>
implements $LogCopyWith<$Res> {
_$LogCopyWithImpl(Log _value, $Res Function(Log) _then)
: super(_value, (v) => _then(v as Log));
@override
Log get _value => super._value as Log;
@override
$Res call({
Object? logLevel = freezed,
Object? message = freezed,
}) {
return _then(Log(
logLevel: logLevel == freezed
? _value.logLevel
: logLevel // ignore: cast_nullable_to_non_nullable
as VeilidLogLevel,
message: message == freezed
? _value.message
: message // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$Log implements Log {
const _$Log({required this.logLevel, required this.message});
@override
final VeilidLogLevel logLevel;
@override
final String message;
@override
String toString() {
return 'VeilidUpdate.log(logLevel: $logLevel, message: $message)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is Log &&
const DeepCollectionEquality().equals(other.logLevel, logLevel) &&
const DeepCollectionEquality().equals(other.message, message));
}
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(logLevel),
const DeepCollectionEquality().hash(message));
@JsonKey(ignore: true)
@override
$LogCopyWith<Log> get copyWith => _$LogCopyWithImpl<Log>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(VeilidLogLevel logLevel, String message) log,
required TResult Function(AttachmentState field0) attachment,
}) {
return log(logLevel, message);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function(VeilidLogLevel logLevel, String message)? log,
TResult Function(AttachmentState field0)? attachment,
}) {
return log?.call(logLevel, message);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(VeilidLogLevel logLevel, String message)? log,
TResult Function(AttachmentState field0)? attachment,
required TResult orElse(),
}) {
if (log != null) {
return log(logLevel, message);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Log value) log,
required TResult Function(Attachment value) attachment,
}) {
return log(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(Log value)? log,
TResult Function(Attachment value)? attachment,
}) {
return log?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Log value)? log,
TResult Function(Attachment value)? attachment,
required TResult orElse(),
}) {
if (log != null) {
return log(this);
}
return orElse();
}
}
abstract class Log implements VeilidUpdate {
const factory Log(
{required VeilidLogLevel logLevel, required String message}) = _$Log;
VeilidLogLevel get logLevel;
String get message;
@JsonKey(ignore: true)
$LogCopyWith<Log> get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $AttachmentCopyWith<$Res> {
factory $AttachmentCopyWith(
Attachment value, $Res Function(Attachment) then) =
_$AttachmentCopyWithImpl<$Res>;
$Res call({AttachmentState field0});
}
/// @nodoc
class _$AttachmentCopyWithImpl<$Res> extends _$VeilidUpdateCopyWithImpl<$Res>
implements $AttachmentCopyWith<$Res> {
_$AttachmentCopyWithImpl(Attachment _value, $Res Function(Attachment) _then)
: super(_value, (v) => _then(v as Attachment));
@override
Attachment get _value => super._value as Attachment;
@override
$Res call({
Object? field0 = freezed,
}) {
return _then(Attachment(
field0 == freezed
? _value.field0
: field0 // ignore: cast_nullable_to_non_nullable
as AttachmentState,
));
}
}
/// @nodoc
class _$Attachment implements Attachment {
const _$Attachment(this.field0);
@override
final AttachmentState field0;
@override
String toString() {
return 'VeilidUpdate.attachment(field0: $field0)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is Attachment &&
const DeepCollectionEquality().equals(other.field0, field0));
}
@override
int get hashCode =>
Object.hash(runtimeType, const DeepCollectionEquality().hash(field0));
@JsonKey(ignore: true)
@override
$AttachmentCopyWith<Attachment> get copyWith =>
_$AttachmentCopyWithImpl<Attachment>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(VeilidLogLevel logLevel, String message) log,
required TResult Function(AttachmentState field0) attachment,
}) {
return attachment(field0);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function(VeilidLogLevel logLevel, String message)? log,
TResult Function(AttachmentState field0)? attachment,
}) {
return attachment?.call(field0);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(VeilidLogLevel logLevel, String message)? log,
TResult Function(AttachmentState field0)? attachment,
required TResult orElse(),
}) {
if (attachment != null) {
return attachment(field0);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Log value) log,
required TResult Function(Attachment value) attachment,
}) {
return attachment(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(Log value)? log,
TResult Function(Attachment value)? attachment,
}) {
return attachment?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Log value)? log,
TResult Function(Attachment value)? attachment,
required TResult orElse(),
}) {
if (attachment != null) {
return attachment(this);
}
return orElse();
}
}
abstract class Attachment implements VeilidUpdate {
const factory Attachment(AttachmentState field0) = _$Attachment;
AttachmentState get field0;
@JsonKey(ignore: true)
$AttachmentCopyWith<Attachment> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -1,31 +1,92 @@
import 'dart:async'; import 'dart:async';
import 'dart:ffi';
import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:veilid/bridge_generated.dart'; import 'package:oxidized/oxidized.dart';
const base = 'veilid_flutter'; import 'veilid_stub.dart'
final path = Platform.isWindows if (dart.library.io) 'veilid_ffi.dart'
? '$base.dll' if (dart.library.js) 'veilid_js.dart';
: Platform.isMacOS
? 'lib$base.dylib'
: 'lib$base.so';
late final dylib = Platform.isIOS ? DynamicLibrary.process() : DynamicLibrary.open(path);
late final veilidApi = VeilidFlutterImpl(dylib);
class Veilid { //////////////////////////////////////////////////////////
static VeilidFlutterImpl get api { enum AttachmentState {
if (veilidApi == null) { Detached,
throw PlatformException( Attaching,
code: 'Library missing', AttachedWeak,
details: 'veilid_flutter library could not be loaded dynamically', AttachedGood,
); AttachedStrong,
} FullyAttached,
return veilidApi; OverAttached,
Detaching,
}
enum VeilidLogLevel {
Error,
Warn,
Info,
Debug,
Trace,
}
// VeilidVersion
class VeilidVersion {
final int major;
final int minor;
final int patch;
VeilidVersion({
required this.major,
required this.minor,
required this.patch,
});
}
// VeilidUpdate
abstract class VeilidUpdate {
VeilidUpdateKind get kind;
}
class VeilidUpdateLog implements VeilidUpdate {
final VeilidLogLevel logLevel;
final String message;
VeilidUpdateLog(this.logLevel, this.message);
}
class VeilidUpdateAttachment implements VeilidUpdate {
final AttachmentState state;
VeilidUpdateAttachment(this.state);
}
// VeilidState
class VeilidState {
final AttachmentState attachment;
VeilidState(this.attachment);
}
// Veilid singleton factory
abstract class Veilid {
static Veilid _instance;
static Veilid get instance {
_instance ??= getVeilid();
return _instance;
} }
Stream<VeilidUpdate> startupVeilidCore(String config);
Future<Result<VeilidState, VeilidAPIError>> getVeilidState();
Future<Result<Unit, VeilidAPIError>> changeApiLogLevel(VeilidLogLevel logLevel);
Future<Result<Unit, VeilidAPIError>> shutdownVeilidCore();
String veilidVersionString();
VeilidVersion veilidVersion();
} }

View File

@ -0,0 +1,106 @@
import 'dart:async';
import 'dart:ffi' as ffi;
import 'dart:io';
import 'dart:typed_data';
import 'package:ffi/ffi.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:oxidized/oxidized.dart';
//////////////////////////////////////////////////////////
// Load the veilid_flutter library once
const _base = 'veilid_flutter';
final _path = Platform.isWindows
? '$_base.dll'
: Platform.isMacOS
? 'lib$_base.dylib'
: 'lib$_base.so';
late final _dylib = Platform.isIOS ? DynamicLibrary.process() : DynamicLibrary.open(_path);
// Linkage for initialization
typedef _dart_postCObject = NativeFunction<Int8 Function(Int64, Pointer<Dart_CObject>)>;
// fn free_string(s: *mut std::os::raw::c_char)
typedef _free_string_C = Void Function(Pointer<Utf8>);
typedef _free_string_Dart = void Function(Pointer<Utf8>);
// fn initialize_veilid_flutter(dart_post_c_object_ptr: ffi::DartPostCObjectFnType)
typedef _initializeVeilidFlutter_C = Void Function(Pointer<_dart_postCObject>);
typedef _initializeVeilidFlutter_Dart = void Function(Pointer<_dart_postCObject>);
// fn startup_veilid_core(port: i64, config: FfiStr)
typedef _startup_veilid_core_C = Void Function(Int64, Pointer<Utf8>);
typedef _startup_veilid_core_Dart = void Function(int, Pointer<Utf8>);
// fn get_veilid_state(port: i64)
typedef _get_veilid_state_C = Void Function(Int64);
typedef _get_veilid_state_Dart = void Function(int);
// fn change_api_log_level(port: i64, log_level: FfiStr)
typedef _change_api_log_level_C = Void Function(Int64, Pointer<Utf8>);
typedef _change_api_log_level_Dart = void Function(int, Pointer<Utf8>);
// fn shutdown_veilid_core(port: i64)
typedef _shutdown_veilid_core_C = Void Function(Int64);
typedef _shutdown_veilid_core_Dart = void Function(int);
// fn veilid_version_string() -> *mut c_char
typedef _veilid_version_string_C = Pointer<Utf8> Function();
typedef _veilid_version_string_Dart = Pointer<Utf8> Function();
// fn veilid_version() -> VeilidVersion
class VeilidVersion extends Struct {
@Uint32()
external int major;
@Uint32()
external int minor;
@Uint32()
external int patch;
}
typedef _veilid_version_C = VeilidVersion Function();
typedef _veilid_version_Dart = VeilidVersion Function();
// Interface factory for high level Veilid API
Veilid getVeilid() => VeilidFFI(_dylib);
// FFI implementation of high level Veilid API
class VeilidFFI {
// veilid_core shared library
final DynamicLibrary _dylib;
// Shared library functions
final _free_string_Dart _freeString;
final _startup_veilid_core_Dart _startupVeilidCore;
final _get_veilid_state_Dart _getVeilidState;
final _change_api_log_level_Dart _changeApiLogLevel;
final _shutdown_veilid_core_Dart _shutdownVeilidCore;
final _veilid_version_string_Dart _veilidVersionString;
final _veilid_version_Dat _veilidVersion;
VeilidFFI(DynamicLibrary dylib): _dylib = dylib {
var initializeVeilidFlutter = _dylib.lookupFunction<_initializeVeilidFlutter_C, _initializeVeilidFlutter_Dart>('initialize_veilid_flutter');
initializeVeilidFlutter(NativeApi.postCObject);
// Look up shared library functions
_freeString = dylib.lookupFunction<_free_string_C, _free_string_Dart>('free_string');
_startupVeilidCore = dylib.lookupFunction<_startup_veilid_core_C, _startup_veilid_core_Dart>('startup_veilid_core');
_getveilidState = dylib.lookupFunction<_get_veilid_state_C, _get_veilid_state_Dart>('get_veilid_state');
_changeApiLogLevel = dylib.lookupFunction<_change_api_log_level_C, _change_api_log_level_Dart>('change_api_log_level');
_shutdownVeilidCore = dylib.lookupFunction<_shutdown_veilid_core_C, _shutdown_veilid_core_Dart>('shutdown_veilid_core');
_veilidVersionString = dylib.lookupFunction<_veilid_version_string_C, _veilid_version_string_Dart>('veilid_version_string');
_veilidVersion = dylib.lookupFunction<_veilid_version_C, _veilid_version_Dart>('veilid_version');
}
Stream<VeilidUpdate> startupVeilidCore(String config);
Future<Result<VeilidState, VeilidAPIError>> getVeilidState();
Future<Result<Unit, VeilidAPIError>> changeApiLogLevel(VeilidLogLevel logLevel);
Future<Result<Unit, VeilidAPIError>> shutdownVeilidCore() async {
// xxx continue here
}
String veilidVersionString() {
final version_string = _veilidVersionString();
String ret = version_string.toDartString();
_freeString(version_string);
return version_string;
}
VeilidVersion veilidVersion() {
return _veilidVersion();
}
}

View File

@ -0,0 +1,41 @@
import 'veilid.dart';
import 'dart:js';
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:oxidized/oxidized.dart';
//////////////////////////////////////////////////////////
Veilid getVeilid() => VeilidJS();
class VeilidJS {
Stream<VeilidUpdate> startupVeilidCore(Object? configCallback(String key)) {
throw UnimplementedError();
}
Future<VeilidState> getVeilidState() {
throw UnimplementedError();
}
Future<void> changeApiLogLevel(VeilidLogLevel logLevel) {
throw UnimplementedError();
}
Future<void> shutdownVeilidCore() {
throw UnimplementedError();
}
Future<String> veilidVersionString() {
throw UnimplementedError();
}
Future<VeilidVersion> veilidVersion() {
throw UnimplementedError();
}
}

View File

@ -11,7 +11,7 @@ import 'package:flutter_web_plugins/flutter_web_plugins.dart';
// xxx link in WASM version of veilid-flutter // xxx link in WASM version of veilid-flutter
/// A web implementation of the Veilid plugin. /// A web implementation of the Veilid plugin.
class VeilidWeb { class VeilidPluginStubWeb {
static void registerWith(Registrar registrar) { static void registerWith(Registrar registrar) {
// final MethodChannel channel = MethodChannel( // final MethodChannel channel = MethodChannel(
// 'veilid', // 'veilid',

View File

@ -0,0 +1,3 @@
import 'veilid.dart'
Veilid getVeilid() => throw UnsupportedError('Cannot create Veilid object');

View File

@ -15,6 +15,8 @@ dependencies:
sdk: flutter sdk: flutter
flutter_rust_bridge: ^1.14.0 flutter_rust_bridge: ^1.14.0
freezed_annotation: ^1.1.0 freezed_annotation: ^1.1.0
oxidized: ^5.1.0
ffi: ^1.1.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@ -46,8 +48,8 @@ flutter:
windows: windows:
pluginClass: VeilidPlugin pluginClass: VeilidPlugin
web: web:
pluginClass: VeilidWeb pluginClass: VeilidPluginStubWeb
fileName: veilid_web.dart fileName: veilid_plugin_stub_web.dart
# To add assets to your plugin package, add an assets section, like this: # To add assets to your plugin package, add an assets section, like this:
# assets: # assets:

View File

@ -4,16 +4,39 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[lib] [lib]
crate-type = ["cdylib", "staticlib"] crate-type = ["cdylib", "staticlib", "rlib"]
[dependencies] [dependencies]
async-std = { version = "^1", features = ["unstable"] }
veilid-core = { path="../../veilid-core" } veilid-core = { path="../../veilid-core" }
flutter_rust_bridge = "^1"
parking_lot = "^0" parking_lot = "^0"
log = "^0" log = "^0"
anyhow = { version = "^1", features = ["backtrace"] }
cfg-if = "^1" cfg-if = "^1"
backtrace = "^0"
serde_json = "^1"
serde = "^1"
futures = "^0"
# Dependencies for native builds only
# Linux, Windows, Mac, iOS, Android
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
async-std = { version = "^1", features = ["unstable"] }
anyhow = { version = "^1", features = ["backtrace"] }
allo-isolate = "^0"
ffi-support = "^0"
lazy_static = "^1"
# Dependencies for WASM builds only
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "^0"
console_error_panic_hook = "^0"
wee_alloc = "^0"
wasm-logger = "^0"
wasm-bindgen-futures = "^0"
js-sys = "^0"
# Dev Dependencies for WASM builds only
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "^0"
[build-dependencies] [build-dependencies]
cfg-if = "^1" cfg-if = "^1"

View File

@ -1,155 +0,0 @@
use cfg_if::*;
use std::env;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::process::Command;
fn resolve_llvm_path() -> Option<PathBuf> {
cfg_if! {
if #[cfg(target_os="linux")] {
// build host is linux
let paths: Vec<PathBuf> =
env::var_os("PATH").map(|paths| env::split_paths(&paths).collect())?;
// find clang
let d = paths.iter().find_map(|p| {
if p.join("clang").exists() {
if let Ok(real_clang_path) = std::fs::canonicalize(p.join("clang")) {
if let Some(llvmbindir) = real_clang_path.parent() {
if let Some(llvmdir) = llvmbindir.parent() {
return Some(llvmdir.to_owned());
}
}
}
}
None
});
d.or_else(|| {
["/usr/lib/llvm-13", "/usr/lib/llvm-12", "/usr/lib/llvm-11", "/usr/lib/llvm-10"].iter().map(Path::new).find_map(|p| if p.exists() { Some(p.to_owned()) } else { None } )
})
} else if #[cfg(target_os="macos")] {
// build host is mac
["/usr/local/opt/llvm", "/opt/homebrew/opt/llvm", ].iter().map(Path::new).find_map(|p| if p.exists() { Some(p.to_owned()) } else { None } )
} else {
// anywhere else, just use the default paths
None
}
}
}
fn main() {
//let out_dir = env::var_os("OUT_DIR").unwrap();
let manifest_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap();
let input_path = Path::new(&manifest_dir).join("src").join("api.rs");
let output_path = Path::new(&manifest_dir)
.parent()
.unwrap()
.join("lib")
.join("bridge_generated.dart");
let c_path = Path::new(&manifest_dir)
.parent()
.unwrap()
.join("ios")
.join("Classes")
.join("bridge_generated.h");
let llvm_path = resolve_llvm_path();
//eprintln!("input_path: {:?}", input_path);
//eprintln!("output_path: {:?}", output_path);
//eprintln!("c_path: {:?}", c_path);
//eprintln!("llvm_path: {:?}", llvm_path);
let mut command = Command::new("flutter_rust_bridge_codegen");
if let Some(llvm_path) = llvm_path {
command.args([
OsStr::new("--rust-input"),
input_path.as_os_str(),
OsStr::new("--dart-output"),
output_path.as_os_str(),
OsStr::new("--c-output"),
c_path.as_os_str(),
OsStr::new("--llvm-path"),
llvm_path.as_os_str(),
]);
} else {
command.args([
OsStr::new("--rust-input"),
input_path.as_os_str(),
OsStr::new("--dart-output"),
output_path.as_os_str(),
OsStr::new("--c-output"),
c_path.as_os_str(),
]);
}
let mut child = command
.spawn()
.expect("flutter_rust_bridge_codegen did not execute correctly");
child
.wait()
.expect("flutter_rust_bridge_codegen was not running");
// Flutter pub get
// Run: flutter pub get
let mut command;
cfg_if! {
if #[cfg(target_os="windows")] {
command = Command::new("cmd");
command.args([
OsStr::new("/c"),
OsStr::new("flutter"),
OsStr::new("pub"),
OsStr::new("get"),
]);
} else {
command = Command::new("flutter");
command.args([
OsStr::new("pub"),
OsStr::new("get"),
]);
}
}
let mut child = command
.spawn()
.expect("'flutter pub get' did not execute correctly");
child.wait().expect("'flutter pub get' was not running");
// Build freezed
// Run: flutter pub run build_runner build
let mut command;
cfg_if! {
if #[cfg(target_os="windows")] {
command = Command::new("cmd");
command.args([
OsStr::new("/c"),
OsStr::new("flutter"),
OsStr::new("pub"),
OsStr::new("run"),
OsStr::new("build_runner"),
OsStr::new("build"),
]);
} else {
command = Command::new("flutter");
command.args([
OsStr::new("pub"),
OsStr::new("run"),
OsStr::new("build_runner"),
OsStr::new("build"),
OsStr::new("--delete-conflicting-outputs"),
]);
}
}
let mut child = command
.spawn()
.expect("'flutter pub run build_runner build' did not execute correctly");
child
.wait()
.expect("'flutter pub run build_runner build' was not running");
}

View File

@ -1,608 +0,0 @@
use anyhow::*;
use async_std::sync::Mutex as AsyncMutex;
use cfg_if::*;
use flutter_rust_bridge::*;
use log::*;
use std::fmt;
use std::sync::Arc;
// Globals
static VEILID_API: AsyncMutex<Option<veilid_core::VeilidAPI>> = AsyncMutex::new(None);
async fn get_veilid_api() -> Result<veilid_core::VeilidAPI> {
let api_lock = VEILID_API.lock().await;
let veilid_api = match &*api_lock {
None => {
return Err(anyhow!(VeilidAPIError::NotInitialized));
}
Some(api) => api.clone(),
};
Ok(veilid_api)
}
async fn take_veilid_api() -> Result<veilid_core::VeilidAPI> {
let mut api_lock = VEILID_API.lock().await;
let veilid_api = match api_lock.take() {
None => {
return Err(anyhow!(VeilidAPIError::NotInitialized));
}
Some(api) => api,
};
Ok(veilid_api)
}
/////////////////////////////////////////
// Config Settings
// Not all settings available through Veilid API are available to Flutter applications
#[derive(Debug, Default, Clone)]
#[allow(non_snake_case)]
pub struct VeilidConfig {
pub program_name: String,
pub veilid_namespace: String,
pub api_log_level: VeilidLogLevel,
// Capabilities
pub capabilities__protocol_udp: bool,
pub capabilities__protocol_connect_tcp: bool,
pub capabilities__protocol_accept_tcp: bool,
pub capabilities__protocol_connect_ws: bool,
pub capabilities__protocol_accept_ws: bool,
pub capabilities__protocol_connect_wss: bool,
pub capabilities__protocol_accept_wss: bool,
// Protected Store
pub protected_store__allow_insecure_fallback: bool,
pub protected_store__always_use_insecure_storage: bool,
pub protected_store__insecure_fallback_directory: String,
pub protected_store__delete: bool,
// Table Store
pub table_store__directory: String,
pub table_store__delete: bool,
// Block Store
pub block_store__directory: String,
pub block_store__delete: bool,
// Network
pub network__max_connections: u32,
pub network__connection_initial_timeout_ms: u32,
pub network__node_id: String,
pub network__node_id_secret: String,
pub network__bootstrap: Vec<String>,
pub network__upnp: bool,
pub network__natpmp: bool,
pub network__enable_local_peer_scope: bool,
pub network__restricted_nat_retries: u32,
// Network / RPC
pub network__rpc__concurrency: u32,
pub network__rpc__queue_size: u32,
pub network__rpc__max_timestamp_behind_ms: Option<u32>,
pub network__rpc__max_timestamp_ahead_ms: Option<u32>,
pub network__rpc__timeout_ms: u32,
pub network__rpc__max_route_hop_count: u8,
// Network / DHT
pub network__dht__resolve_node_timeout_ms: Option<u32>,
pub network__dht__resolve_node_count: u32,
pub network__dht__resolve_node_fanout: u32,
pub network__dht__max_find_node_count: u32,
pub network__dht__get_value_timeout_ms: Option<u32>,
pub network__dht__get_value_count: u32,
pub network__dht__get_value_fanout: u32,
pub network__dht__set_value_timeout_ms: Option<u32>,
pub network__dht__set_value_count: u32,
pub network__dht__set_value_fanout: u32,
pub network__dht__min_peer_count: u32,
pub network__dht__min_peer_refresh_time_ms: u32,
pub network__dht__validate_dial_info_receipt_time_ms: u32,
// Network / Protocol
// Network / Protocol / UDP
pub network__protocol__udp__enabled: bool,
pub network__protocol__udp__socket_pool_size: u32,
pub network__protocol__udp__listen_address: String,
pub network__protocol__udp__public_address: Option<String>,
// Network / Protocol / TCP
pub network__protocol__tcp__connect: bool,
pub network__protocol__tcp__listen: bool,
pub network__protocol__tcp__max_connections: u32,
pub network__protocol__tcp__listen_address: String,
pub network__protocol__tcp__public_address: Option<String>,
// Network / Protocol / WS
pub network__protocol__ws__connect: bool,
pub network__protocol__ws__listen: bool,
pub network__protocol__ws__max_connections: u32,
pub network__protocol__ws__listen_address: String,
pub network__protocol__ws__path: String,
pub network__protocol__ws__url: Option<String>,
// Network / Protocol / WSS
pub network__protocol__wss__connect: bool,
pub network__protocol__wss__max_connections: u32,
// Network / Leases
pub network__leases__max_server_signal_leases: u32,
pub network__leases__max_server_relay_leases: u32,
pub network__leases__max_client_signal_leases: u32,
pub network__leases__max_client_relay_leases: u32,
}
cfg_if! {
if #[cfg(target_arch="wasm32")] {
} else {
}
}
cfg_if! {
if #[cfg(target_arch="wasm32")] {
type ConfigReturn = Box<dyn std::any::Any + 'static>;
} else {
type ConfigReturn = Box<dyn std::any::Any + Send + 'static>;
}
}
impl VeilidConfig {
pub fn get_by_str(&self, key: &str) -> std::result::Result<ConfigReturn, String> {
let out: ConfigReturn = match key {
"program_name" => Box::new(self.program_name.clone()),
"namespace" => Box::new(self.veilid_namespace.clone()),
"api_log_level" => Box::new(self.api_log_level.to_config_log_level()),
"capabilities.protocol_udp" => Box::new(self.capabilities__protocol_udp.clone()),
"capabilities.protocol_connect_tcp" => {
Box::new(self.capabilities__protocol_connect_tcp.clone())
}
"capabilities.protocol_accept_tcp" => {
Box::new(self.capabilities__protocol_accept_tcp.clone())
}
"capabilities.protocol_connect_ws" => {
Box::new(self.capabilities__protocol_connect_ws.clone())
}
"capabilities.protocol_accept_ws" => {
Box::new(self.capabilities__protocol_accept_ws.clone())
}
"capabilities.protocol_connect_wss" => {
Box::new(self.capabilities__protocol_connect_wss.clone())
}
"capabilities.protocol_accept_wss" => {
Box::new(self.capabilities__protocol_accept_wss.clone())
}
"table_store.directory" => Box::new(self.table_store__directory.clone()),
"table_store.delete" => Box::new(self.table_store__delete.clone()),
"block_store.directory" => Box::new(self.block_store__directory.clone()),
"block_store.delete" => Box::new(self.block_store__delete.clone()),
"protected_store.allow_insecure_fallback" => {
Box::new(self.protected_store__allow_insecure_fallback.clone())
}
"protected_store.always_use_insecure_storage" => {
Box::new(self.protected_store__always_use_insecure_storage.clone())
}
"protected_store.insecure_fallback_directory" => {
Box::new(self.protected_store__insecure_fallback_directory.clone())
}
"protected_store.delete" => Box::new(self.protected_store__delete.clone()),
"network.node_id" => Box::new(self.network__node_id.clone()),
"network.node_id_secret" => Box::new(self.network__node_id_secret.clone()),
"network.max_connections" => Box::new(self.network__max_connections.clone()),
"network.connection_initial_timeout_ms" => {
Box::new(self.network__connection_initial_timeout_ms.clone())
}
"network.bootstrap" => Box::new(self.network__bootstrap.clone()),
"network.dht.resolve_node_timeout_ms" => {
Box::new(self.network__dht__resolve_node_timeout_ms.clone())
}
"network.dht.resolve_node_count" => {
Box::new(self.network__dht__resolve_node_count.clone())
}
"network.dht.resolve_node_fanout" => {
Box::new(self.network__dht__resolve_node_fanout.clone())
}
"network.dht.max_find_node_count" => {
Box::new(self.network__dht__max_find_node_count.clone())
}
"network.dht.get_value_timeout_ms" => {
Box::new(self.network__dht__get_value_timeout_ms.clone())
}
"network.dht.get_value_count" => Box::new(self.network__dht__get_value_count.clone()),
"network.dht.get_value_fanout" => Box::new(self.network__dht__get_value_fanout.clone()),
"network.dht.set_value_timeout_ms" => {
Box::new(self.network__dht__set_value_timeout_ms.clone())
}
"network.dht.set_value_count" => Box::new(self.network__dht__set_value_count.clone()),
"network.dht.set_value_fanout" => Box::new(self.network__dht__set_value_fanout.clone()),
"network.dht.min_peer_count" => Box::new(self.network__dht__min_peer_count.clone()),
"network.dht.min_peer_refresh_time_ms" => {
Box::new(self.network__dht__min_peer_refresh_time_ms.clone())
}
"network.dht.validate_dial_info_receipt_time_ms" => Box::new(
self.network__dht__validate_dial_info_receipt_time_ms
.clone(),
),
"network.rpc.concurrency" => Box::new(self.network__rpc__concurrency.clone()),
"network.rpc.queue_size" => Box::new(self.network__rpc__queue_size.clone()),
"network.rpc.max_timestamp_behind_ms" => {
Box::new(self.network__rpc__max_timestamp_behind_ms.clone())
}
"network.rpc.max_timestamp_ahead_ms" => {
Box::new(self.network__rpc__max_timestamp_ahead_ms.clone())
}
"network.rpc.timeout_ms" => Box::new(self.network__rpc__timeout_ms.clone()),
"network.rpc.max_route_hop_count" => {
Box::new(self.network__rpc__max_route_hop_count.clone())
}
"network.upnp" => Box::new(self.network__upnp.clone()),
"network.natpmp" => Box::new(self.network__natpmp.clone()),
"network.enable_local_peer_scope" => {
Box::new(self.network__enable_local_peer_scope.clone())
}
"network.restricted_nat_retries" => {
Box::new(self.network__restricted_nat_retries.clone())
}
"network.tls.certificate_path" => Box::new("".to_owned()),
"network.tls.private_key_path" => Box::new("".to_owned()),
"network.tls.connection_initial_timeout" => Box::new(0u32),
"network.application.https.enabled" => Box::new(false),
"network.application.https.listen_address" => Box::new("".to_owned()),
"network.application.https.path" => Box::new("".to_owned()),
"network.application.https.url" => Box::new(Option::<String>::None),
"network.application.http.enabled" => Box::new(false),
"network.application.http.listen_address" => Box::new("".to_owned()),
"network.application.http.path" => Box::new("".to_owned()),
"network.application.http.url" => Box::new(Option::<String>::None),
"network.protocol.udp.enabled" => {
Box::new(self.network__protocol__udp__enabled.clone())
}
"network.protocol.udp.socket_pool_size" => {
Box::new(self.network__protocol__udp__socket_pool_size.clone())
}
"network.protocol.udp.listen_address" => {
Box::new(self.network__protocol__udp__listen_address.clone())
}
"network.protocol.udp.public_address" => {
Box::new(self.network__protocol__udp__public_address.clone())
}
"network.protocol.tcp.connect" => {
Box::new(self.network__protocol__tcp__connect.clone())
}
"network.protocol.tcp.listen" => Box::new(self.network__protocol__tcp__listen.clone()),
"network.protocol.tcp.max_connections" => {
Box::new(self.network__protocol__tcp__max_connections.clone())
}
"network.protocol.tcp.listen_address" => {
Box::new(self.network__protocol__tcp__listen_address.clone())
}
"network.protocol.tcp.public_address" => {
Box::new(self.network__protocol__tcp__public_address.clone())
}
"network.protocol.ws.connect" => Box::new(self.network__protocol__ws__connect.clone()),
"network.protocol.ws.listen" => Box::new(self.network__protocol__ws__listen.clone()),
"network.protocol.ws.max_connections" => {
Box::new(self.network__protocol__ws__max_connections.clone())
}
"network.protocol.ws.listen_address" => {
Box::new(self.network__protocol__ws__listen_address.clone())
}
"network.protocol.ws.path" => Box::new(self.network__protocol__ws__path.clone()),
"network.protocol.ws.url" => Box::new(self.network__protocol__ws__url.clone()),
"network.protocol.wss.connect" => {
Box::new(self.network__protocol__wss__connect.clone())
}
"network.protocol.wss.listen" => Box::new(false),
"network.protocol.wss.max_connections" => {
Box::new(self.network__protocol__wss__max_connections.clone())
}
"network.protocol.wss.listen_address" => Box::new("".to_owned()),
"network.protocol.wss.path" => Box::new("".to_owned()),
"network.protocol.wss.url" => Box::new(Option::<String>::None),
"network.leases.max_server_signal_leases" => {
Box::new(self.network__leases__max_server_signal_leases.clone())
}
"network.leases.max_server_relay_leases" => {
Box::new(self.network__leases__max_server_relay_leases.clone())
}
"network.leases.max_client_signal_leases" => {
Box::new(self.network__leases__max_client_signal_leases.clone())
}
"network.leases.max_client_relay_leases" => {
Box::new(self.network__leases__max_client_relay_leases.clone())
}
_ => {
let err = format!("config key '{}' doesn't exist", key);
error!("{}", err);
return Err(err);
}
};
std::result::Result::Ok(out)
}
}
/////////////////////////////////////////
#[derive(Debug)]
pub enum VeilidAPIError {
AlreadyInitialized,
NotInitialized,
InvalidConfig(String),
Timeout,
Shutdown,
NodeNotFound(String),
NoDialInfo(String),
Internal(String),
Unimplemented(String),
ParseError {
message: String,
value: String,
},
InvalidArgument {
context: String,
argument: String,
value: String,
},
MissingArgument {
context: String,
argument: String,
},
}
impl fmt::Display for VeilidAPIError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
VeilidAPIError::AlreadyInitialized => write!(f, "VeilidAPIError::AlreadyInitialized"),
VeilidAPIError::NotInitialized => write!(f, "VeilidAPIError::NotInitialized"),
VeilidAPIError::InvalidConfig(e) => write!(f, "VeilidAPIError::InvalidConfig({})", e),
VeilidAPIError::Timeout => write!(f, "VeilidAPIError::Timeout"),
VeilidAPIError::Shutdown => write!(f, "VeilidAPIError::Shutdown"),
VeilidAPIError::NodeNotFound(ni) => write!(f, "VeilidAPIError::NodeNotFound({})", ni),
VeilidAPIError::NoDialInfo(ni) => write!(f, "VeilidAPIError::NoDialInfo({})", ni),
VeilidAPIError::Internal(e) => write!(f, "VeilidAPIError::Internal({})", e),
VeilidAPIError::Unimplemented(e) => write!(f, "VeilidAPIError::Unimplemented({})", e),
VeilidAPIError::ParseError { message, value } => {
write!(f, "VeilidAPIError::ParseError({}: {})", message, value)
}
VeilidAPIError::InvalidArgument {
context,
argument,
value,
} => {
write!(
f,
"VeilidAPIError::InvalidArgument({}: {} = {})",
context, argument, value
)
}
VeilidAPIError::MissingArgument { context, argument } => {
write!(
f,
"VeilidAPIError::MissingArgument({}: {})",
context, argument
)
}
}
}
}
impl std::error::Error for VeilidAPIError {}
impl VeilidAPIError {
fn from_core(api_error: veilid_core::VeilidAPIError) -> Self {
match api_error {
veilid_core::VeilidAPIError::Timeout => VeilidAPIError::Timeout,
veilid_core::VeilidAPIError::Shutdown => VeilidAPIError::Shutdown,
veilid_core::VeilidAPIError::NodeNotFound(node_id) => {
VeilidAPIError::NodeNotFound(format!("{}", node_id))
}
veilid_core::VeilidAPIError::NoDialInfo(node_id) => {
VeilidAPIError::NodeNotFound(format!("{}", node_id))
}
veilid_core::VeilidAPIError::Internal(msg) => VeilidAPIError::Internal(msg.clone()),
veilid_core::VeilidAPIError::Unimplemented(msg) => {
VeilidAPIError::Unimplemented(msg.clone())
}
veilid_core::VeilidAPIError::ParseError { message, value } => {
VeilidAPIError::ParseError {
message: message.clone(),
value: value.clone(),
}
}
veilid_core::VeilidAPIError::InvalidArgument {
context,
argument,
value,
} => VeilidAPIError::InvalidArgument {
context: context.clone(),
argument: argument.clone(),
value: value.clone(),
},
veilid_core::VeilidAPIError::MissingArgument { context, argument } => {
VeilidAPIError::MissingArgument {
context: context.clone(),
argument: argument.clone(),
}
}
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum AttachmentState {
Detached,
Attaching,
AttachedWeak,
AttachedGood,
AttachedStrong,
FullyAttached,
OverAttached,
Detaching,
}
impl AttachmentState {
fn from_core(attachment_state: veilid_core::AttachmentState) -> Self {
match attachment_state {
veilid_core::AttachmentState::Detached => AttachmentState::Detached,
veilid_core::AttachmentState::Attaching => AttachmentState::Attaching,
veilid_core::AttachmentState::AttachedWeak => AttachmentState::AttachedWeak,
veilid_core::AttachmentState::AttachedGood => AttachmentState::AttachedGood,
veilid_core::AttachmentState::AttachedStrong => AttachmentState::AttachedStrong,
veilid_core::AttachmentState::FullyAttached => AttachmentState::FullyAttached,
veilid_core::AttachmentState::OverAttached => AttachmentState::OverAttached,
veilid_core::AttachmentState::Detaching => AttachmentState::Detaching,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum VeilidLogLevel {
Error,
Warn,
Info,
Debug,
Trace,
}
impl Default for VeilidLogLevel {
fn default() -> Self {
Self::Info
}
}
impl VeilidLogLevel {
fn from_core(level: veilid_core::VeilidLogLevel) -> Self {
match level {
veilid_core::VeilidLogLevel::Error => VeilidLogLevel::Error,
veilid_core::VeilidLogLevel::Warn => VeilidLogLevel::Warn,
veilid_core::VeilidLogLevel::Info => VeilidLogLevel::Info,
veilid_core::VeilidLogLevel::Debug => VeilidLogLevel::Debug,
veilid_core::VeilidLogLevel::Trace => VeilidLogLevel::Trace,
}
}
fn to_config_log_level(&self) -> veilid_core::VeilidConfigLogLevel {
match self {
Self::Error => veilid_core::VeilidConfigLogLevel::Error,
Self::Warn => veilid_core::VeilidConfigLogLevel::Warn,
Self::Info => veilid_core::VeilidConfigLogLevel::Info,
Self::Debug => veilid_core::VeilidConfigLogLevel::Debug,
Self::Trace => veilid_core::VeilidConfigLogLevel::Trace,
}
}
}
#[derive(Debug, Clone)]
pub enum VeilidUpdate {
Log {
log_level: VeilidLogLevel,
message: String,
},
Attachment(AttachmentState),
}
impl VeilidUpdate {
fn from_core(veilid_update: veilid_core::VeilidUpdate) -> Self {
match veilid_update {
veilid_core::VeilidUpdate::Log { log_level, message } => Self::Log {
log_level: VeilidLogLevel::from_core(log_level),
message,
},
veilid_core::VeilidUpdate::Attachment(attachment) => {
Self::Attachment(AttachmentState::from_core(attachment))
}
}
}
}
#[derive(Debug, Clone)]
pub struct VeilidState {
pub attachment: AttachmentState,
}
impl VeilidState {
fn from_core(veilid_state: veilid_core::VeilidState) -> Self {
Self {
attachment: AttachmentState::from_core(veilid_state.attachment),
}
}
}
/////////////////////////////////////////
pub fn startup_veilid_core(
sink: StreamSink<VeilidUpdate>,
config: VeilidConfig,
) -> Result<VeilidState> {
async_std::task::block_on(async {
let mut api_lock = VEILID_API.lock().await;
if api_lock.is_some() {
return Err(anyhow!(VeilidAPIError::AlreadyInitialized));
}
let core = veilid_core::VeilidCore::new();
let setup = veilid_core::VeilidCoreSetup {
update_callback: Arc::new(
move |update: veilid_core::VeilidUpdate| -> veilid_core::SystemPinBoxFuture<()> {
let sink = sink.clone();
Box::pin(async move {
if !sink.add(VeilidUpdate::from_core(update)) {
error!("error sending veilid update callback");
}
})
},
),
config_callback: Arc::new(move |key| config.get_by_str(&key)),
};
let veilid_api = core
.startup(setup)
.await
.map_err(|e| VeilidAPIError::InvalidConfig(e.clone()))?;
*api_lock = Some(veilid_api.clone());
let core_state = veilid_api
.get_state()
.await
.map_err(VeilidAPIError::from_core)?;
Ok(VeilidState::from_core(core_state))
})
}
pub fn get_veilid_state() -> Result<VeilidState> {
async_std::task::block_on(async {
let veilid_api = get_veilid_api().await?;
let core_state = veilid_api
.get_state()
.await
.map_err(VeilidAPIError::from_core)?;
Ok(VeilidState::from_core(core_state))
})
}
// xxx api functions
pub fn change_api_log_level(log_level: VeilidLogLevel) -> Result<()> {
async_std::task::block_on(async {
let veilid_api = get_veilid_api().await?;
veilid_api
.change_api_log_level(log_level.to_config_log_level())
.await;
Ok(())
})
}
pub fn shutdown_veilid_core() -> Result<()> {
async_std::task::block_on(async {
let veilid_api = get_veilid_api().await?;
veilid_api.shutdown().await;
Ok(())
})
}
pub fn veilid_version_string() -> Result<String> {
Ok(veilid_core::veilid_version_string())
}
pub struct VeilidVersion {
pub major: u32,
pub minor: u32,
pub patch: u32,
}
pub fn veilid_version() -> Result<VeilidVersion> {
let (major, minor, patch) = veilid_core::veilid_version();
Ok(VeilidVersion {
major,
minor,
patch,
})
}

View File

@ -1,581 +0,0 @@
#![allow(
non_camel_case_types,
unused,
clippy::redundant_closure,
clippy::useless_conversion,
non_snake_case
)]
// AUTO GENERATED FILE, DO NOT EDIT.
// Generated by `flutter_rust_bridge`.
use crate::api::*;
use flutter_rust_bridge::*;
// Section: wire functions
#[no_mangle]
pub extern "C" fn wire_startup_veilid_core(port_: i64, config: *mut wire_VeilidConfig) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap(
WrapInfo {
debug_name: "startup_veilid_core",
port: Some(port_),
mode: FfiCallMode::Stream,
},
move || {
let api_config = config.wire2api();
move |task_callback| startup_veilid_core(task_callback.stream_sink(), api_config)
},
)
}
#[no_mangle]
pub extern "C" fn wire_get_veilid_state(port_: i64) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap(
WrapInfo {
debug_name: "get_veilid_state",
port: Some(port_),
mode: FfiCallMode::Normal,
},
move || move |task_callback| get_veilid_state(),
)
}
#[no_mangle]
pub extern "C" fn wire_change_api_log_level(port_: i64, log_level: i32) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap(
WrapInfo {
debug_name: "change_api_log_level",
port: Some(port_),
mode: FfiCallMode::Normal,
},
move || {
let api_log_level = log_level.wire2api();
move |task_callback| change_api_log_level(api_log_level)
},
)
}
#[no_mangle]
pub extern "C" fn wire_shutdown_veilid_core(port_: i64) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap(
WrapInfo {
debug_name: "shutdown_veilid_core",
port: Some(port_),
mode: FfiCallMode::Normal,
},
move || move |task_callback| shutdown_veilid_core(),
)
}
#[no_mangle]
pub extern "C" fn wire_veilid_version_string(port_: i64) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap(
WrapInfo {
debug_name: "veilid_version_string",
port: Some(port_),
mode: FfiCallMode::Normal,
},
move || move |task_callback| veilid_version_string(),
)
}
#[no_mangle]
pub extern "C" fn wire_veilid_version(port_: i64) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap(
WrapInfo {
debug_name: "veilid_version",
port: Some(port_),
mode: FfiCallMode::Normal,
},
move || move |task_callback| veilid_version(),
)
}
// Section: wire structs
#[repr(C)]
#[derive(Clone)]
pub struct wire_StringList {
ptr: *mut *mut wire_uint_8_list,
len: i32,
}
#[repr(C)]
#[derive(Clone)]
pub struct wire_uint_8_list {
ptr: *mut u8,
len: i32,
}
#[repr(C)]
#[derive(Clone)]
pub struct wire_VeilidConfig {
program_name: *mut wire_uint_8_list,
veilid_namespace: *mut wire_uint_8_list,
api_log_level: i32,
capabilities__protocol_udp: bool,
capabilities__protocol_connect_tcp: bool,
capabilities__protocol_accept_tcp: bool,
capabilities__protocol_connect_ws: bool,
capabilities__protocol_accept_ws: bool,
capabilities__protocol_connect_wss: bool,
capabilities__protocol_accept_wss: bool,
protected_store__allow_insecure_fallback: bool,
protected_store__always_use_insecure_storage: bool,
protected_store__insecure_fallback_directory: *mut wire_uint_8_list,
protected_store__delete: bool,
table_store__directory: *mut wire_uint_8_list,
table_store__delete: bool,
block_store__directory: *mut wire_uint_8_list,
block_store__delete: bool,
network__max_connections: u32,
network__connection_initial_timeout_ms: u32,
network__node_id: *mut wire_uint_8_list,
network__node_id_secret: *mut wire_uint_8_list,
network__bootstrap: *mut wire_StringList,
network__upnp: bool,
network__natpmp: bool,
network__enable_local_peer_scope: bool,
network__restricted_nat_retries: u32,
network__rpc__concurrency: u32,
network__rpc__queue_size: u32,
network__rpc__max_timestamp_behind_ms: *mut u32,
network__rpc__max_timestamp_ahead_ms: *mut u32,
network__rpc__timeout_ms: u32,
network__rpc__max_route_hop_count: u8,
network__dht__resolve_node_timeout_ms: *mut u32,
network__dht__resolve_node_count: u32,
network__dht__resolve_node_fanout: u32,
network__dht__max_find_node_count: u32,
network__dht__get_value_timeout_ms: *mut u32,
network__dht__get_value_count: u32,
network__dht__get_value_fanout: u32,
network__dht__set_value_timeout_ms: *mut u32,
network__dht__set_value_count: u32,
network__dht__set_value_fanout: u32,
network__dht__min_peer_count: u32,
network__dht__min_peer_refresh_time_ms: u32,
network__dht__validate_dial_info_receipt_time_ms: u32,
network__protocol__udp__enabled: bool,
network__protocol__udp__socket_pool_size: u32,
network__protocol__udp__listen_address: *mut wire_uint_8_list,
network__protocol__udp__public_address: *mut wire_uint_8_list,
network__protocol__tcp__connect: bool,
network__protocol__tcp__listen: bool,
network__protocol__tcp__max_connections: u32,
network__protocol__tcp__listen_address: *mut wire_uint_8_list,
network__protocol__tcp__public_address: *mut wire_uint_8_list,
network__protocol__ws__connect: bool,
network__protocol__ws__listen: bool,
network__protocol__ws__max_connections: u32,
network__protocol__ws__listen_address: *mut wire_uint_8_list,
network__protocol__ws__path: *mut wire_uint_8_list,
network__protocol__ws__url: *mut wire_uint_8_list,
network__protocol__wss__connect: bool,
network__protocol__wss__max_connections: u32,
network__leases__max_server_signal_leases: u32,
network__leases__max_server_relay_leases: u32,
network__leases__max_client_signal_leases: u32,
network__leases__max_client_relay_leases: u32,
}
// Section: wire enums
// Section: allocate functions
#[no_mangle]
pub extern "C" fn new_StringList(len: i32) -> *mut wire_StringList {
let wrap = wire_StringList {
ptr: support::new_leak_vec_ptr(<*mut wire_uint_8_list>::new_with_null_ptr(), len),
len,
};
support::new_leak_box_ptr(wrap)
}
#[no_mangle]
pub extern "C" fn new_box_autoadd_u32(value: u32) -> *mut u32 {
support::new_leak_box_ptr(value)
}
#[no_mangle]
pub extern "C" fn new_box_autoadd_veilid_config() -> *mut wire_VeilidConfig {
support::new_leak_box_ptr(wire_VeilidConfig::new_with_null_ptr())
}
#[no_mangle]
pub extern "C" fn new_uint_8_list(len: i32) -> *mut wire_uint_8_list {
let ans = wire_uint_8_list {
ptr: support::new_leak_vec_ptr(Default::default(), len),
len,
};
support::new_leak_box_ptr(ans)
}
// Section: impl Wire2Api
pub trait Wire2Api<T> {
fn wire2api(self) -> T;
}
impl<T, S> Wire2Api<Option<T>> for *mut S
where
*mut S: Wire2Api<T>,
{
fn wire2api(self) -> Option<T> {
if self.is_null() {
None
} else {
Some(self.wire2api())
}
}
}
impl Wire2Api<String> for *mut wire_uint_8_list {
fn wire2api(self) -> String {
let vec: Vec<u8> = self.wire2api();
String::from_utf8_lossy(&vec).into_owned()
}
}
impl Wire2Api<Vec<String>> for *mut wire_StringList {
fn wire2api(self) -> Vec<String> {
let vec = unsafe {
let wrap = support::box_from_leak_ptr(self);
support::vec_from_leak_ptr(wrap.ptr, wrap.len)
};
vec.into_iter().map(Wire2Api::wire2api).collect()
}
}
impl Wire2Api<bool> for bool {
fn wire2api(self) -> bool {
self
}
}
impl Wire2Api<u32> for *mut u32 {
fn wire2api(self) -> u32 {
unsafe { *support::box_from_leak_ptr(self) }
}
}
impl Wire2Api<VeilidConfig> for *mut wire_VeilidConfig {
fn wire2api(self) -> VeilidConfig {
let wrap = unsafe { support::box_from_leak_ptr(self) };
(*wrap).wire2api().into()
}
}
impl Wire2Api<u32> for u32 {
fn wire2api(self) -> u32 {
self
}
}
impl Wire2Api<u8> for u8 {
fn wire2api(self) -> u8 {
self
}
}
impl Wire2Api<Vec<u8>> for *mut wire_uint_8_list {
fn wire2api(self) -> Vec<u8> {
unsafe {
let wrap = support::box_from_leak_ptr(self);
support::vec_from_leak_ptr(wrap.ptr, wrap.len)
}
}
}
impl Wire2Api<VeilidConfig> for wire_VeilidConfig {
fn wire2api(self) -> VeilidConfig {
VeilidConfig {
program_name: self.program_name.wire2api(),
veilid_namespace: self.veilid_namespace.wire2api(),
api_log_level: self.api_log_level.wire2api(),
capabilities__protocol_udp: self.capabilities__protocol_udp.wire2api(),
capabilities__protocol_connect_tcp: self.capabilities__protocol_connect_tcp.wire2api(),
capabilities__protocol_accept_tcp: self.capabilities__protocol_accept_tcp.wire2api(),
capabilities__protocol_connect_ws: self.capabilities__protocol_connect_ws.wire2api(),
capabilities__protocol_accept_ws: self.capabilities__protocol_accept_ws.wire2api(),
capabilities__protocol_connect_wss: self.capabilities__protocol_connect_wss.wire2api(),
capabilities__protocol_accept_wss: self.capabilities__protocol_accept_wss.wire2api(),
protected_store__allow_insecure_fallback: self
.protected_store__allow_insecure_fallback
.wire2api(),
protected_store__always_use_insecure_storage: self
.protected_store__always_use_insecure_storage
.wire2api(),
protected_store__insecure_fallback_directory: self
.protected_store__insecure_fallback_directory
.wire2api(),
protected_store__delete: self.protected_store__delete.wire2api(),
table_store__directory: self.table_store__directory.wire2api(),
table_store__delete: self.table_store__delete.wire2api(),
block_store__directory: self.block_store__directory.wire2api(),
block_store__delete: self.block_store__delete.wire2api(),
network__max_connections: self.network__max_connections.wire2api(),
network__connection_initial_timeout_ms: self
.network__connection_initial_timeout_ms
.wire2api(),
network__node_id: self.network__node_id.wire2api(),
network__node_id_secret: self.network__node_id_secret.wire2api(),
network__bootstrap: self.network__bootstrap.wire2api(),
network__upnp: self.network__upnp.wire2api(),
network__natpmp: self.network__natpmp.wire2api(),
network__enable_local_peer_scope: self.network__enable_local_peer_scope.wire2api(),
network__restricted_nat_retries: self.network__restricted_nat_retries.wire2api(),
network__rpc__concurrency: self.network__rpc__concurrency.wire2api(),
network__rpc__queue_size: self.network__rpc__queue_size.wire2api(),
network__rpc__max_timestamp_behind_ms: self
.network__rpc__max_timestamp_behind_ms
.wire2api(),
network__rpc__max_timestamp_ahead_ms: self
.network__rpc__max_timestamp_ahead_ms
.wire2api(),
network__rpc__timeout_ms: self.network__rpc__timeout_ms.wire2api(),
network__rpc__max_route_hop_count: self.network__rpc__max_route_hop_count.wire2api(),
network__dht__resolve_node_timeout_ms: self
.network__dht__resolve_node_timeout_ms
.wire2api(),
network__dht__resolve_node_count: self.network__dht__resolve_node_count.wire2api(),
network__dht__resolve_node_fanout: self.network__dht__resolve_node_fanout.wire2api(),
network__dht__max_find_node_count: self.network__dht__max_find_node_count.wire2api(),
network__dht__get_value_timeout_ms: self.network__dht__get_value_timeout_ms.wire2api(),
network__dht__get_value_count: self.network__dht__get_value_count.wire2api(),
network__dht__get_value_fanout: self.network__dht__get_value_fanout.wire2api(),
network__dht__set_value_timeout_ms: self.network__dht__set_value_timeout_ms.wire2api(),
network__dht__set_value_count: self.network__dht__set_value_count.wire2api(),
network__dht__set_value_fanout: self.network__dht__set_value_fanout.wire2api(),
network__dht__min_peer_count: self.network__dht__min_peer_count.wire2api(),
network__dht__min_peer_refresh_time_ms: self
.network__dht__min_peer_refresh_time_ms
.wire2api(),
network__dht__validate_dial_info_receipt_time_ms: self
.network__dht__validate_dial_info_receipt_time_ms
.wire2api(),
network__protocol__udp__enabled: self.network__protocol__udp__enabled.wire2api(),
network__protocol__udp__socket_pool_size: self
.network__protocol__udp__socket_pool_size
.wire2api(),
network__protocol__udp__listen_address: self
.network__protocol__udp__listen_address
.wire2api(),
network__protocol__udp__public_address: self
.network__protocol__udp__public_address
.wire2api(),
network__protocol__tcp__connect: self.network__protocol__tcp__connect.wire2api(),
network__protocol__tcp__listen: self.network__protocol__tcp__listen.wire2api(),
network__protocol__tcp__max_connections: self
.network__protocol__tcp__max_connections
.wire2api(),
network__protocol__tcp__listen_address: self
.network__protocol__tcp__listen_address
.wire2api(),
network__protocol__tcp__public_address: self
.network__protocol__tcp__public_address
.wire2api(),
network__protocol__ws__connect: self.network__protocol__ws__connect.wire2api(),
network__protocol__ws__listen: self.network__protocol__ws__listen.wire2api(),
network__protocol__ws__max_connections: self
.network__protocol__ws__max_connections
.wire2api(),
network__protocol__ws__listen_address: self
.network__protocol__ws__listen_address
.wire2api(),
network__protocol__ws__path: self.network__protocol__ws__path.wire2api(),
network__protocol__ws__url: self.network__protocol__ws__url.wire2api(),
network__protocol__wss__connect: self.network__protocol__wss__connect.wire2api(),
network__protocol__wss__max_connections: self
.network__protocol__wss__max_connections
.wire2api(),
network__leases__max_server_signal_leases: self
.network__leases__max_server_signal_leases
.wire2api(),
network__leases__max_server_relay_leases: self
.network__leases__max_server_relay_leases
.wire2api(),
network__leases__max_client_signal_leases: self
.network__leases__max_client_signal_leases
.wire2api(),
network__leases__max_client_relay_leases: self
.network__leases__max_client_relay_leases
.wire2api(),
}
}
}
impl Wire2Api<VeilidLogLevel> for i32 {
fn wire2api(self) -> VeilidLogLevel {
match self {
0 => VeilidLogLevel::Error,
1 => VeilidLogLevel::Warn,
2 => VeilidLogLevel::Info,
3 => VeilidLogLevel::Debug,
4 => VeilidLogLevel::Trace,
_ => unreachable!("Invalid variant for VeilidLogLevel: {}", self),
}
}
}
// Section: impl NewWithNullPtr
pub trait NewWithNullPtr {
fn new_with_null_ptr() -> Self;
}
impl<T> NewWithNullPtr for *mut T {
fn new_with_null_ptr() -> Self {
std::ptr::null_mut()
}
}
impl NewWithNullPtr for wire_VeilidConfig {
fn new_with_null_ptr() -> Self {
Self {
program_name: core::ptr::null_mut(),
veilid_namespace: core::ptr::null_mut(),
api_log_level: Default::default(),
capabilities__protocol_udp: Default::default(),
capabilities__protocol_connect_tcp: Default::default(),
capabilities__protocol_accept_tcp: Default::default(),
capabilities__protocol_connect_ws: Default::default(),
capabilities__protocol_accept_ws: Default::default(),
capabilities__protocol_connect_wss: Default::default(),
capabilities__protocol_accept_wss: Default::default(),
protected_store__allow_insecure_fallback: Default::default(),
protected_store__always_use_insecure_storage: Default::default(),
protected_store__insecure_fallback_directory: core::ptr::null_mut(),
protected_store__delete: Default::default(),
table_store__directory: core::ptr::null_mut(),
table_store__delete: Default::default(),
block_store__directory: core::ptr::null_mut(),
block_store__delete: Default::default(),
network__max_connections: Default::default(),
network__connection_initial_timeout_ms: Default::default(),
network__node_id: core::ptr::null_mut(),
network__node_id_secret: core::ptr::null_mut(),
network__bootstrap: core::ptr::null_mut(),
network__upnp: Default::default(),
network__natpmp: Default::default(),
network__enable_local_peer_scope: Default::default(),
network__restricted_nat_retries: Default::default(),
network__rpc__concurrency: Default::default(),
network__rpc__queue_size: Default::default(),
network__rpc__max_timestamp_behind_ms: core::ptr::null_mut(),
network__rpc__max_timestamp_ahead_ms: core::ptr::null_mut(),
network__rpc__timeout_ms: Default::default(),
network__rpc__max_route_hop_count: Default::default(),
network__dht__resolve_node_timeout_ms: core::ptr::null_mut(),
network__dht__resolve_node_count: Default::default(),
network__dht__resolve_node_fanout: Default::default(),
network__dht__max_find_node_count: Default::default(),
network__dht__get_value_timeout_ms: core::ptr::null_mut(),
network__dht__get_value_count: Default::default(),
network__dht__get_value_fanout: Default::default(),
network__dht__set_value_timeout_ms: core::ptr::null_mut(),
network__dht__set_value_count: Default::default(),
network__dht__set_value_fanout: Default::default(),
network__dht__min_peer_count: Default::default(),
network__dht__min_peer_refresh_time_ms: Default::default(),
network__dht__validate_dial_info_receipt_time_ms: Default::default(),
network__protocol__udp__enabled: Default::default(),
network__protocol__udp__socket_pool_size: Default::default(),
network__protocol__udp__listen_address: core::ptr::null_mut(),
network__protocol__udp__public_address: core::ptr::null_mut(),
network__protocol__tcp__connect: Default::default(),
network__protocol__tcp__listen: Default::default(),
network__protocol__tcp__max_connections: Default::default(),
network__protocol__tcp__listen_address: core::ptr::null_mut(),
network__protocol__tcp__public_address: core::ptr::null_mut(),
network__protocol__ws__connect: Default::default(),
network__protocol__ws__listen: Default::default(),
network__protocol__ws__max_connections: Default::default(),
network__protocol__ws__listen_address: core::ptr::null_mut(),
network__protocol__ws__path: core::ptr::null_mut(),
network__protocol__ws__url: core::ptr::null_mut(),
network__protocol__wss__connect: Default::default(),
network__protocol__wss__max_connections: Default::default(),
network__leases__max_server_signal_leases: Default::default(),
network__leases__max_server_relay_leases: Default::default(),
network__leases__max_client_signal_leases: Default::default(),
network__leases__max_client_relay_leases: Default::default(),
}
}
}
// Section: impl IntoDart
impl support::IntoDart for AttachmentState {
fn into_dart(self) -> support::DartCObject {
match self {
Self::Detached => 0,
Self::Attaching => 1,
Self::AttachedWeak => 2,
Self::AttachedGood => 3,
Self::AttachedStrong => 4,
Self::FullyAttached => 5,
Self::OverAttached => 6,
Self::Detaching => 7,
}
.into_dart()
}
}
impl support::IntoDart for VeilidLogLevel {
fn into_dart(self) -> support::DartCObject {
match self {
Self::Error => 0,
Self::Warn => 1,
Self::Info => 2,
Self::Debug => 3,
Self::Trace => 4,
}
.into_dart()
}
}
impl support::IntoDart for VeilidState {
fn into_dart(self) -> support::DartCObject {
vec![self.attachment.into_dart()].into_dart()
}
}
impl support::IntoDartExceptPrimitive for VeilidState {}
impl support::IntoDart for VeilidUpdate {
fn into_dart(self) -> support::DartCObject {
match self {
Self::Log { log_level, message } => {
vec![0.into_dart(), log_level.into_dart(), message.into_dart()]
}
Self::Attachment(field0) => vec![1.into_dart(), field0.into_dart()],
}
.into_dart()
}
}
impl support::IntoDart for VeilidVersion {
fn into_dart(self) -> support::DartCObject {
vec![
self.major.into_dart(),
self.minor.into_dart(),
self.patch.into_dart(),
]
.into_dart()
}
}
impl support::IntoDartExceptPrimitive for VeilidVersion {}
// Section: executor
support::lazy_static! {
pub static ref FLUTTER_RUST_BRIDGE_HANDLER: support::DefaultHandler = Default::default();
}
// Section: sync execution mode utility
#[no_mangle]
pub extern "C" fn free_WireSyncReturnStruct(val: support::WireSyncReturnStruct) {
unsafe {
let _ = support::vec_from_leak_ptr(val.ptr, val.len);
}
}

View File

@ -0,0 +1,243 @@
use cfg_if::*;
use log::*;
use serde::*;
/////////////////////////////////////////
// Config Settings
// Not all settings available through Veilid API are available to Flutter applications
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(non_snake_case)]
pub struct VeilidConfig {
pub program_name: String,
pub veilid_namespace: String,
pub api_log_level: veilid_core::VeilidConfigLogLevel,
// Capabilities
pub capabilities__protocol_udp: bool,
pub capabilities__protocol_connect_tcp: bool,
pub capabilities__protocol_accept_tcp: bool,
pub capabilities__protocol_connect_ws: bool,
pub capabilities__protocol_accept_ws: bool,
pub capabilities__protocol_connect_wss: bool,
pub capabilities__protocol_accept_wss: bool,
// Protected Store
pub protected_store__allow_insecure_fallback: bool,
pub protected_store__always_use_insecure_storage: bool,
pub protected_store__insecure_fallback_directory: String,
pub protected_store__delete: bool,
// Table Store
pub table_store__directory: String,
pub table_store__delete: bool,
// Block Store
pub block_store__directory: String,
pub block_store__delete: bool,
// Network
pub network__max_connections: u32,
pub network__connection_initial_timeout_ms: u32,
pub network__node_id: String,
pub network__node_id_secret: String,
pub network__bootstrap: Vec<String>,
pub network__upnp: bool,
pub network__natpmp: bool,
pub network__enable_local_peer_scope: bool,
pub network__restricted_nat_retries: u32,
// Network / RPC
pub network__rpc__concurrency: u32,
pub network__rpc__queue_size: u32,
pub network__rpc__max_timestamp_behind_ms: Option<u32>,
pub network__rpc__max_timestamp_ahead_ms: Option<u32>,
pub network__rpc__timeout_ms: u32,
pub network__rpc__max_route_hop_count: u8,
// Network / DHT
pub network__dht__resolve_node_timeout_ms: Option<u32>,
pub network__dht__resolve_node_count: u32,
pub network__dht__resolve_node_fanout: u32,
pub network__dht__max_find_node_count: u32,
pub network__dht__get_value_timeout_ms: Option<u32>,
pub network__dht__get_value_count: u32,
pub network__dht__get_value_fanout: u32,
pub network__dht__set_value_timeout_ms: Option<u32>,
pub network__dht__set_value_count: u32,
pub network__dht__set_value_fanout: u32,
pub network__dht__min_peer_count: u32,
pub network__dht__min_peer_refresh_time_ms: u32,
pub network__dht__validate_dial_info_receipt_time_ms: u32,
// Network / Protocol
// Network / Protocol / UDP
pub network__protocol__udp__enabled: bool,
pub network__protocol__udp__socket_pool_size: u32,
pub network__protocol__udp__listen_address: String,
pub network__protocol__udp__public_address: Option<String>,
// Network / Protocol / TCP
pub network__protocol__tcp__connect: bool,
pub network__protocol__tcp__listen: bool,
pub network__protocol__tcp__max_connections: u32,
pub network__protocol__tcp__listen_address: String,
pub network__protocol__tcp__public_address: Option<String>,
// Network / Protocol / WS
pub network__protocol__ws__connect: bool,
pub network__protocol__ws__listen: bool,
pub network__protocol__ws__max_connections: u32,
pub network__protocol__ws__listen_address: String,
pub network__protocol__ws__path: String,
pub network__protocol__ws__url: Option<String>,
// Network / Protocol / WSS
pub network__protocol__wss__connect: bool,
pub network__protocol__wss__max_connections: u32,
// Network / Leases
pub network__leases__max_server_signal_leases: u32,
pub network__leases__max_server_relay_leases: u32,
pub network__leases__max_client_signal_leases: u32,
pub network__leases__max_client_relay_leases: u32,
}
cfg_if! {
if #[cfg(target_arch="wasm32")] {
type ConfigReturn = Box<dyn std::any::Any + 'static>;
} else {
type ConfigReturn = Box<dyn std::any::Any + Send + 'static>;
}
}
impl VeilidConfig {
pub fn get_by_str(&self, key: &str) -> std::result::Result<ConfigReturn, String> {
let out: ConfigReturn = match key {
"program_name" => Box::new(self.program_name.clone()),
"namespace" => Box::new(self.veilid_namespace.clone()),
"api_log_level" => Box::new(self.api_log_level),
"capabilities.protocol_udp" => Box::new(self.capabilities__protocol_udp),
"capabilities.protocol_connect_tcp" => {
Box::new(self.capabilities__protocol_connect_tcp)
}
"capabilities.protocol_accept_tcp" => Box::new(self.capabilities__protocol_accept_tcp),
"capabilities.protocol_connect_ws" => Box::new(self.capabilities__protocol_connect_ws),
"capabilities.protocol_accept_ws" => Box::new(self.capabilities__protocol_accept_ws),
"capabilities.protocol_connect_wss" => {
Box::new(self.capabilities__protocol_connect_wss)
}
"capabilities.protocol_accept_wss" => Box::new(self.capabilities__protocol_accept_wss),
"table_store.directory" => Box::new(self.table_store__directory.clone()),
"table_store.delete" => Box::new(self.table_store__delete),
"block_store.directory" => Box::new(self.block_store__directory.clone()),
"block_store.delete" => Box::new(self.block_store__delete),
"protected_store.allow_insecure_fallback" => {
Box::new(self.protected_store__allow_insecure_fallback)
}
"protected_store.always_use_insecure_storage" => {
Box::new(self.protected_store__always_use_insecure_storage)
}
"protected_store.insecure_fallback_directory" => {
Box::new(self.protected_store__insecure_fallback_directory.clone())
}
"protected_store.delete" => Box::new(self.protected_store__delete),
"network.node_id" => Box::new(self.network__node_id.clone()),
"network.node_id_secret" => Box::new(self.network__node_id_secret.clone()),
"network.max_connections" => Box::new(self.network__max_connections),
"network.connection_initial_timeout_ms" => {
Box::new(self.network__connection_initial_timeout_ms)
}
"network.bootstrap" => Box::new(self.network__bootstrap.clone()),
"network.dht.resolve_node_timeout_ms" => {
Box::new(self.network__dht__resolve_node_timeout_ms)
}
"network.dht.resolve_node_count" => Box::new(self.network__dht__resolve_node_count),
"network.dht.resolve_node_fanout" => Box::new(self.network__dht__resolve_node_fanout),
"network.dht.max_find_node_count" => Box::new(self.network__dht__max_find_node_count),
"network.dht.get_value_timeout_ms" => Box::new(self.network__dht__get_value_timeout_ms),
"network.dht.get_value_count" => Box::new(self.network__dht__get_value_count),
"network.dht.get_value_fanout" => Box::new(self.network__dht__get_value_fanout),
"network.dht.set_value_timeout_ms" => Box::new(self.network__dht__set_value_timeout_ms),
"network.dht.set_value_count" => Box::new(self.network__dht__set_value_count),
"network.dht.set_value_fanout" => Box::new(self.network__dht__set_value_fanout),
"network.dht.min_peer_count" => Box::new(self.network__dht__min_peer_count),
"network.dht.min_peer_refresh_time_ms" => {
Box::new(self.network__dht__min_peer_refresh_time_ms)
}
"network.dht.validate_dial_info_receipt_time_ms" => {
Box::new(self.network__dht__validate_dial_info_receipt_time_ms)
}
"network.rpc.concurrency" => Box::new(self.network__rpc__concurrency),
"network.rpc.queue_size" => Box::new(self.network__rpc__queue_size),
"network.rpc.max_timestamp_behind_ms" => {
Box::new(self.network__rpc__max_timestamp_behind_ms)
}
"network.rpc.max_timestamp_ahead_ms" => {
Box::new(self.network__rpc__max_timestamp_ahead_ms)
}
"network.rpc.timeout_ms" => Box::new(self.network__rpc__timeout_ms),
"network.rpc.max_route_hop_count" => Box::new(self.network__rpc__max_route_hop_count),
"network.upnp" => Box::new(self.network__upnp),
"network.natpmp" => Box::new(self.network__natpmp),
"network.enable_local_peer_scope" => Box::new(self.network__enable_local_peer_scope),
"network.restricted_nat_retries" => Box::new(self.network__restricted_nat_retries),
"network.tls.certificate_path" => Box::new("".to_owned()),
"network.tls.private_key_path" => Box::new("".to_owned()),
"network.tls.connection_initial_timeout" => Box::new(0u32),
"network.application.https.enabled" => Box::new(false),
"network.application.https.listen_address" => Box::new("".to_owned()),
"network.application.https.path" => Box::new("".to_owned()),
"network.application.https.url" => Box::new(Option::<String>::None),
"network.application.http.enabled" => Box::new(false),
"network.application.http.listen_address" => Box::new("".to_owned()),
"network.application.http.path" => Box::new("".to_owned()),
"network.application.http.url" => Box::new(Option::<String>::None),
"network.protocol.udp.enabled" => Box::new(self.network__protocol__udp__enabled),
"network.protocol.udp.socket_pool_size" => {
Box::new(self.network__protocol__udp__socket_pool_size)
}
"network.protocol.udp.listen_address" => {
Box::new(self.network__protocol__udp__listen_address.clone())
}
"network.protocol.udp.public_address" => {
Box::new(self.network__protocol__udp__public_address.clone())
}
"network.protocol.tcp.connect" => Box::new(self.network__protocol__tcp__connect),
"network.protocol.tcp.listen" => Box::new(self.network__protocol__tcp__listen),
"network.protocol.tcp.max_connections" => {
Box::new(self.network__protocol__tcp__max_connections)
}
"network.protocol.tcp.listen_address" => {
Box::new(self.network__protocol__tcp__listen_address.clone())
}
"network.protocol.tcp.public_address" => {
Box::new(self.network__protocol__tcp__public_address.clone())
}
"network.protocol.ws.connect" => Box::new(self.network__protocol__ws__connect),
"network.protocol.ws.listen" => Box::new(self.network__protocol__ws__listen),
"network.protocol.ws.max_connections" => {
Box::new(self.network__protocol__ws__max_connections)
}
"network.protocol.ws.listen_address" => {
Box::new(self.network__protocol__ws__listen_address.clone())
}
"network.protocol.ws.path" => Box::new(self.network__protocol__ws__path.clone()),
"network.protocol.ws.url" => Box::new(self.network__protocol__ws__url.clone()),
"network.protocol.wss.connect" => Box::new(self.network__protocol__wss__connect),
"network.protocol.wss.listen" => Box::new(false),
"network.protocol.wss.max_connections" => {
Box::new(self.network__protocol__wss__max_connections)
}
"network.protocol.wss.listen_address" => Box::new("".to_owned()),
"network.protocol.wss.path" => Box::new("".to_owned()),
"network.protocol.wss.url" => Box::new(Option::<String>::None),
"network.leases.max_server_signal_leases" => {
Box::new(self.network__leases__max_server_signal_leases)
}
"network.leases.max_server_relay_leases" => {
Box::new(self.network__leases__max_server_relay_leases)
}
"network.leases.max_client_signal_leases" => {
Box::new(self.network__leases__max_client_signal_leases)
}
"network.leases.max_client_relay_leases" => {
Box::new(self.network__leases__max_client_relay_leases)
}
_ => {
let err = format!("config key '{}' doesn't exist", key);
error!("{}", err);
return Err(err);
}
};
std::result::Result::Ok(out)
}
}

View File

@ -0,0 +1,177 @@
use crate::config::*;
use crate::dart_isolate_wrapper::*;
use crate::dart_serialize::*;
use allo_isolate::*;
use async_std::sync::Mutex as AsyncMutex;
use ffi_support::*;
use lazy_static::*;
use log::*;
use std::os::raw::c_char;
use std::sync::Arc;
// Globals
lazy_static! {
static ref VEILID_API: AsyncMutex<Option<veilid_core::VeilidAPI>> = AsyncMutex::new(None);
}
async fn get_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::VeilidAPIError> {
let api_lock = VEILID_API.lock().await;
api_lock
.as_ref()
.cloned()
.ok_or(veilid_core::VeilidAPIError::NotInitialized)
}
async fn take_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::VeilidAPIError> {
let mut api_lock = VEILID_API.lock().await;
api_lock
.take()
.ok_or(veilid_core::VeilidAPIError::NotInitialized)
}
/////////////////////////////////////////
// FFI Helpers
// Declare external routine to release ffi strings
define_string_destructor!(free_string);
// Utility types for async API results
type APIResult<T> = Result<T, veilid_core::VeilidAPIError>;
const APIRESULT_VOID: APIResult<()> = APIResult::Ok(());
// Stream abort macro for simplified error handling
macro_rules! check_err_json {
($stream:expr, $ex:expr) => {
match $ex {
Ok(v) => v,
Err(e) => {
$stream.abort_json(e);
return;
}
}
};
}
/////////////////////////////////////////
// Initializer
#[no_mangle]
pub extern "C" fn initialize_veilid_flutter(dart_post_c_object_ptr: ffi::DartPostCObjectFnType) {
unsafe {
store_dart_post_cobject(dart_post_c_object_ptr);
}
use std::sync::Once;
static INIT_BACKTRACE: Once = Once::new();
INIT_BACKTRACE.call_once(move || {
std::env::set_var("RUST_BACKTRACE", "1");
std::panic::set_hook(Box::new(move |panic_info| {
let (file, line) = if let Some(loc) = panic_info.location() {
(loc.file(), loc.line())
} else {
("<unknown>", 0)
};
log::error!("### Rust `panic!` hit at file '{}', line {}", file, line);
if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
error!("panic payload: {:?}", s);
} else if let Some(s) = panic_info.payload().downcast_ref::<String>() {
error!("panic payload: {:?}", s);
} else if let Some(a) = panic_info.payload().downcast_ref::<std::fmt::Arguments>() {
error!("panic payload: {:?}", a);
} else {
error!("no panic payload");
}
log::error!(" Complete stack trace:\n{:?}", backtrace::Backtrace::new());
// And stop the process, no recovery is going to be possible here
std::process::abort();
}));
});
}
//////////////////////////////////////////////////////////////////////////////////
/// C-compatible FFI Functions
#[no_mangle]
pub extern "C" fn startup_veilid_core(port: i64, config: FfiStr) {
let config = config.into_opt_string();
let stream = DartIsolateStream::new(port);
async_std::task::spawn(async move {
let config: VeilidConfig = check_err_json!(stream, deserialize_opt_json(config));
let mut api_lock = VEILID_API.lock().await;
if api_lock.is_some() {
stream.abort_json(veilid_core::VeilidAPIError::AlreadyInitialized);
return;
}
let sink = stream.clone();
let setup = veilid_core::VeilidCoreSetup {
update_callback: Arc::new(
move |update: veilid_core::VeilidUpdate| -> veilid_core::SystemPinBoxFuture<()> {
let sink = sink.clone();
Box::pin(async move {
sink.item_json(update);
})
},
),
config_callback: Arc::new(move |key| config.get_by_str(&key)),
};
let res = veilid_core::api_startup(setup).await;
let veilid_api = check_err_json!(stream, res);
*api_lock = Some(veilid_api);
});
}
#[no_mangle]
pub extern "C" fn get_veilid_state(port: i64) {
DartIsolateWrapper::new(port).spawn_result_json(async move {
let veilid_api = get_veilid_api().await?;
let core_state = veilid_api.get_state().await?;
APIResult::Ok(core_state)
});
}
#[no_mangle]
pub extern "C" fn change_api_log_level(port: i64, log_level: FfiStr) {
let log_level = log_level.into_opt_string();
DartIsolateWrapper::new(port).spawn_result_json(async move {
let log_level: veilid_core::VeilidConfigLogLevel = deserialize_opt_json(log_level)?;
let veilid_api = get_veilid_api().await?;
veilid_api.change_api_log_level(log_level).await;
APIRESULT_VOID
});
}
#[no_mangle]
pub extern "C" fn shutdown_veilid_core(port: i64) {
DartIsolateWrapper::new(port).spawn_result_json(async move {
let veilid_api = take_veilid_api().await?;
veilid_api.shutdown().await;
APIRESULT_VOID
});
}
#[no_mangle]
pub extern "C" fn veilid_version_string() -> *mut c_char {
veilid_core::veilid_version_string().into_ffi_value()
}
#[repr(C)]
pub struct VeilidVersion {
pub major: u32,
pub minor: u32,
pub patch: u32,
}
#[no_mangle]
pub extern "C" fn veilid_version() -> VeilidVersion {
let (major, minor, patch) = veilid_core::veilid_version();
VeilidVersion {
major,
minor,
patch,
}
}

View File

@ -0,0 +1,151 @@
use crate::dart_serialize::*;
pub use allo_isolate::ffi::DartCObject;
pub use allo_isolate::IntoDart;
use allo_isolate::Isolate;
use core::future::Future;
use parking_lot::Mutex;
use serde::*;
use std::sync::Arc;
#[derive(Clone)]
pub struct DartIsolateWrapper {
isolate: Isolate,
}
const MESSAGE_OK: i32 = 0;
const MESSAGE_ERR: i32 = 1;
const MESSAGE_OK_JSON: i32 = 2;
const MESSAGE_ERR_JSON: i32 = 3;
const MESSAGE_STREAM_ITEM: i32 = 4;
const MESSAGE_STREAM_ITEM_JSON: i32 = 5;
const MESSAGE_STREAM_ABORT: i32 = 6;
const MESSAGE_STREAM_ABORT_JSON: i32 = 7;
const MESSAGE_STREAM_CLOSE: i32 = 8;
impl DartIsolateWrapper {
pub fn new(port: i64) -> Self {
DartIsolateWrapper {
isolate: Isolate::new(port),
}
}
pub fn spawn_result_json<F, T, E>(self, future: F)
where
F: Future<Output = Result<T, E>> + Send + 'static,
T: Serialize,
E: Serialize,
{
async_std::task::spawn(async move {
self.result_json(future.await);
});
}
pub fn result<T: IntoDart, E: IntoDart>(&self, result: Result<T, E>) -> bool {
match result {
Ok(v) => self.ok(v),
Err(e) => self.err(e),
}
}
pub fn result_json<T: Serialize, E: Serialize>(&self, result: Result<T, E>) -> bool {
match result {
Ok(v) => self.ok_json(v),
Err(e) => self.err_json(e),
}
}
pub fn ok<T: IntoDart>(&self, value: T) -> bool {
self.isolate
.post(vec![MESSAGE_OK.into_dart(), value.into_dart()])
}
pub fn ok_json<T: Serialize>(&self, value: T) -> bool {
self.isolate.post(vec![
MESSAGE_OK_JSON.into_dart(),
serialize_json(value).into_dart(),
])
}
pub fn err<E: IntoDart>(&self, error: E) -> bool {
self.isolate
.post(vec![MESSAGE_ERR.into_dart(), error.into_dart()])
}
pub fn err_json<E: Serialize>(&self, error: E) -> bool {
self.isolate.post(vec![
MESSAGE_ERR_JSON.into_dart(),
serialize_json(error).into_dart(),
])
}
}
#[derive(Clone)]
pub struct DartIsolateStream {
isolate: Arc<Mutex<Option<Isolate>>>,
}
impl DartIsolateStream {
pub fn new(port: i64) -> Self {
DartIsolateStream {
isolate: Arc::new(Mutex::new(Some(Isolate::new(port)))),
}
}
pub fn item<T: IntoDart>(&self, value: T) -> bool {
let isolate = self.isolate.lock();
if let Some(isolate) = &*isolate {
isolate.post(vec![MESSAGE_STREAM_ITEM.into_dart(), value.into_dart()])
} else {
false
}
}
pub fn item_json<T: Serialize>(&self, value: T) -> bool {
let isolate = self.isolate.lock();
if let Some(isolate) = &*isolate {
isolate.post(vec![
MESSAGE_STREAM_ITEM_JSON.into_dart(),
serialize_json(value).into_dart(),
])
} else {
false
}
}
pub fn abort<E: IntoDart>(self, error: E) -> bool {
let mut isolate = self.isolate.lock();
if let Some(isolate) = isolate.take() {
isolate.post(vec![MESSAGE_STREAM_ABORT.into_dart(), error.into_dart()])
} else {
false
}
}
pub fn abort_json<E: Serialize>(self, error: E) -> bool {
let mut isolate = self.isolate.lock();
if let Some(isolate) = isolate.take() {
isolate.post(vec![
MESSAGE_STREAM_ABORT_JSON.into_dart(),
serialize_json(error).into_dart(),
])
} else {
false
}
}
pub fn close(self) -> bool {
let mut isolate = self.isolate.lock();
if let Some(isolate) = isolate.take() {
isolate.post(vec![MESSAGE_STREAM_CLOSE.into_dart()])
} else {
false
}
}
}
impl Drop for DartIsolateStream {
fn drop(&mut self) {
let mut isolate = self.isolate.lock();
if let Some(isolate) = isolate.take() {
isolate.post(vec![MESSAGE_STREAM_CLOSE.into_dart()]);
}
}
}

View File

@ -0,0 +1,24 @@
use serde::*;
pub fn deserialize_json<'a, T: de::Deserialize<'a>>(
arg: &'a str,
) -> Result<T, veilid_core::VeilidAPIError> {
serde_json::from_str(arg).map_err(|e| veilid_core::VeilidAPIError::ParseError {
message: e.to_string(),
value: String::new(),
})
}
pub fn deserialize_opt_json<T: de::DeserializeOwned>(
arg: Option<String>,
) -> Result<T, veilid_core::VeilidAPIError> {
let arg = arg.ok_or_else(|| veilid_core::VeilidAPIError::ParseError {
message: "invalid null string passed to rust".to_owned(),
value: String::new(),
})?;
deserialize_json(&arg)
}
pub fn serialize_json<T: Serialize>(val: T) -> String {
serde_json::to_string(&val).expect("failed to serialize json value")
}

View File

@ -1,5 +1,15 @@
mod api; use cfg_if::*;
mod bridge_generated;
cfg_if! {
if #[cfg(not(target_arch = "wasm32"))] {
mod dart_ffi;
mod dart_isolate_wrapper;
mod dart_serialize;
} else {
mod wasm;
}
}
mod config;
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
use jni::{objects::JClass, objects::JObject, JNIEnv}; use jni::{objects::JClass, objects::JObject, JNIEnv};

View File

@ -0,0 +1,25 @@
#![cfg(target_arch = "wasm32")]
#![no_std]
#[macro_use]
extern crate alloc;
pub use log::*;
pub use wasm_bindgen::prelude::*;
pub use wasm_bindgen::JsCast;
pub use alloc::boxed::Box;
pub use alloc::string::String;
pub use alloc::sync::Arc;
pub use alloc::vec::Vec;
pub use core::convert::TryFrom;
pub use js_sys::*;
pub use js_veilid_core::*;
pub use utils::*;
pub use veilid_core::dht::key::*;
pub use veilid_core::xx::*;
pub use veilid_core::*;
pub use wasm_logger::*;
mod js_veilid_core;
mod utils;

View File

@ -36,7 +36,10 @@ fn convert_update(
rpc_update: crate::veilid_client_capnp::veilid_update::Builder, rpc_update: crate::veilid_client_capnp::veilid_update::Builder,
) { ) {
match update { match update {
veilid_core::VeilidUpdate::Log(_ll, _s) => { veilid_core::VeilidUpdate::Log {
log_level: _,
message: _,
} => {
panic!("Should not be logging to api in server!"); panic!("Should not be logging to api in server!");
} }
veilid_core::VeilidUpdate::Attachment(state) => { veilid_core::VeilidUpdate::Attachment(state) => {

View File

@ -24,9 +24,6 @@ pub fn shutdown() {
pub async fn run_veilid_server(settings: Settings, logs: VeilidLogs) -> Result<(), String> { pub async fn run_veilid_server(settings: Settings, logs: VeilidLogs) -> Result<(), String> {
let settingsr = settings.read(); let settingsr = settings.read();
// Create Veilid Core
let veilid_core = veilid_core::VeilidCore::new();
// Create client api state change pipe // Create client api state change pipe
let (sender, receiver): ( let (sender, receiver): (
Sender<veilid_core::VeilidUpdate>, Sender<veilid_core::VeilidUpdate>,
@ -49,8 +46,7 @@ pub async fn run_veilid_server(settings: Settings, logs: VeilidLogs) -> Result<(
}; };
// Start Veilid Core and get API // Start Veilid Core and get API
let veilid_api = veilid_core let veilid_api = veilid_core::api_startup(vcs)
.startup(vcs)
.await .await
.map_err(|e| format!("VeilidCore startup failed: {}", e))?; .map_err(|e| format!("VeilidCore startup failed: {}", e))?;

5
veilid-wasm/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/target
**/*.rs.bk
bin/
pkg/
wasm-pack.log

23
veilid-wasm/Cargo.toml Normal file
View File

@ -0,0 +1,23 @@
[package]
name = "veilid-wasm"
version = "0.1.0"
authors = ["John Smith <jsmith@example.com>"]
edition = "2021"
license = "LGPL-2.0-or-later OR MPL-2.0 OR (MIT AND BSD-3-Clause)"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
wasm-bindgen = "^0"
console_error_panic_hook = "^0"
wee_alloc = "^0"
wasm-logger = "^0"
log = "^0"
veilid-core = { path = "../veilid-core" }
cfg-if = "^1"
wasm-bindgen-futures = "^0"
js-sys = "^0"
[dev-dependencies]
wasm-bindgen-test = "^0"

View File

@ -0,0 +1,286 @@
use crate::*;
pub use wasm_bindgen_futures::*;
#[wasm_bindgen(js_name = VeilidStateChange)]
pub struct JsVeilidStateChange {
kind: String, // "attachment" => AttachmentState(String)
from: JsValue,
to: JsValue,
}
#[wasm_bindgen(js_name = VeilidState)]
pub struct JsVeilidState {
kind: String, // "attachment" => AttachmentState(String)
state: JsValue,
}
#[wasm_bindgen(js_name = VeilidCore)]
pub struct JsVeilidCore {
core: VeilidCore,
}
#[wasm_bindgen(js_class = VeilidCore)]
impl JsVeilidCore {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
set_panic_hook();
JsVeilidCore {
core: VeilidCore::new(),
}
}
fn value_to_string(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
Ok(Box::new(val.as_string().ok_or(())?))
}
fn value_to_option_string(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
if val.is_null() || val.is_undefined() {
return Ok(Box::new(Option::<String>::None));
}
Ok(Box::new(Some(val.as_string().ok_or(())?)))
}
fn value_to_bool(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
Ok(Box::new(val.is_truthy()))
}
fn value_to_u8(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
Ok(Box::new(f64_try_to_unsigned::<u8>(
val.as_f64().ok_or(())?,
)?))
}
fn value_to_u32(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
Ok(Box::new(f64_try_to_unsigned::<u32>(
val.as_f64().ok_or(())?,
)?))
}
fn value_to_u64(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
Ok(Box::new(f64_try_to_unsigned::<u64>(
val.as_f64().ok_or(())?,
)?))
}
fn value_to_option_u64(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
if val.is_null() || val.is_undefined() {
return Ok(Box::new(Option::<u64>::None));
}
Ok(Box::new(Some(f64_try_to_unsigned::<u64>(
val.as_f64().ok_or(())?,
)?)))
}
fn value_to_dht_key(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
Ok(Box::new(
DHTKey::try_decode(val.as_string().ok_or(())?.as_str()).map_err(drop)?,
))
}
fn value_to_dht_key_secret(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
Ok(Box::new(
DHTKeySecret::try_decode(val.as_string().ok_or(())?.as_str()).map_err(drop)?,
))
}
fn value_to_vec_string(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
let arrval = val.dyn_into::<Array>().map_err(drop)?.to_vec();
let mut out = Vec::<String>::with_capacity(arrval.len());
for v in arrval {
out.push(v.as_string().ok_or(())?);
}
Ok(Box::new(out))
}
fn translate_config_callback(key: &str, val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
match key {
// xxx: lots of missing keys here
"namespace" => Self::value_to_string(val),
"capabilities.protocol_udp" => Self::value_to_bool(val),
"capabilities.protocol_connect_tcp" => Self::value_to_bool(val),
"capabilities.protocol_accept_tcp" => Self::value_to_bool(val),
"capabilities.protocol_connect_ws" => Self::value_to_bool(val),
"capabilities.protocol_accept_ws" => Self::value_to_bool(val),
"capabilities.protocol_connect_wss" => Self::value_to_bool(val),
"capabilities.protocol_accept_wss" => Self::value_to_bool(val),
"tablestore.directory" => Self::value_to_string(val),
"network.max_connections" => Self::value_to_u32(val),
"network.node_id" => Self::value_to_dht_key(val),
"network.node_id_secret" => Self::value_to_dht_key_secret(val),
"network.bootstrap" => Self::value_to_vec_string(val),
"network.rpc.concurrency" => Self::value_to_u32(val),
"network.rpc.queue_size" => Self::value_to_u32(val),
"network.rpc.max_timestamp_behind" => Self::value_to_option_u64(val),
"network.rpc.max_timestamp_ahead" => Self::value_to_option_u64(val),
"network.rpc.timeout" => Self::value_to_u64(val),
"network.rpc.max_route_hop_count" => Self::value_to_u8(val),
"network.dht.resolve_node_timeout" => Self::value_to_option_u64(val),
"network.dht.resolve_node_count" => Self::value_to_u32(val),
"network.dht.resolve_node_fanout" => Self::value_to_u32(val),
"network.dht.max_find_node_count" => Self::value_to_u32(val),
"network.dht.get_value_timeout" => Self::value_to_option_u64(val),
"network.dht.get_value_count" => Self::value_to_u32(val),
"network.dht.get_value_fanout" => Self::value_to_u32(val),
"network.dht.set_value_timeout" => Self::value_to_option_u64(val),
"network.dht.set_value_count" => Self::value_to_u32(val),
"network.dht.set_value_fanout" => Self::value_to_u32(val),
"network.dht.min_peer_count" => Self::value_to_u32(val),
"network.dht.min_peer_refresh_time" => Self::value_to_u64(val),
"network.dht.validate_dial_info_receipt_time" => Self::value_to_u64(val),
"network.upnp" => Self::value_to_bool(val),
"network.natpmp" => Self::value_to_bool(val),
"network.address_filter" => Self::value_to_bool(val),
"network.restricted_nat_retries" => Self::value_to_u32(val),
"network.tls.certificate_path" => Self::value_to_string(val),
"network.tls.private_key_path" => Self::value_to_string(val),
"network.application.path" => Self::value_to_string(val),
"network.application.https.enabled" => Self::value_to_bool(val),
"network.application.https.listen_address" => Self::value_to_string(val),
"network.application.http.enabled" => Self::value_to_bool(val),
"network.application.http.listen_address" => Self::value_to_string(val),
"network.protocol.udp.enabled" => Self::value_to_bool(val),
"network.protocol.udp.socket_pool_size" => Self::value_to_u32(val),
"network.protocol.udp.listen_address" => Self::value_to_string(val),
"network.protocol.udp.public_address" => Self::value_to_option_string(val),
"network.protocol.tcp.connect" => Self::value_to_bool(val),
"network.protocol.tcp.listen" => Self::value_to_bool(val),
"network.protocol.tcp.max_connections" => Self::value_to_u32(val),
"network.protocol.tcp.listen_address" => Self::value_to_string(val),
"network.protocol.tcp.public_address" => Self::value_to_option_string(val),
"network.protocol.ws.connect" => Self::value_to_bool(val),
"network.protocol.ws.listen" => Self::value_to_bool(val),
"network.protocol.ws.max_connections" => Self::value_to_u32(val),
"network.protocol.ws.listen_address" => Self::value_to_string(val),
"network.protocol.ws.path" => Self::value_to_string(val),
"network.protocol.ws.public_address" => Self::value_to_option_string(val),
"network.protocol.wss.connect" => Self::value_to_bool(val),
"network.protocol.wss.listen" => Self::value_to_bool(val),
"network.protocol.wss.max_connections" => Self::value_to_u32(val),
"network.protocol.wss.listen_address" => Self::value_to_string(val),
"network.protocol.wss.path" => Self::value_to_string(val),
"network.protocol.wss.public_address" => Self::value_to_option_string(val),
_ => return Err(()),
}
}
fn translate_veilid_state(state: JsVeilidState) -> Result<VeilidState, JsValue> {
Ok(match state.kind.as_str() {
"attachment" => {
let state_string = state
.state
.as_string()
.ok_or(JsValue::from_str("state should be a string"))?;
let astate = AttachmentState::try_from(state_string)
.map_err(|e| JsValue::from_str(format!("invalid state: {:?}", e).as_str()))?;
VeilidState::Attachment(astate)
}
_ => return Err(JsValue::from_str("unknown state kind")),
})
}
// xxx rework this for new veilid_api mechanism which should be its own js object now
pub fn startup(
&self,
js_state_change_callback: Function,
js_config_callback: Function,
) -> Promise {
let core = self.core.clone();
future_to_promise(async move {
let vcs = VeilidCoreSetup {
state_change_callback: Arc::new(
move |change: VeilidStateChange| -> SystemPinBoxFuture<()> {
let js_state_change_callback = js_state_change_callback.clone();
Box::pin(async move {
let js_change = match change {
VeilidStateChange::Attachment {
old_state,
new_state,
} => JsVeilidStateChange {
kind: "attachment".to_owned(),
from: JsValue::from_str(old_state.to_string().as_str()),
to: JsValue::from_str(new_state.to_string().as_str()),
},
};
let ret = match Function::call1(
&js_state_change_callback,
&JsValue::UNDEFINED,
&JsValue::from(js_change),
) {
Ok(v) => v,
Err(e) => {
error!("calling state change callback failed: {:?}", e);
return;
}
};
let retp: Promise = match ret.dyn_into() {
Ok(v) => v,
Err(e) => {
error!(
"state change callback did not return a promise: {:?}",
e
);
return;
}
};
match JsFuture::from(retp).await {
Ok(_) => (),
Err(e) => {
error!("state change callback returned an error: {:?}", e);
return;
}
};
})
},
),
config_callback: Arc::new(
move |key: String| -> Result<Box<dyn core::any::Any>, String> {
let val = Function::call1(
&js_config_callback,
&JsValue::UNDEFINED,
&JsValue::from_str(key.as_str()),
)
.map_err(|_| {
format!("Failed to get config from callback for key '{}'", key)
})?;
Self::translate_config_callback(key.as_str(), val)
.map_err(|_| format!("invalid value type for config key '{}'", key))
},
),
};
match core.startup(vcs).await {
Ok(_) => Ok(JsValue::UNDEFINED),
Err(e) => Err(JsValue::from_str(
format!("VeilidCore startup() failed: {}", e.to_string()).as_str(),
)),
}
})
}
pub fn send_state_update(&self) {
self.core.send_state_update();
}
pub fn shutdown(&self) -> Promise {
let core = self.core.clone();
future_to_promise(async move {
core.shutdown().await;
Ok(JsValue::UNDEFINED)
})
}
pub fn attach(&self) -> Promise {
let core = self.core.clone();
future_to_promise(async move {
core.attach();
Ok(JsValue::UNDEFINED)
})
}
pub fn detach(&self) -> Promise {
let core = self.core.clone();
future_to_promise(async move {
core.detach();
Ok(JsValue::UNDEFINED)
})
}
pub fn wait_for_state(&self, state: JsVeilidState) -> Promise {
let core = self.core.clone();
future_to_promise(async move {
let state = Self::translate_veilid_state(state)?;
core.wait_for_state(state).await;
Ok(JsValue::UNDEFINED)
})
}
}

25
veilid-wasm/src/lib.rs Normal file
View File

@ -0,0 +1,25 @@
#![cfg(target_arch = "wasm32")]
#![no_std]
#[macro_use]
extern crate alloc;
pub use log::*;
pub use wasm_bindgen::prelude::*;
pub use wasm_bindgen::JsCast;
pub use alloc::boxed::Box;
pub use alloc::string::String;
pub use alloc::sync::Arc;
pub use alloc::vec::Vec;
pub use core::convert::TryFrom;
pub use js_sys::*;
pub use js_veilid_core::*;
pub use utils::*;
pub use veilid_core::dht::key::*;
pub use veilid_core::xx::*;
pub use veilid_core::*;
pub use wasm_logger::*;
mod js_veilid_core;
mod utils;

38
veilid-wasm/src/utils.rs Normal file
View File

@ -0,0 +1,38 @@
use cfg_if::*;
use wasm_bindgen::prelude::*;
//use wasm_bindgen_futures::*;
cfg_if! {
if #[cfg(feature = "wee_alloc")] {
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
extern crate wee_alloc;
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
}
}
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console, js_name = log)]
pub fn console_log(s: &str);
#[wasm_bindgen]
pub fn alert(s: &str);
}
pub fn set_panic_hook() {
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
}
pub fn f64_try_to_unsigned<T>(f: f64) -> Result<T, ()>
where
T: core::convert::TryFrom<u64>,
{
let rf = f.floor();
if rf < 0.0 {
return Err(());
}
T::try_from(rf as u64).map_err(drop)
}

179
veilid-wasm/tests/web.rs Normal file
View File

@ -0,0 +1,179 @@
//! Test suite for the Web and headless browsers.
#![cfg(target_arch = "wasm32")]
extern crate alloc;
extern crate wasm_bindgen_test;
use core::sync::atomic::AtomicBool;
use veilid_wasm::*;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
static SETUP_ONCE: AtomicBool = AtomicBool::new(false);
pub fn setup() -> () {
if SETUP_ONCE
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_ok()
{
console_log("setup()");
console_error_panic_hook::set_once();
wasm_logger::init(wasm_logger::Config::new(Level::Trace));
init_callbacks();
}
}
// xxx needs updating to new keys and veilid_api object
fn init_callbacks() {
assert_eq!(js_sys::eval(r#"
window.sleep = (milliseconds) => { return new Promise(resolve => setTimeout(resolve, milliseconds)) };
window.stateChangeCallback = async (stateChange) => { console.log("State change: " + stateChange); };
window.configCallback = (configKey) => {
switch(configKey) {
case "namespace": return "";
case "capabilities.protocol_udp": return false;
case "capabilities.protocol_connect_tcp": return false;
case "capabilities.protocol_accept_tcp": return false;
case "capabilities.protocol_connect_ws": return true;
case "capabilities.protocol_accept_ws": return false;
case "capabilities.protocol_connect_wss": return true;
case "capabilities.protocol_accept_wss": return false;
case "tablestore.directory": return "";
case "network.max_connections": return 16;
case "network.node_id": return "ZLd4uMYdP4qYLtxF6GqrzBb32Z6T3rE2FWMkWup1pdY";
case "network.node_id_secret": return "s2Gvq6HJOxgQh-3xIgfWSL3I-DWZ2c1RjZLJl2Xmg2E";
case "network.bootstrap": return [];
case "network.rpc.concurrency": return 2;
case "network.rpc.queue_size": return 128;
case "network.rpc.max_timestamp_behind": return 10000000;
case "network.rpc.max_timestamp_ahead": return 10000000;
case "network.rpc.timeout": return 10000000;
case "network.rpc.max_route_hop_count": return 7;
case "network.dht.resolve_node_timeout": return null;
case "network.dht.resolve_node_count": return 20;
case "network.dht.resolve_node_fanout": return 3;
case "network.dht.max_find_node_count": return 20;
case "network.dht.get_value_timeout": return null;
case "network.dht.get_value_count": return 20;
case "network.dht.get_value_fanout": return 3;
case "network.dht.set_value_timeout": return null;
case "network.dht.set_value_count": return 20;
case "network.dht.set_value_fanout": return 5;
case "network.dht.min_peer_count": return 20;
case "network.dht.min_peer_refresh_time": return 2000000;
case "network.dht.validate_dial_info_receipt_time": return 5000000;
case "network.upnp": return false;
case "network.natpmp": return false;
case "network.address_filter": return true;
case "network.restricted_nat_retries": return 3;
case "network.tls.certificate_path": return "";
case "network.tls.private_key_path": return "";
case "network.application.path": return "/app";
case "network.application.https.enabled": return false;
case "network.application.https.listen_address": return "";
case "network.application.http.enabled": return false;
case "network.application.http.listen_address": return "";
case "network.protocol.udp.enabled": return false;
case "network.protocol.udp.socket_pool_size": return 0;
case "network.protocol.udp.listen_address": return "";
case "network.protocol.udp.public_address": return "";
case "network.protocol.tcp.connect": return false;
case "network.protocol.tcp.listen": return false;
case "network.protocol.tcp.max_connections": return 32;
case "network.protocol.tcp.listen_address": return "";
case "network.protocol.tcp.public_address": return "";
case "network.protocol.ws.connect": return true;
case "network.protocol.ws.listen": return false;
case "network.protocol.ws.max_connections": return 16;
case "network.protocol.ws.listen_address": return "";
case "network.protocol.ws.path": return "/ws";
case "network.protocol.ws.public_address": return "";
case "network.protocol.wss.connect": return true;
case "network.protocol.wss.listen": return false;
case "network.protocol.wss.max_connections": return 16;
case "network.protocol.wss.listen_address": return "";
case "network.protocol.wss.path": return "/ws";
case "network.protocol.wss.public_address": return "";
default:
console.log("config key '" + key +"' doesn't exist"); break;
}
};
true
"#).expect("failed to eval"), JsValue::TRUE);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
///
#[wasm_bindgen_test]
fn test_construct() {
setup();
assert_eq!(
js_sys::eval(
r#"
let vc = new VeilidCore();
true
"#
)
.expect("failed to eval"),
JsValue::TRUE
);
}
#[wasm_bindgen_test(async)]
async fn test_startup_shutdown() {
setup();
assert_eq!(
JsFuture::from(
js_sys::eval(
r#"
(async function() {
let vc = new VeilidCore();
await vc.startup(window.stateChangeCallback, window.configCallback);
await vc.shutdown();
return true;
})().then(v => {
console.log("finished: " + v);
return v;
});
"#
)
.expect("failed to eval")
.dyn_into::<Promise>()
.unwrap()
)
.await,
Ok(JsValue::TRUE)
);
}
#[wasm_bindgen_test(async)]
async fn test_attach_detach() {
setup();
assert_eq!(
JsFuture::from(
js_sys::eval(
r#"
(async function() {
let vc = new VeilidCore();
await vc.startup(window.stateChangeCallback, window.configCallback);
await vc.attach();
await window.sleep(1000);
await vc.detach();
await vc.shutdown();
return true;
})().then(v => {
console.log("finished: " + v);
return v;
});
"#
)
.expect("failed to eval")
.dyn_into::<Promise>()
.unwrap()
)
.await,
Ok(JsValue::TRUE)
);
}