Widgets are now just values and not js promises. All js runtimes run in the same tokio runtime

Simplifies error reporting
This commit is contained in:
Exidex 2023-11-16 20:11:06 +01:00
parent f7bf8054b7
commit 6ab8bcba4a
5 changed files with 80 additions and 107 deletions

View file

@ -52,10 +52,7 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
},
appendInitialChild: (parentInstance: Instance, child: Instance | TextInstance): void => {
Promise.all([parentInstance, child])
.then(([resolvedParent, resolvedChild]) => {
InternalApi.op_react_append_child(resolvedParent, resolvedChild)
})
InternalApi.op_react_append_child(parentInstance, child)
},
finalizeInitialChildren: (
@ -131,18 +128,12 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
appendChild(parentInstance: Instance, child: Instance | TextInstance): void {
assertMutationMode(options.mode);
Promise.all([parentInstance, child])
.then(([resolvedParent, resolvedChild]) => {
InternalApi.op_react_append_child(resolvedParent, resolvedChild)
})
InternalApi.op_react_append_child(parentInstance, child)
},
appendChildToContainer(container: Container, child: Instance | TextInstance): void {
assertMutationMode(options.mode);
Promise.all([container, child])
.then(([resolvedContainer, resolvedChild]) => {
InternalApi.op_react_append_child(resolvedContainer, resolvedChild)
})
InternalApi.op_react_append_child(container, child)
},
insertBefore(
@ -152,10 +143,7 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
): void {
assertMutationMode(options.mode);
Promise.all([parentInstance, child, beforeChild])
.then(([resolvedParentInstance, resolvedChild, resolvedBeforeChild]) => {
InternalApi.op_react_insert_before(resolvedParentInstance, resolvedChild, resolvedBeforeChild)
})
InternalApi.op_react_insert_before(parentInstance, child, beforeChild)
},
insertInContainerBefore(
container: Container,
@ -164,10 +152,7 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
): void {
assertMutationMode(options.mode);
Promise.all([container, child, beforeChild])
.then(([resolvedContainer, resolvedChild, resolvedBeforeChild]) => {
InternalApi.op_react_insert_before(resolvedContainer, resolvedChild, resolvedBeforeChild)
})
InternalApi.op_react_insert_before(container, child, beforeChild)
},
removeChild(
@ -176,10 +161,7 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
): void {
assertMutationMode(options.mode);
Promise.all([parentInstance, child])
.then(([resolvedParent, resolvedChild]) => {
InternalApi.op_react_remove_child(resolvedParent, resolvedChild)
})
InternalApi.op_react_remove_child(parentInstance, child)
},
removeChildFromContainer(
container: Container,
@ -187,10 +169,7 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
): void {
assertMutationMode(options.mode);
Promise.all([container, child])
.then(([resolvedContainer, resolvedChild]) => {
InternalApi.op_react_remove_child(resolvedContainer, resolvedChild)
})
InternalApi.op_react_remove_child(container, child)
},
@ -201,13 +180,13 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
const props = Object.fromEntries(
updatePayload.map(propName => [propName, nextProps[propName]])
);
instance.then(value => InternalApi.op_react_set_properties(value, props));
InternalApi.op_react_set_properties(instance, props);
}
},
commitTextUpdate(textInstance: TextInstance, oldText: string, newText: string): void {
assertMutationMode(options.mode);
textInstance.then(value => InternalApi.op_react_set_text(value, newText))
InternalApi.op_react_set_text(textInstance, newText)
},
hideInstance(instance: Instance): void {
@ -268,10 +247,8 @@ export const createHostConfig = (options: { mode: "mutation" | "persistent" }):
replaceContainerChildren(container: Container, newChildren: ChildSet): void {
assertPersistentMode(options.mode);
Promise.all([container, ...newChildren])
.then(([resolvedContainer, ...resolvedChild]) => {
InternalApi.op_react_replace_container_children(resolvedContainer, resolvedChild)
})
InternalApi.op_react_replace_container_children(container, newChildren)
},
cloneHiddenInstance(

38
js/typings/index.d.ts vendored
View file

@ -18,23 +18,23 @@ declare interface Deno {
declare type PluginEvent = ViewEvent | ViewCreated | ViewDestroyed | PluginCommand
declare type ViewEvent = {
declare type ViewEvent = {
type: "ViewEvent"
eventName: string
widget: InstanceSync
widget: Instance
}
declare type ViewCreated = {
declare type ViewCreated = {
type: "ViewCreated"
reconcilerMode: string
viewName: string
}
declare type ViewDestroyed = {
declare type ViewDestroyed = {
type: "ViewDestroyed"
}
declare type PluginCommand = {
declare type PluginCommand = {
type: "PluginCommand"
commandType: "stop"
}
@ -45,16 +45,14 @@ declare type Type = string;
declare type Props = { children?: any } & { [key: string]: any };
declare type Container = Instance
declare type Instance = Promise<UiWidget>
declare type TextInstance = Promise<UiWidget>
declare type InstanceSync = UiWidget
declare type TextInstanceSync = UiWidget
declare type ChildSet = (InstanceSync | TextInstanceSync)[]
declare type Instance = UiWidget
declare type TextInstance = UiWidget
declare type ChildSet = (Instance | TextInstance)[]
type SuspenseInstance = never;
declare interface InternalApi {
op_react_call_event_listener(instance: InstanceSync, eventName: string): void;
op_react_call_event_listener(instance: Instance, eventName: string): void;
op_react_get_container(): Container;
@ -62,25 +60,25 @@ declare interface InternalApi {
op_react_create_text_instance(text: string): TextInstance;
op_react_append_child(parent: InstanceSync, child: InstanceSync | TextInstanceSync): void;
op_react_append_child(parent: Instance, child: Instance | TextInstance): void;
op_react_call_event_listener(instance: InstanceSync, eventName: string): void;
op_react_call_event_listener(instance: Instance, eventName: string): void;
// mutation mode
op_react_remove_child(parent: InstanceSync, child: InstanceSync | TextInstanceSync): void;
op_react_remove_child(parent: Instance, child: Instance | TextInstance): void;
op_react_insert_before(
parent: InstanceSync,
child: InstanceSync | TextInstanceSync | SuspenseInstance,
beforeChild: InstanceSync | TextInstanceSync | SuspenseInstance
parent: Instance,
child: Instance | TextInstance | SuspenseInstance,
beforeChild: Instance | TextInstance | SuspenseInstance
): void;
op_react_set_properties(instance: InstanceSync, properties: Props): void;
op_react_set_properties(instance: Instance, properties: Props): void;
op_react_set_text(instance: InstanceSync, text: string): void;
op_react_set_text(instance: Instance, text: string): void;
// persistent mode
op_react_clone_instance(type: Type, properties: Props): Instance;
op_react_replace_container_children(container: InstanceSync, newChildren: ChildSet): void;
op_react_replace_container_children(container: Instance, newChildren: ChildSet): void;
}

View file

@ -9,7 +9,7 @@ pub(in crate) mod model;
mod dirs;
pub fn start_server() {
let runtime = tokio::runtime::Builder::new_current_thread()
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();

View file

@ -7,6 +7,7 @@ use std::rc::Rc;
use anyhow::anyhow;
use deno_core::{FastString, futures, ModuleLoader, ModuleSource, ModuleSourceFuture, ModuleType, op, OpState, ResolutionKind, serde_v8, StaticModuleLoader, v8};
use deno_core::futures::{FutureExt, Stream, StreamExt};
use deno_core::futures::executor::block_on;
use deno_runtime::deno_core::ModuleSpecifier;
use deno_runtime::permissions::PermissionsContainer;
use deno_runtime::worker::MainWorker;
@ -369,10 +370,10 @@ deno_core::extension!(
#[op]
async fn op_react_get_container(state: Rc<RefCell<OpState>>) -> anyhow::Result<JsUiWidget> {
fn op_react_get_container(state: Rc<RefCell<OpState>>) -> anyhow::Result<JsUiWidget> {
println!("op_react_get_container");
let container = match make_request_receive(&state, JsUiRequestData::GetContainer).await? {
let container = match make_request_receive(&state, JsUiRequestData::GetContainer)? {
JsUiResponseData::GetContainer { container } => container,
value @ _ => panic!("unsupported response type {:?}", value),
};
@ -383,7 +384,7 @@ async fn op_react_get_container(state: Rc<RefCell<OpState>>) -> anyhow::Result<J
}
#[op]
async fn op_react_append_child(
fn op_react_append_child(
state: Rc<RefCell<OpState>>,
parent: JsUiWidget,
child: JsUiWidget,
@ -395,7 +396,7 @@ async fn op_react_append_child(
child,
};
match make_request_receive(&state, data).await? {
match make_request_receive(&state, data)? {
JsUiResponseData::Nothing => {
println!("op_react_append_child end");
Ok(())
@ -405,7 +406,7 @@ async fn op_react_append_child(
}
#[op]
async fn op_react_remove_child(
fn op_react_remove_child(
state: Rc<RefCell<OpState>>,
parent: JsUiWidget,
child: JsUiWidget,
@ -417,7 +418,7 @@ async fn op_react_remove_child(
child: child.into(),
};
match make_request_receive(&state, data).await? {
match make_request_receive(&state, data)? {
JsUiResponseData::Nothing => {
println!("op_react_remove_child end");
Ok(())
@ -427,7 +428,7 @@ async fn op_react_remove_child(
}
#[op]
async fn op_react_insert_before(
fn op_react_insert_before(
state: Rc<RefCell<OpState>>,
parent: JsUiWidget,
child: JsUiWidget,
@ -441,7 +442,7 @@ async fn op_react_insert_before(
before_child,
};
match make_request_receive(&state, data).await? {
match make_request_receive(&state, data)? {
JsUiResponseData::Nothing => {
println!("op_react_insert_before end");
Ok(())
@ -456,7 +457,7 @@ fn op_react_create_instance<'a>(
state: Rc<RefCell<OpState>>,
widget_type: String,
v8_properties: HashMap<String, serde_v8::Value<'a>>,
) -> anyhow::Result<impl Future<Output=anyhow::Result<JsUiWidget>> + 'static> {
) -> anyhow::Result<JsUiWidget> {
// TODO component model
println!("op_react_create_instance");
@ -475,20 +476,18 @@ fn op_react_create_instance<'a>(
println!("op_react_create_instance end");
Ok(async move {
let widget = match make_request_receive(&state, data).await? {
JsUiResponseData::CreateInstance { widget } => widget,
value @ _ => panic!("unsupported response type {:?}", value),
};
let widget = match make_request_receive(&state, data)? {
JsUiResponseData::CreateInstance { widget } => widget,
value @ _ => panic!("unsupported response type {:?}", value),
};
assign_event_listeners(&state, &widget, &conversion_properties);
assign_event_listeners(&state, &widget, &conversion_properties);
Ok(widget.into())
})
Ok(widget.into())
}
#[op]
async fn op_react_create_text_instance(
fn op_react_create_text_instance(
state: Rc<RefCell<OpState>>,
text: String,
) -> anyhow::Result<JsUiWidget> {
@ -496,7 +495,7 @@ async fn op_react_create_text_instance(
let data = JsUiRequestData::CreateTextInstance { text };
let widget = match make_request_receive(&state, data).await? {
let widget = match make_request_receive(&state, data)? {
JsUiResponseData::CreateTextInstance { widget } => widget,
value @ _ => panic!("unsupported response type {:?}", value),
};
@ -512,7 +511,7 @@ fn op_react_set_properties<'a>(
state: Rc<RefCell<OpState>>,
widget: JsUiWidget,
v8_properties: HashMap<String, serde_v8::Value<'a>>,
) -> anyhow::Result<impl Future<Output=anyhow::Result<()>> + 'static> {
) -> anyhow::Result<()> {
println!("op_react_set_properties");
let properties = convert_properties(scope, v8_properties)?;
@ -530,12 +529,12 @@ fn op_react_set_properties<'a>(
println!("op_react_set_properties end");
Ok(async move {
match make_request_receive(&state, data).await? {
JsUiResponseData::Nothing => Ok(()),
value @ _ => panic!("unsupported response type {:?}", value),
}
})
match make_request_receive(&state, data)? {
JsUiResponseData::Nothing => {
Ok(())
},
value @ _ => panic!("unsupported response type {:?}", value),
}
}
#[op]
@ -579,7 +578,7 @@ fn op_react_call_event_listener(
}
#[op]
async fn op_react_set_text(
fn op_react_set_text(
state: Rc<RefCell<OpState>>,
widget: JsUiWidget,
text: String,
@ -593,14 +592,14 @@ async fn op_react_set_text(
println!("op_react_set_text end");
match make_request_receive(&state, data).await? {
match make_request_receive(&state, data)? {
JsUiResponseData::Nothing => Ok(()),
value @ _ => panic!("unsupported response type {:?}", value),
}
}
#[op]
async fn op_react_replace_container_children(
fn op_react_replace_container_children(
state: Rc<RefCell<OpState>>,
container: JsUiWidget,
new_children: Vec<JsUiWidget>,
@ -614,7 +613,7 @@ async fn op_react_replace_container_children(
println!("op_react_replace_container_children end");
match make_request_receive(&state, data).await? {
match make_request_receive(&state, data)? {
JsUiResponseData::Nothing => Ok(()),
value @ _ => panic!("unsupported response type {:?}", value),
}
@ -626,7 +625,7 @@ fn op_react_clone_instance<'a>(
state: Rc<RefCell<OpState>>,
widget_type: String,
v8_properties: HashMap<String, serde_v8::Value<'a>>,
) -> anyhow::Result<impl Future<Output=anyhow::Result<JsUiWidget>> + 'static> {
) -> anyhow::Result<JsUiWidget> {
// TODO component model
@ -643,28 +642,30 @@ fn op_react_clone_instance<'a>(
properties,
};
let widget = match make_request_receive(&state, data)? {
JsUiResponseData::CloneInstance { widget } => widget,
value @ _ => panic!("unsupported response type {:?}", value),
};
assign_event_listeners(&state, &widget, &conversion_properties);
println!("op_react_clone_instance end");
Ok(async move {
let widget = match make_request_receive(&state, data).await? {
JsUiResponseData::CloneInstance { widget } => widget,
value @ _ => panic!("unsupported response type {:?}", value),
};
assign_event_listeners(&state, &widget, &conversion_properties);
Ok(widget.into())
})
Ok(widget.into())
}
async fn make_request_receive(state: &Rc<RefCell<OpState>>, data: JsUiRequestData) -> anyhow::Result<JsUiResponseData> {
fn make_request_receive(state: &Rc<RefCell<OpState>>, data: JsUiRequestData) -> anyhow::Result<JsUiResponseData> {
let request_sender = {
state.borrow()
.borrow::<RequestSender>()
.clone()
};
request_sender.channel.send_receive(data).await?
tokio::task::block_in_place(move || {
block_on(async {
request_sender.channel.send_receive(data).await?
})
})
}
fn make_request(state: &Rc<RefCell<OpState>>, data: JsUiRequestData) -> anyhow::Result<()> {

View file

@ -224,15 +224,12 @@ impl ApplicationManager {
fn start_plugin_runtime(&mut self, data: PluginRuntimeData) {
let run_status_guard = self.run_status_holder.start_block(data.id.clone());
let handle = move || {
let _run_status_guard = run_status_guard;
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
let handle = tokio::runtime::Handle::current();
let local_set = tokio::task::LocalSet::new();
local_set.block_on(&runtime, tokio::task::unconstrained(async move {
let thread_fn = move || {
let _run_status_guard = run_status_guard;
handle.block_on(tokio::task::unconstrained(async move {
let result = start_plugin_runtime(data).await;
println!("runtime execution failed {:?}", result)
}))
@ -240,7 +237,7 @@ impl ApplicationManager {
std::thread::Builder::new()
.name("plugin-js-thread".into())
.spawn(handle)
.spawn(thread_fn)
.expect("failed to spawn plugin js thread");
}