This commit is contained in:
John Smith 2022-12-02 22:52:03 -05:00
parent ef313133cf
commit 60aa3fafc0
4 changed files with 282 additions and 73 deletions

View File

@ -21,7 +21,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811 FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811
path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19 path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19
veilid: 6bed3adec63fd8708a2ace498e0e17941c9fc32b veilid: f2b3b5b3ac8cd93fc5443ab830d5153575dacf36
PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c

View File

@ -337,30 +337,40 @@ Stream<T> processStreamJson<T>(
} }
} }
class _Ctx {
final int id;
final VeilidFFI ffi;
_Ctx(this.id, this.ffi);
}
// FFI implementation of VeilidRoutingContext // FFI implementation of VeilidRoutingContext
class VeilidRoutingContextFFI implements VeilidRoutingContext { class VeilidRoutingContextFFI implements VeilidRoutingContext {
final int _id; final _Ctx _ctx;
final VeilidFFI _ffi; static final Finalizer<_Ctx> _finalizer =
Finalizer((ctx) => {ctx.ffi._releaseRoutingContext(ctx.id)});
VeilidRoutingContextFFI._(this._ctx) {
_finalizer.attach(this, _ctx, detach: this);
}
VeilidRoutingContextFFI._(this._id, this._ffi);
@override @override
VeilidRoutingContextFFI withPrivacy() { VeilidRoutingContextFFI withPrivacy() {
final newId = _ffi._routingContextWithPrivacy(_id); final newId = _ctx.ffi._routingContextWithPrivacy(_ctx.id);
return VeilidRoutingContextFFI._(newId, _ffi); return VeilidRoutingContextFFI._(_Ctx(newId, _ctx.ffi));
} }
@override @override
VeilidRoutingContextFFI withCustomPrivacy(Stability stability) { VeilidRoutingContextFFI withCustomPrivacy(Stability stability) {
final newId = _ffi._routingContextWithCustomPrivacy( final newId = _ctx.ffi._routingContextWithCustomPrivacy(
_id, stability.json.toNativeUtf8()); _ctx.id, stability.json.toNativeUtf8());
return VeilidRoutingContextFFI._(newId, _ffi); return VeilidRoutingContextFFI._(_Ctx(newId, _ctx.ffi));
} }
@override @override
VeilidRoutingContextFFI withSequencing(Sequencing sequencing) { VeilidRoutingContextFFI withSequencing(Sequencing sequencing) {
final newId = final newId = _ctx.ffi
_ffi._routingContextWithSequencing(_id, sequencing.json.toNativeUtf8()); ._routingContextWithSequencing(_ctx.id, sequencing.json.toNativeUtf8());
return VeilidRoutingContextFFI._(newId, _ffi); return VeilidRoutingContextFFI._(_Ctx(newId, _ctx.ffi));
} }
@override @override
@ -370,8 +380,8 @@ class VeilidRoutingContextFFI implements VeilidRoutingContext {
final recvPort = ReceivePort("routing_context_app_call"); final recvPort = ReceivePort("routing_context_app_call");
final sendPort = recvPort.sendPort; final sendPort = recvPort.sendPort;
_ffi._routingContextAppCall( _ctx.ffi._routingContextAppCall(sendPort.nativePort, _ctx.id,
sendPort.nativePort, _id, nativeEncodedTarget, nativeEncodedRequest); nativeEncodedTarget, nativeEncodedRequest);
final out = await processFuturePlain(recvPort.first); final out = await processFuturePlain(recvPort.first);
return base64Decode(out); return base64Decode(out);
} }
@ -381,10 +391,10 @@ class VeilidRoutingContextFFI implements VeilidRoutingContext {
var nativeEncodedTarget = target.toNativeUtf8(); var nativeEncodedTarget = target.toNativeUtf8();
var nativeEncodedMessage = base64UrlEncode(message).toNativeUtf8(); var nativeEncodedMessage = base64UrlEncode(message).toNativeUtf8();
final recvPort = ReceivePort("routing_context_app_call"); final recvPort = ReceivePort("routing_context_app_message");
final sendPort = recvPort.sendPort; final sendPort = recvPort.sendPort;
_ffi._routingContextAppCall( _ctx.ffi._routingContextAppMessage(sendPort.nativePort, _ctx.id,
sendPort.nativePort, _id, nativeEncodedTarget, nativeEncodedMessage); nativeEncodedTarget, nativeEncodedMessage);
return processFutureVoid(recvPort.first); return processFutureVoid(recvPort.first);
} }
} }
@ -566,7 +576,7 @@ class VeilidFFI implements Veilid {
final sendPort = recvPort.sendPort; final sendPort = recvPort.sendPort;
_routingContext(sendPort.nativePort); _routingContext(sendPort.nativePort);
final id = await processFuturePlain(recvPort.first); final id = await processFuturePlain(recvPort.first);
return VeilidRoutingContextFFI._(id, this); return VeilidRoutingContextFFI._(_Ctx(id, this));
} }
@override @override

