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

View File

@ -4,7 +4,8 @@ members = [
"veilid-core",
"veilid-server",
"veilid-cli",
"veilid-flutter/rust"
"veilid-flutter/rust",
"veilid-wasm",
]
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::veilid_api::*;
use crate::veilid_core::*;
use crate::xx::*;
use log::{set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record};
use once_cell::sync::OnceCell;
@ -23,20 +23,12 @@ impl ApiLogger {
fn new_inner(level: LevelFilter, update_callback: UpdateCallback) -> ApiLoggerInner {
let (tx, rx) = async_channel::unbounded::<(VeilidLogLevel, String)>();
let _join_handle: JoinHandle<()> = spawn(async move {
loop {
match rx.recv().await {
Ok(v) => {
(update_callback)(VeilidUpdate::Log {
log_level: v.0,
message: v.1,
})
.await;
}
Err(_) => {
// Nothing to be done here...
break;
}
}
while let Ok(v) = rx.recv().await {
(update_callback)(VeilidUpdate::Log {
log_level: v.0,
message: v.1,
})
.await;
}
});
ApiLoggerInner {

View File

@ -6,9 +6,10 @@ use crate::xx::*;
use crate::*;
use core::convert::TryFrom;
use core::fmt;
use serde::*;
state_machine! {
derive(Debug, PartialEq, Eq, Clone, Copy)
derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)
pub Attachment(Detached)
//---
Detached(AttachRequested) => Attaching [StartAttachment],
@ -102,8 +103,6 @@ impl TryFrom<String> for AttachmentState {
pub struct AttachmentManagerInner {
config: VeilidConfig,
table_store: TableStore,
crypto: Crypto,
attachment_machine: CallbackStateMachine<Attachment>,
network_manager: NetworkManager,
maintain_peers: bool,
@ -125,8 +124,6 @@ impl AttachmentManager {
) -> AttachmentManagerInner {
AttachmentManagerInner {
config: config.clone(),
table_store: table_store.clone(),
crypto: crypto.clone(),
attachment_machine: CallbackStateMachine::new(),
network_manager: NetworkManager::new(config, table_store, crypto),
maintain_peers: false,
@ -145,14 +142,6 @@ impl AttachmentManager {
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 {
self.inner.lock().network_manager.clone()
}
@ -274,20 +263,26 @@ impl AttachmentManager {
&self,
state_change_callback: StateChangeCallback<Attachment>,
) -> Result<(), String> {
let inner = self.inner.lock();
inner
.attachment_machine
.set_state_change_callback(state_change_callback);
let network_manager = {
let inner = self.inner.lock();
inner
.attachment_machine
.set_state_change_callback(state_change_callback);
inner.network_manager.clone()
};
inner.network_manager.init().await?;
network_manager.init().await?;
Ok(())
}
pub async fn terminate(&self) {
// Ensure we detached
self.detach().await;
let inner = self.inner.lock();
inner.network_manager.terminate().await;
let network_manager = {
let inner = self.inner.lock();
inner.network_manager.clone()
};
network_manager.terminate().await;
}
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");
// make local copy of node id for easy access
let mut inner = self.inner.lock();
let c = self.config.get();
inner.node_id = c.network.node_id;
inner.node_id_secret = c.network.node_id_secret;
let (table_store, node_id) = {
let mut inner = self.inner.lock();
let c = self.config.get();
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
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? {
Some(v) => v.as_slice() == inner.node_id.bytes,
Some(v) => v.as_slice() == node_id.bytes,
None => false,
};
if caches_valid {
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);
}
} else {
drop(db);
inner.table_store.delete("crypto_caches").await?;
db = inner.table_store.open("crypto_caches", 1).await?;
db.store(0, b"node_id", &inner.node_id.bytes).await?;
table_store.delete("crypto_caches").await?;
db = table_store.open("crypto_caches", 1).await?;
db.store(0, b"node_id", &node_id.bytes).await?;
}
// Schedule flushing
let this = self.clone();
inner.flush_future = Some(Box::pin(interval(60000, move || {
let flush_future = interval(60000, move || {
let this = this.clone();
async move {
if let Err(e) = this.flush().await {
warn!("flush failed: {}", e);
}
}
})));
});
self.inner.lock().flush_future = Some(flush_future);
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 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();
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 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))
}
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
.inner
.lock()
@ -197,24 +204,12 @@ impl Crypto {
///////////
// 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!(secret.valid);
let pk_ed = match ed::PublicKey::from_bytes(&key.bytes) {
Ok(v) => v,
Err(e) => {
trace!("compute_dh error: {:?}", e);
return Err(());
}
};
let pk_ed = ed::PublicKey::from_bytes(&key.bytes).map_err(map_to_string)?;
let pk_xd = Self::ed25519_to_x25519_pk(&pk_ed)?;
let sk_ed = match ed::SecretKey::from_bytes(&secret.bytes) {
Ok(v) => v,
Err(e) => {
trace!("compute_dh error: {:?}", e);
return Err(());
}
};
let sk_ed = ed::SecretKey::from_bytes(&secret.bytes).map_err(map_to_string)?;
let sk_xd = Self::ed25519_to_x25519_sk(&sk_ed)?;
Ok(sk_xd.diffie_hellman(&pk_xd).to_bytes())
}
@ -236,12 +231,13 @@ impl Crypto {
nonce: &Nonce,
shared_secret: &SharedSecret,
associated_data: Option<&[u8]>,
) -> Result<(), ()> {
) -> Result<(), String> {
let key = ch::Key::from(*shared_secret);
let xnonce = ch::XNonce::from(*nonce);
let aead = ch::XChaCha20Poly1305::new(&key);
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(
@ -249,9 +245,11 @@ impl Crypto {
nonce: &Nonce,
shared_secret: &SharedSecret,
associated_data: Option<&[u8]>,
) -> Result<Vec<u8>, ()> {
) -> Result<Vec<u8>, String> {
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)
}
@ -260,13 +258,14 @@ impl Crypto {
nonce: &Nonce,
shared_secret: &SharedSecret,
associated_data: Option<&[u8]>,
) -> Result<(), ()> {
) -> Result<(), String> {
let key = ch::Key::from(*shared_secret);
let xnonce = ch::XNonce::from(*nonce);
let aead = ch::XChaCha20Poly1305::new(&key);
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(
@ -274,9 +273,11 @@ impl Crypto {
nonce: &Nonce,
shared_secret: &SharedSecret,
associated_data: Option<&[u8]>,
) -> Result<Vec<u8>, ()> {
) -> Result<Vec<u8>, String> {
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)
}
}

View File

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

View File

@ -1,2 +1,30 @@
//use crate::intf::*;
//use crate::xx::*;
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

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

View File

@ -44,8 +44,8 @@ impl ProtectedStore {
}
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();
if !c.protected_store.always_use_insecure_storage {
cfg_if! {
@ -74,9 +74,10 @@ impl ProtectedStore {
if inner.keyring_manager.is_none() {
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?;
}

View File

@ -24,29 +24,6 @@ lazy_static! {
}
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 {
vm: env.get_java_vm().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);
}

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());
// Split dial info up
let (tls, scheme) = match &dial_info {
let (_tls, scheme) = match &dial_info {
DialInfo::WS(_) => (false, "ws"),
DialInfo::WSS(_) => (true, "wss"),
_ => panic!("invalid dialinfo for WS/WSS protocol"),

View File

@ -9,6 +9,7 @@ mod attachment_manager;
mod callback_state_machine;
mod connection_manager;
mod connection_table;
mod core_context;
mod dht;
mod intf;
mod lease_manager;
@ -19,16 +20,15 @@ mod routing_table;
mod rpc_processor;
mod veilid_api;
mod veilid_config;
mod veilid_core;
mod veilid_rng;
#[macro_use]
pub mod xx;
pub use self::attachment_manager::AttachmentState;
pub use self::core_context::{api_startup, VeilidCoreSetup};
pub use self::veilid_api::*;
pub use self::veilid_config::*;
pub use self::veilid_core::{VeilidCore, VeilidCoreSetup};
pub mod veilid_capnp {
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_io",
"polling",

View File

@ -170,10 +170,12 @@ impl NetworkManager {
Ok(())
}
pub async fn terminate(&self) {
let mut inner = self.inner.lock();
if let Some(routing_table) = &inner.routing_table {
let routing_table = {
let mut inner = self.inner.lock();
inner.routing_table.take()
};
if let Some(routing_table) = routing_table {
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");
let api = core
.startup(setup_veilid_core())
let api = api_startup(setup_veilid_core())
.await
.expect("startup failed");
api
@ -130,9 +129,8 @@ pub async fn test_dh(crypto: Crypto) {
}
pub async fn test_all() {
let core = VeilidCore::new();
let api = startup(core.clone()).await;
let crypto = core.crypto();
let api = startup().await;
let crypto = api.crypto().unwrap();
test_enc_dec().await;
test_dh(crypto).await;
shutdown(api.clone()).await;

View File

@ -8,13 +8,12 @@ use crate::*;
pub async fn test_envelope_round_trip() {
info!("--- test envelope round trip ---");
let veilid_core = VeilidCore::new();
let api = veilid_core
.startup(setup_veilid_core())
let api = api_startup(setup_veilid_core())
.await
.expect("startup failed");
// Get crypto
let crypto = veilid_core.crypto();
let crypto = api.crypto().unwrap();
// Create envelope
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");
core.startup(setup_veilid_core())
api_startup(setup_veilid_core())
.await
.expect("startup failed")
}
@ -93,10 +93,8 @@ pub async fn test_protected_store(ps: ProtectedStore) {
}
pub async fn test_all() {
let core = VeilidCore::new();
let api = startup(core.clone()).await;
let ps = core.protected_store();
let api = startup().await;
let ps = api.protected_store().unwrap();
test_protected_store(ps.clone()).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");
core.startup(setup_veilid_core())
api_startup(setup_veilid_core())
.await
.expect("startup failed")
}
@ -169,10 +169,8 @@ pub async fn test_cbor(ts: TableStore) {
}
pub async fn test_all() {
let core = VeilidCore::new();
let api = startup(core.clone()).await;
let ts = core.table_store();
let api = startup().await;
let ts = api.table_store().unwrap();
test_delete_open_delete(ts.clone()).await;
test_store_delete_load(ts.clone()).await;
test_cbor(ts.clone()).await;

View File

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

View File

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

View File

@ -3,28 +3,38 @@
mod debug;
pub use debug::*;
pub use crate::rpc_processor::InfoAnswer;
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::{
IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, SystemPinBoxFuture,
ToSocketAddrs,
};
pub use alloc::string::ToString;
pub use attachment_manager::AttachmentManager;
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 {
NotInitialized,
AlreadyInitialized,
Timeout,
Shutdown,
NodeNotFound(NodeId),
@ -49,6 +59,8 @@ pub enum VeilidAPIError {
impl fmt::Display for VeilidAPIError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
VeilidAPIError::NotInitialized => write!(f, "VeilidAPIError::NotInitialized"),
VeilidAPIError::AlreadyInitialized => write!(f, "VeilidAPIError::AlreadyInitialized"),
VeilidAPIError::Timeout => write!(f, "VeilidAPIError::Timeout"),
VeilidAPIError::Shutdown => write!(f, "VeilidAPIError::Shutdown"),
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 {
Error = 1,
Warn,
@ -128,7 +140,8 @@ impl VeilidLogLevel {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind")]
pub enum VeilidUpdate {
Log {
log_level: VeilidLogLevel,
@ -137,14 +150,14 @@ pub enum VeilidUpdate {
Attachment(AttachmentState),
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VeilidState {
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 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 key: DHTKey,
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 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 socket_address: Option<SocketAddress>,
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct NodeInfo {
pub can_route: bool,
pub will_route: bool,
@ -212,7 +225,7 @@ pub struct NodeInfo {
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
// Must match DialInfo order
pub enum ProtocolType {
@ -222,13 +235,13 @@ pub enum ProtocolType {
WSS,
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
pub enum AddressType {
IPV4,
IPV6,
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
pub enum Address {
IPV4(Ipv4Addr),
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 {
address: Address,
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 peer_scope: PeerScope,
pub protocol_type: Option<ProtocolType>,
@ -435,29 +450,30 @@ pub trait MatchesDialInfoFilter {
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 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 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 socket_address: SocketAddress,
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 socket_address: SocketAddress,
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
// Must match ProtocolType order
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 {
All,
Global,
@ -718,13 +734,13 @@ impl Default for PeerScope {
}
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct PeerInfo {
pub node_id: NodeId,
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 socket_address: SocketAddress,
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 remote: PeerAddress,
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 node_id: NodeId,
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 fastest: u64, // fastest latency in 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
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct TransferStatsDownUp {
pub down: TransferStats,
pub up: TransferStats,
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct TransferStats {
pub total: u64, // total amount transferred ever
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
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct PingStats {
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
@ -869,7 +885,7 @@ pub struct PingStats {
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 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
@ -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 {
Raw,
Turn,
@ -897,7 +913,7 @@ pub enum TunnelMode {
type TunnelId = u64;
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TunnelEndpoint {
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
@ -914,7 +930,7 @@ impl Default for TunnelEndpoint {
}
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct FullTunnel {
pub id: TunnelId,
pub timeout: u64,
@ -922,7 +938,7 @@ pub struct FullTunnel {
pub remote: TunnelEndpoint,
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct PartialTunnel {
pub id: TunnelId,
pub timeout: u64,
@ -931,12 +947,12 @@ pub struct PartialTunnel {
/////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct RouteHopSpec {
pub dial_info: NodeDialInfo,
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct PrivateRouteSpec {
//
pub public_key: DHTKey,
@ -944,7 +960,7 @@ pub struct PrivateRouteSpec {
pub hops: Vec<RouteHopSpec>,
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct SafetyRouteSpec {
pub public_key: DHTKey,
pub secret_key: DHTKeySecret,
@ -962,7 +978,7 @@ impl SafetyRouteSpec {
}
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct RoutingContextOptions {
pub safety_route_spec: Option<SafetyRouteSpec>,
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 node_id: NodeId,
pub dial_info: Vec<DialInfo>,
@ -1051,26 +1067,19 @@ impl RoutingContext {
/////////////////////////////////////////////////////////////////////////////////////////////////////
struct VeilidAPIInner {
core: Option<VeilidCore>,
context: Option<VeilidCoreContext>,
}
impl fmt::Debug for VeilidAPIInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VeilidAPIInner: {}",
match self.core {
Some(_) => "active",
None => "shutdown",
}
)
write!(f, "VeilidAPIInner")
}
}
impl Drop for VeilidAPIInner {
fn drop(&mut self) {
if let Some(core) = self.core.take() {
intf::spawn_local(core.shutdown()).detach();
if let Some(context) = self.context.take() {
intf::spawn_local(api_shutdown(context)).detach();
}
}
}
@ -1080,59 +1089,83 @@ pub struct VeilidAPI {
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 {
pub(crate) fn new(core: VeilidCore) -> Self {
pub(crate) fn new(context: VeilidCoreContext) -> 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) {
let core = { self.inner.lock().core.take() };
if let Some(core) = core {
core.shutdown().await;
let context = { self.inner.lock().context.take() };
if let Some(context) = context {
api_shutdown(context).await;
}
}
pub fn is_shutdown(&self) -> bool {
self.inner.lock().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::xx::*;
use serde::*;
cfg_if! {
if #[cfg(target_arch = "wasm32")] {
pub type ConfigCallbackReturn = Result<Box<dyn core::any::Any>, String>;
@ -9,7 +11,7 @@ cfg_if! {
} else {
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,
}
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub enum VeilidConfigLogLevel {
Off,
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),+)
}
}
#[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_rules! logthru {

View File

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

View File

@ -50,6 +50,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
equatable:
dependency: transitive
description:
name: equatable
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
fake_async:
dependency: transitive
description:
@ -121,6 +128,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
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:
dependency: transitive
description:
@ -128,6 +142,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
oxidized:
dependency: transitive
description:
name: oxidized
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
path:
dependency: transitive
description:
@ -181,7 +202,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.3"
version: "0.4.8"
typed_data:
dependency: transitive
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:ffi';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:veilid/bridge_generated.dart';
import 'package:oxidized/oxidized.dart';
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);
late final veilidApi = VeilidFlutterImpl(dylib);
import 'veilid_stub.dart'
if (dart.library.io) 'veilid_ffi.dart'
if (dart.library.js) 'veilid_js.dart';
class Veilid {
//////////////////////////////////////////////////////////
static VeilidFlutterImpl get api {
if (veilidApi == null) {
throw PlatformException(
code: 'Library missing',
details: 'veilid_flutter library could not be loaded dynamically',
);
}
return veilidApi;
enum AttachmentState {
Detached,
Attaching,
AttachedWeak,
AttachedGood,
AttachedStrong,
FullyAttached,
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
/// A web implementation of the Veilid plugin.
class VeilidWeb {
class VeilidPluginStubWeb {
static void registerWith(Registrar registrar) {
// final MethodChannel channel = MethodChannel(
// '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
flutter_rust_bridge: ^1.14.0
freezed_annotation: ^1.1.0
oxidized: ^5.1.0
ffi: ^1.1.2
dev_dependencies:
flutter_test:
@ -46,8 +48,8 @@ flutter:
windows:
pluginClass: VeilidPlugin
web:
pluginClass: VeilidWeb
fileName: veilid_web.dart
pluginClass: VeilidPluginStubWeb
fileName: veilid_plugin_stub_web.dart
# To add assets to your plugin package, add an assets section, like this:
# assets:

View File

@ -4,16 +4,39 @@ version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "staticlib"]
crate-type = ["cdylib", "staticlib", "rlib"]
[dependencies]
async-std = { version = "^1", features = ["unstable"] }
veilid-core = { path="../../veilid-core" }
flutter_rust_bridge = "^1"
parking_lot = "^0"
log = "^0"
anyhow = { version = "^1", features = ["backtrace"] }
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]
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;
mod bridge_generated;
use cfg_if::*;
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")]
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,
) {
match update {
veilid_core::VeilidUpdate::Log(_ll, _s) => {
veilid_core::VeilidUpdate::Log {
log_level: _,
message: _,
} => {
panic!("Should not be logging to api in server!");
}
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> {
let settingsr = settings.read();
// Create Veilid Core
let veilid_core = veilid_core::VeilidCore::new();
// Create client api state change pipe
let (sender, receiver): (
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
let veilid_api = veilid_core
.startup(vcs)
let veilid_api = veilid_core::api_startup(vcs)
.await
.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)
);
}