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:
FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811
path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19
veilid: 6bed3adec63fd8708a2ace498e0e17941c9fc32b
veilid: f2b3b5b3ac8cd93fc5443ab830d5153575dacf36
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
class VeilidRoutingContextFFI implements VeilidRoutingContext {
final int _id;
final VeilidFFI _ffi;
final _Ctx _ctx;
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
VeilidRoutingContextFFI withPrivacy() {
final newId = _ffi._routingContextWithPrivacy(_id);
return VeilidRoutingContextFFI._(newId, _ffi);
final newId = _ctx.ffi._routingContextWithPrivacy(_ctx.id);
return VeilidRoutingContextFFI._(_Ctx(newId, _ctx.ffi));
}
@override
VeilidRoutingContextFFI withCustomPrivacy(Stability stability) {
final newId = _ffi._routingContextWithCustomPrivacy(
_id, stability.json.toNativeUtf8());
return VeilidRoutingContextFFI._(newId, _ffi);
final newId = _ctx.ffi._routingContextWithCustomPrivacy(
_ctx.id, stability.json.toNativeUtf8());
return VeilidRoutingContextFFI._(_Ctx(newId, _ctx.ffi));
}
@override
VeilidRoutingContextFFI withSequencing(Sequencing sequencing) {
final newId =
_ffi._routingContextWithSequencing(_id, sequencing.json.toNativeUtf8());
return VeilidRoutingContextFFI._(newId, _ffi);
final newId = _ctx.ffi
._routingContextWithSequencing(_ctx.id, sequencing.json.toNativeUtf8());
return VeilidRoutingContextFFI._(_Ctx(newId, _ctx.ffi));
}
@override
@ -370,8 +380,8 @@ class VeilidRoutingContextFFI implements VeilidRoutingContext {
final recvPort = ReceivePort("routing_context_app_call");
final sendPort = recvPort.sendPort;
_ffi._routingContextAppCall(
sendPort.nativePort, _id, nativeEncodedTarget, nativeEncodedRequest);
_ctx.ffi._routingContextAppCall(sendPort.nativePort, _ctx.id,
nativeEncodedTarget, nativeEncodedRequest);
final out = await processFuturePlain(recvPort.first);
return base64Decode(out);
}
@ -381,10 +391,10 @@ class VeilidRoutingContextFFI implements VeilidRoutingContext {
var nativeEncodedTarget = target.toNativeUtf8();
var nativeEncodedMessage = base64UrlEncode(message).toNativeUtf8();
final recvPort = ReceivePort("routing_context_app_call");
final recvPort = ReceivePort("routing_context_app_message");
final sendPort = recvPort.sendPort;
_ffi._routingContextAppCall(
sendPort.nativePort, _id, nativeEncodedTarget, nativeEncodedMessage);
_ctx.ffi._routingContextAppMessage(sendPort.nativePort, _ctx.id,
nativeEncodedTarget, nativeEncodedMessage);
return processFutureVoid(recvPort.first);
}
}
@ -566,7 +576,7 @@ class VeilidFFI implements Veilid {
final sendPort = recvPort.sendPort;
_routingContext(sendPort.nativePort);
final id = await processFuturePlain(recvPort.first);
return VeilidRoutingContextFFI._(id, this);
return VeilidRoutingContextFFI._(_Ctx(id, this));
}
@override

View File

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

View File

@ -9,6 +9,7 @@ use alloc::sync::Arc;
use alloc::*;
use core::any::{Any, TypeId};
use core::cell::RefCell;
use core::fmt::Debug;
use futures_util::FutureExt;
use gloo_utils::format::JsValueSerdeExt;
use js_sys::*;
@ -21,6 +22,7 @@ use tracing_subscriber::*;
use tracing_wasm::{WASMLayerConfigBuilder, *};
use veilid_core::tools::*;
use veilid_core::*;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::*;
// Allocator
@ -57,11 +59,13 @@ fn take_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::VeilidAPIErr
}
// 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))
}
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
.as_string()
.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
where
F: Future<Output = APIResult<T>> + 'static,
T: Serialize + 'static,
T: Serialize + Debug + 'static,
{
future_to_promise(future.map(|res| {
res.map(|v| {
@ -121,7 +125,7 @@ pub struct VeilidWASMConfig {
}
#[derive(Debug, Deserialize, Serialize)]
pub struct VeilidFFIKeyBlob {
pub struct VeilidKeyBlob {
pub key: veilid_core::DHTKey,
#[serde(with = "veilid_core::json_as_base64")]
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()]
pub fn debug(command: String) -> Promise {
pub fn routing_context() -> Promise {
wrap_api_future(async move {
let veilid_api = get_veilid_api()?;
let out = veilid_api.debug(command).await?;
Ok(out)
let routing_context = veilid_api.routing_context();
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()]
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 {
let id = match id.parse() {
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))
}
};
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 out = veilid_api.app_call_reply(id, message).await?;
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()]
pub fn veilid_version_string() -> String {
veilid_core::veilid_version_string()