View File

@ -19,59 +19,62 @@ Future<T> _wrapApiPromise<T>(Object p) {
VeilidAPIException.fromJson(jsonDecode(error as String)))); VeilidAPIException.fromJson(jsonDecode(error as String))));
} }
class _Ctx {
final int id;
final VeilidJS js;
_Ctx(this.id, this.js);
}
// JS implementation of VeilidRoutingContext // JS implementation of VeilidRoutingContext
class VeilidRoutingContextJS implements VeilidRoutingContext { class VeilidRoutingContextJS implements VeilidRoutingContext {
final int _id; final _Ctx _ctx;
final VeilidFFI _ffi; static final Finalizer<_Ctx> _finalizer = Finalizer((ctx) => {
js_util.callMethod(wasm, "release_routing_context", [ctx.id])
});
VeilidRoutingContextFFI._(this._id, this._ffi); VeilidRoutingContextJS._(this._ctx) {
@override _finalizer.attach(this, _ctx, detach: this);
VeilidRoutingContextFFI withPrivacy() {
final newId = _ffi._routingContextWithPrivacy(_id);
return VeilidRoutingContextFFI._(newId, _ffi);
} }
@override @override
VeilidRoutingContextFFI withCustomPrivacy(Stability stability) { VeilidRoutingContextJS withPrivacy() {
final newId = _ffi._routingContextWithCustomPrivacy( int newId =
_id, stability.json.toNativeUtf8()); js_util.callMethod(wasm, "routing_context_with_privacy", [_ctx.id]);
return VeilidRoutingContextFFI._(newId, _ffi); return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
} }
@override @override
VeilidRoutingContextFFI withSequencing(Sequencing sequencing) { VeilidRoutingContextJS withCustomPrivacy(Stability stability) {
final newId = final newId = js_util.callMethod(
_ffi._routingContextWithSequencing(_id, sequencing.json.toNativeUtf8()); wasm, "routing_context_with_custom_privacy", [_ctx.id, stability.json]);
return VeilidRoutingContextFFI._(newId, _ffi);
return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
}
@override
VeilidRoutingContextJS withSequencing(Sequencing sequencing) {
final newId = js_util.callMethod(
wasm, "routing_context_with_sequencing", [_ctx.id, sequencing.json]);
return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
} }
@override @override
Future<Uint8List> appCall(String target, Uint8List request) async { Future<Uint8List> appCall(String target, Uint8List request) async {
var nativeEncodedTarget = target.toNativeUtf8(); var encodedRequest = base64UrlEncode(request);
var nativeEncodedRequest = base64UrlEncode(request).toNativeUtf8();
final recvPort = ReceivePort("routing_context_app_call"); return base64Decode(await _wrapApiPromise(js_util.callMethod(
final sendPort = recvPort.sendPort; wasm, "routing_context_app_call", [_ctx.id, encodedRequest])));
_ffi._routingContextAppCall(
sendPort.nativePort, _id, nativeEncodedTarget, nativeEncodedRequest);
final out = await processFuturePlain(recvPort.first);
return base64Decode(out);
} }
@override @override
Future<void> appMessage(String target, Uint8List message) async { Future<void> appMessage(String target, Uint8List message) async {
var nativeEncodedTarget = target.toNativeUtf8(); var encodedMessage = base64UrlEncode(message);
var nativeEncodedMessage = base64UrlEncode(message).toNativeUtf8();
final recvPort = ReceivePort("routing_context_app_call"); return _wrapApiPromise(js_util.callMethod(
final sendPort = recvPort.sendPort; wasm, "routing_context_app_message", [_ctx.id, encodedMessage]));
_ffi._routingContextAppCall(
sendPort.nativePort, _id, nativeEncodedTarget, nativeEncodedMessage);
return processFutureVoid(recvPort.first);
} }
} }
// JS implementation of high level Veilid API // JS implementation of high level Veilid API
class VeilidJS implements Veilid { class VeilidJS implements Veilid {
@ -133,30 +136,32 @@ class VeilidJS implements Veilid {
js_util.callMethod(wasm, "shutdown_veilid_core", [])); js_util.callMethod(wasm, "shutdown_veilid_core", []));
} }
@override @override
Future<VeilidRoutingContext> routingContext() async { Future<VeilidRoutingContext> routingContext() async {
final recvPort = ReceivePort("routing_context"); int id = jsonDecode(
final sendPort = recvPort.sendPort; await _wrapApiPromise(js_util.callMethod(wasm, "routing_context", [])));
_routingContext(sendPort.nativePort); return VeilidRoutingContextJS._(_Ctx(id, this));
final id = await processFuturePlain(recvPort.first);
return VeilidRoutingContextFFI._(id, this);
} }
@override @override
Future<KeyBlob> newPrivateRoute() async { Future<KeyBlob> newPrivateRoute() async {
final recvPort = ReceivePort("new_private_route"); Map<String, dynamic> blobJson = jsonDecode(await _wrapApiPromise(
final sendPort = recvPort.sendPort; js_util.callMethod(wasm, "new_private_route", [])));
_newPrivateRoute(sendPort.nativePort); return KeyBlob.fromJson(blobJson);
return processFutureJson(KeyBlob.fromJson, recvPort.first);
} }
@override @override
Future<KeyBlob> newCustomPrivateRoute( Future<KeyBlob> newCustomPrivateRoute(
Stability stability, Sequencing sequencing) async { Stability stability, Sequencing sequencing) async {
return _wrapApiPromise( var stabilityString =
js_util.callMethod(wasm, "new_custom_private_route", [stability, sequencing])); jsonEncode(stability, toEncodable: veilidApiToEncodable);
var sequencingString =
jsonEncode(sequencing, toEncodable: veilidApiToEncodable);
Map<String, dynamic> blobJson = jsonDecode(await _wrapApiPromise(js_util
.callMethod(
wasm, "new_private_route", [stabilityString, sequencingString])));
return KeyBlob.fromJson(blobJson);
} }
@override @override
@ -191,7 +196,7 @@ class VeilidJS implements Veilid {
@override @override
VeilidVersion veilidVersion() { VeilidVersion veilidVersion() {
var jsonVersion = Map<String, dynamic> jsonVersion =
jsonDecode(js_util.callMethod(wasm, "veilid_version", [])); jsonDecode(js_util.callMethod(wasm, "veilid_version", []));
return VeilidVersion( return VeilidVersion(
jsonVersion["major"], jsonVersion["minor"], jsonVersion["patch"]); jsonVersion["major"], jsonVersion["minor"], jsonVersion["patch"]);

View File

@ -9,6 +9,7 @@ use alloc::sync::Arc;
use alloc::*; use alloc::*;
use core::any::{Any, TypeId}; use core::any::{Any, TypeId};
use core::cell::RefCell; use core::cell::RefCell;
use core::fmt::Debug;
use futures_util::FutureExt; use futures_util::FutureExt;
use gloo_utils::format::JsValueSerdeExt; use gloo_utils::format::JsValueSerdeExt;
use js_sys::*; use js_sys::*;
@ -21,6 +22,7 @@ use tracing_subscriber::*;
use tracing_wasm::{WASMLayerConfigBuilder, *}; use tracing_wasm::{WASMLayerConfigBuilder, *};
use veilid_core::tools::*; use veilid_core::tools::*;
use veilid_core::*; use veilid_core::*;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::*; use wasm_bindgen_futures::*;
// Allocator // Allocator
@ -57,11 +59,13 @@ fn take_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::VeilidAPIErr
} }
// JSON Helpers for WASM // JSON Helpers for WASM
pub fn to_json<T: Serialize>(val: T) -> JsValue { pub fn to_json<T: Serialize + Debug>(val: T) -> JsValue {
JsValue::from_str(&serialize_json(val)) JsValue::from_str(&serialize_json(val))
} }
pub fn from_json<T: de::DeserializeOwned>(val: JsValue) -> Result<T, veilid_core::VeilidAPIError> { pub fn from_json<T: de::DeserializeOwned + Debug>(
val: JsValue,
) -> Result<T, veilid_core::VeilidAPIError> {
let s = val let s = val
.as_string() .as_string()
.ok_or_else(|| veilid_core::VeilidAPIError::ParseError { .ok_or_else(|| veilid_core::VeilidAPIError::ParseError {
@ -78,7 +82,7 @@ const APIRESULT_UNDEFINED: APIResult<()> = APIResult::Ok(());
pub fn wrap_api_future<F, T>(future: F) -> Promise pub fn wrap_api_future<F, T>(future: F) -> Promise
where where
F: Future<Output = APIResult<T>> + 'static, F: Future<Output = APIResult<T>> + 'static,
T: Serialize + 'static, T: Serialize + Debug + 'static,
{ {
future_to_promise(future.map(|res| { future_to_promise(future.map(|res| {
res.map(|v| { res.map(|v| {
@ -121,7 +125,7 @@ pub struct VeilidWASMConfig {
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct VeilidFFIKeyBlob { pub struct VeilidKeyBlob {
pub key: veilid_core::DHTKey, pub key: veilid_core::DHTKey,
#[serde(with = "veilid_core::json_as_base64")] #[serde(with = "veilid_core::json_as_base64")]
pub blob: Vec<u8>, pub blob: Vec<u8>,
@ -256,17 +260,201 @@ pub fn shutdown_veilid_core() -> Promise {
}) })
} }
fn add_routing_context(routing_context: veilid_core::RoutingContext) -> u32 {
let mut next_id: u32 = 1;
let mut rc = (*ROUTING_CONTEXTS).borrow_mut();
while rc.contains_key(&next_id) {
next_id += 1;
}
rc.insert(next_id, routing_context);
next_id
}
#[wasm_bindgen()] #[wasm_bindgen()]
pub fn debug(command: String) -> Promise { pub fn routing_context() -> Promise {
wrap_api_future(async move { wrap_api_future(async move {
let veilid_api = get_veilid_api()?; let veilid_api = get_veilid_api()?;
let out = veilid_api.debug(command).await?; let routing_context = veilid_api.routing_context();
Ok(out) let new_id = add_routing_context(routing_context);
APIResult::Ok(new_id)
})
}
#[wasm_bindgen()]
pub fn release_routing_context(id: u32) -> i32 {
let mut rc = (*ROUTING_CONTEXTS).borrow_mut();
if rc.remove(&id).is_none() {
return 0;
}
return 1;
}
#[wasm_bindgen()]
pub fn routing_context_with_privacy(id: u32) -> u32 {
let rc = (*ROUTING_CONTEXTS).borrow();
let Some(routing_context) = rc.get(&id) else {
return 0;
};
let Ok(routing_context) = routing_context.clone().with_privacy() else {
return 0;
};
let new_id = add_routing_context(routing_context);
new_id
}
#[wasm_bindgen()]
pub fn routing_context_with_custom_privacy(id: u32, stability: String) -> u32 {
let stability: veilid_core::Stability = veilid_core::deserialize_json(&stability).unwrap();
let rc = (*ROUTING_CONTEXTS).borrow();
let Some(routing_context) = rc.get(&id) else {
return 0;
};
let Ok(routing_context) = routing_context.clone().with_custom_privacy(stability) else {
return 0;
};
let new_id = add_routing_context(routing_context);
new_id
}
#[wasm_bindgen()]
pub fn routing_context_with_sequencing(id: u32, sequencing: String) -> u32 {
let sequencing: veilid_core::Sequencing = veilid_core::deserialize_json(&sequencing).unwrap();
let rc = (*ROUTING_CONTEXTS).borrow();
let Some(routing_context) = rc.get(&id) else {
return 0;
};
let routing_context = routing_context.clone().with_sequencing(sequencing);
let new_id = add_routing_context(routing_context);
new_id
}
#[wasm_bindgen()]
pub fn routing_context_app_call(id: u32, target: String, request: String) -> Promise {
let request: Vec<u8> = data_encoding::BASE64URL_NOPAD
.decode(request.as_bytes())
.unwrap();
wrap_api_future(async move {
let veilid_api = get_veilid_api()?;
let routing_table = veilid_api.routing_table()?;
let rss = routing_table.route_spec_store();
let routing_context = {
let rc = (*ROUTING_CONTEXTS).borrow();
let Some(routing_context) = rc.get(&id) else {
return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("routing_context_app_call", "id", id));
};
routing_context.clone()
};
let target: DHTKey =
DHTKey::try_decode(&target).map_err(|e| VeilidAPIError::parse_error(e, &target))?;
let target = if rss.get_remote_private_route(&target).is_some() {
veilid_core::Target::PrivateRoute(target)
} else {
veilid_core::Target::NodeId(veilid_core::NodeId::new(target))
};
let answer = routing_context.app_call(target, request).await?;
let answer = data_encoding::BASE64URL_NOPAD.encode(&answer);
APIResult::Ok(answer)
})
}
#[wasm_bindgen()]
pub fn routing_context_app_message(id: u32, target: String, message: String) -> Promise {
let message: Vec<u8> = data_encoding::BASE64URL_NOPAD
.decode(message.as_bytes())
.unwrap();
wrap_api_future(async move {
let veilid_api = get_veilid_api()?;
let routing_table = veilid_api.routing_table()?;
let rss = routing_table.route_spec_store();
let routing_context = {
let rc = (*ROUTING_CONTEXTS).borrow();
let Some(routing_context) = rc.get(&id) else {
return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument("routing_context_app_call", "id", id));
};
routing_context.clone()
};
let target: DHTKey =
DHTKey::try_decode(&target).map_err(|e| VeilidAPIError::parse_error(e, &target))?;
let target = if rss.get_remote_private_route(&target).is_some() {
veilid_core::Target::PrivateRoute(target)
} else {
veilid_core::Target::NodeId(veilid_core::NodeId::new(target))
};
routing_context.app_message(target, message).await?;
APIRESULT_UNDEFINED
})
}
#[wasm_bindgen()]
pub fn new_private_route() -> Promise {
wrap_api_future(async move {
let veilid_api = get_veilid_api()?;
let (key, blob) = veilid_api.new_private_route().await?;
let keyblob = VeilidKeyBlob { key, blob };
APIResult::Ok(keyblob)
})
}
#[wasm_bindgen()]
pub fn new_custom_private_route(stability: String, sequencing: String) -> Promise {
let stability: veilid_core::Stability = veilid_core::deserialize_json(&stability).unwrap();
let sequencing: veilid_core::Sequencing = veilid_core::deserialize_json(&sequencing).unwrap();
wrap_api_future(async move {
let veilid_api = get_veilid_api()?;
let (key, blob) = veilid_api
.new_custom_private_route(stability, sequencing)
.await?;
let keyblob = VeilidKeyBlob { key, blob };
APIResult::Ok(keyblob)
})
}
#[wasm_bindgen()]
pub fn import_remote_private_route(blob: String) -> Promise {
let blob: Vec<u8> = data_encoding::BASE64URL_NOPAD
.decode(blob.as_bytes())
.unwrap();
wrap_api_future(async move {
let veilid_api = get_veilid_api()?;
let key = veilid_api.import_remote_private_route(blob)?;
APIResult::Ok(key.encode())
})
}
#[wasm_bindgen()]
pub fn release_private_route(key: String) -> Promise {
let key: veilid_core::DHTKey = veilid_core::deserialize_json(&key).unwrap();
wrap_api_future(async move {
let veilid_api = get_veilid_api()?;
veilid_api.release_private_route(&key)?;
APIRESULT_UNDEFINED
}) })
} }
#[wasm_bindgen()] #[wasm_bindgen()]
pub fn app_call_reply(id: String, message: String) -> Promise { pub fn app_call_reply(id: String, message: String) -> Promise {
let message: Vec<u8> = data_encoding::BASE64URL_NOPAD
.decode(message.as_bytes())
.unwrap();
wrap_api_future(async move { wrap_api_future(async move {
let id = match id.parse() { let id = match id.parse() {
Ok(v) => v, Ok(v) => v,
@ -274,15 +462,21 @@ pub fn app_call_reply(id: String, message: String) -> Promise {
return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument(e, "id", id)) return APIResult::Err(veilid_core::VeilidAPIError::invalid_argument(e, "id", id))
} }
}; };
let message = data_encoding::BASE64URL_NOPAD
.decode(message.as_bytes())
.map_err(|e| veilid_core::VeilidAPIError::invalid_argument(e, "message", message))?;
let veilid_api = get_veilid_api()?; let veilid_api = get_veilid_api()?;
let out = veilid_api.app_call_reply(id, message).await?; let out = veilid_api.app_call_reply(id, message).await?;
Ok(out) Ok(out)
}) })
} }
#[wasm_bindgen()]
pub fn debug(command: String) -> Promise {
wrap_api_future(async move {
let veilid_api = get_veilid_api()?;
let out = veilid_api.debug(command).await?;
Ok(out)
})
}
#[wasm_bindgen()] #[wasm_bindgen()]
pub fn veilid_version_string() -> String { pub fn veilid_version_string() -> String {
veilid_core::veilid_version_string() veilid_core::veilid_version_string()