mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-10-01 01:26:08 -04:00
ffi work
This commit is contained in:
parent
d660d86884
commit
70960fa592
104
Cargo.lock
generated
104
Cargo.lock
generated
@ -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"
|
||||
|
@ -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" ]
|
||||
|
2
external/keyring-manager
vendored
2
external/keyring-manager
vendored
@ -1 +1 @@
|
||||
Subproject commit 3713e10599c6078e058aab785ef46594420dc11b
|
||||
Subproject commit 935ca957d7e223ef560a0b20b656730a325e0ba7
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
197
veilid-core/src/core_context.rs
Normal file
197
veilid-core/src/core_context.rs
Normal 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;
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)?;
|
||||
|
||||
|
@ -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) {}
|
||||
}
|
||||
|
@ -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::*;
|
||||
|
@ -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?;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {}
|
||||
}
|
||||
|
@ -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"),
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Debugging
|
||||
|
||||
use super::*;
|
||||
use routing_table::*;
|
||||
|
||||
fn get_bucket_entry_state(text: &str) -> Option<BucketEntryState> {
|
||||
if text == "dead" {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
//
|
||||
}
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
106
veilid-flutter/lib/veilid_ffi.dart
Normal file
106
veilid-flutter/lib/veilid_ffi.dart
Normal 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();
|
||||
}
|
||||
|
||||
}
|
41
veilid-flutter/lib/veilid_js.dart
Normal file
41
veilid-flutter/lib/veilid_js.dart
Normal 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();
|
||||
}
|
||||
|
||||
}
|
@ -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',
|
3
veilid-flutter/lib/veilid_stub.dart
Normal file
3
veilid-flutter/lib/veilid_stub.dart
Normal file
@ -0,0 +1,3 @@
|
||||
import 'veilid.dart'
|
||||
|
||||
Veilid getVeilid() => throw UnsupportedError('Cannot create Veilid object');
|
@ -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:
|
||||
|
@ -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"
|
||||
|
@ -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");
|
||||
}
|
@ -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,
|
||||
})
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
243
veilid-flutter/rust/src/config.rs
Normal file
243
veilid-flutter/rust/src/config.rs
Normal 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)
|
||||
}
|
||||
}
|
177
veilid-flutter/rust/src/dart_ffi.rs
Normal file
177
veilid-flutter/rust/src/dart_ffi.rs
Normal 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,
|
||||
}
|
||||
}
|
151
veilid-flutter/rust/src/dart_isolate_wrapper.rs
Normal file
151
veilid-flutter/rust/src/dart_isolate_wrapper.rs
Normal 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()]);
|
||||
}
|
||||
}
|
||||
}
|
24
veilid-flutter/rust/src/dart_serialize.rs
Normal file
24
veilid-flutter/rust/src/dart_serialize.rs
Normal 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")
|
||||
}
|
@ -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};
|
||||
|
25
veilid-flutter/rust/src/wasm/mod.rs
Normal file
25
veilid-flutter/rust/src/wasm/mod.rs
Normal 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;
|
@ -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) => {
|
||||
|
@ -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
5
veilid-wasm/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
bin/
|
||||
pkg/
|
||||
wasm-pack.log
|
23
veilid-wasm/Cargo.toml
Normal file
23
veilid-wasm/Cargo.toml
Normal 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"
|
286
veilid-wasm/src/js_veilid_core.rs
Normal file
286
veilid-wasm/src/js_veilid_core.rs
Normal 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
25
veilid-wasm/src/lib.rs
Normal 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
38
veilid-wasm/src/utils.rs
Normal 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
179
veilid-wasm/tests/web.rs
Normal 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)
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user