Skip to content

Commit 6391c0c

Browse files
committed
Improve editor api
1 parent 560317f commit 6391c0c

File tree

3 files changed

+74
-107
lines changed

3 files changed

+74
-107
lines changed

frontend/wasm/src/editor_api.rs

Lines changed: 70 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,34 @@ pub struct EditorHandle {
137137
frontend_message_handler_callback: js_sys::Function,
138138
}
139139

140-
// Defined separately from the `impl` block below since this `impl` block lacks the `#[wasm_bindgen]` attribute.
141-
// Quirks in wasm-bindgen prevent functions in `#[wasm_bindgen]` `impl` blocks from being made publicly accessible from Rust.
142140
impl EditorHandle {
143-
pub fn send_frontend_message_to_js_rust_proxy(&self, message: FrontendMessage) {
144-
self.send_frontend_message_to_js(message);
141+
// Sends a FrontendMessage to JavaScript
142+
pub fn send_frontend_message_to_js(&self, mut message: FrontendMessage) {
143+
if let FrontendMessage::UpdateImageData { ref image_data } = message {
144+
let new_hash = calculate_hash(image_data);
145+
let prev_hash = IMAGE_DATA_HASH.load(Ordering::Relaxed);
146+
147+
if new_hash != prev_hash {
148+
render_image_data_to_canvases(image_data.as_slice());
149+
IMAGE_DATA_HASH.store(new_hash, Ordering::Relaxed);
150+
}
151+
return;
152+
}
153+
154+
if let FrontendMessage::UpdateDocumentLayerStructure { data_buffer } = message {
155+
message = FrontendMessage::UpdateDocumentLayerStructureJs { data_buffer: data_buffer.into() };
156+
}
157+
158+
let message_type = message.to_discriminant().local_name();
159+
160+
let serializer = serde_wasm_bindgen::Serializer::new().serialize_large_number_types_as_bigints(true);
161+
let message_data = message.serialize(&serializer).expect("Failed to serialize FrontendMessage");
162+
163+
let js_return_value = self.frontend_message_handler_callback.call2(&JsValue::null(), &JsValue::from(message_type), &message_data);
164+
165+
if let Err(error) = js_return_value {
166+
error!("While handling FrontendMessage {:?}, JavaScript threw an error:\n{:?}", message.to_discriminant().local_name(), error,)
167+
}
145168
}
146169
}
147170

@@ -179,28 +202,12 @@ impl EditorHandle {
179202
#[cfg(not(feature = "native"))]
180203
fn dispatch<T: Into<Message>>(&self, message: T) {
181204
// Process no further messages after a crash to avoid spamming the console
182-
183-
use crate::MESSAGE_BUFFER;
184205
if EDITOR_HAS_CRASHED.load(Ordering::SeqCst) {
185206
return;
186207
}
187-
188-
// Get the editor, dispatch the message, and store the `FrontendMessage` queue response
189-
let frontend_messages = EDITOR.with(|editor| {
190-
let mut guard = editor.try_lock();
191-
let Ok(Some(editor)) = guard.as_deref_mut() else {
192-
// Enqueue messages which can't be procssed currently
193-
MESSAGE_BUFFER.with_borrow_mut(|buffer| buffer.push(message.into()));
194-
return vec![];
195-
};
196-
197-
editor.handle_message(message)
208+
let _ = editor(|editor| {
209+
self.process_messages(std::iter::once(message.into()), editor);
198210
});
199-
200-
// Send each `FrontendMessage` to the JavaScript frontend
201-
for message in frontend_messages.into_iter() {
202-
self.send_frontend_message_to_js(message);
203-
}
204211
}
205212

206213
#[cfg(feature = "native")]
@@ -213,43 +220,22 @@ impl EditorHandle {
213220
crate::native_communcation::send_message_to_cef(serialized_message)
214221
}
215222

216-
// Sends a FrontendMessage to JavaScript
217-
fn send_frontend_message_to_js(&self, mut message: FrontendMessage) {
218-
// Intercept any requests to render the node graph overlay
219-
if message == FrontendMessage::RequestNativeNodeGraphRender {
220-
executor_editor_and_handle(|executor, editor, _handle| {
223+
// Messages can come from the runtime, browser, or a timed callback. This processes them in the editor and does all the side effects
224+
// Like updating the frontend and node graph ui network.
225+
fn process_messages(&self, messages: impl IntoIterator<Item = Message>, editor: &mut Editor) {
226+
// Get the editor, dispatch the message, and store the `FrontendMessage` queue response
227+
for side_effect in messages.into_iter().flat_map(|message| editor.handle_message(message)).collect::<Vec<_>>() {
228+
if side_effect == FrontendMessage::RequestNativeNodeGraphRender {
221229
if let Some(node_graph_overlay_network) = editor.generate_node_graph_overlay_network() {
222230
let compilation_request = CompilationRequest { network: node_graph_overlay_network };
223-
executor.compilation_request(compilation_request);
231+
let res = executor(|executor| executor.compilation_request(compilation_request));
232+
if let Err(_) = res {
233+
log::error!("Could not borrow executor in process_messages_in_editor");
234+
}
224235
}
225-
});
226-
return;
227-
}
228-
229-
if let FrontendMessage::UpdateImageData { ref image_data } = message {
230-
let new_hash = calculate_hash(image_data);
231-
let prev_hash = IMAGE_DATA_HASH.load(Ordering::Relaxed);
232-
233-
if new_hash != prev_hash {
234-
render_image_data_to_canvases(image_data.as_slice());
235-
IMAGE_DATA_HASH.store(new_hash, Ordering::Relaxed);
236+
} else {
237+
self.send_frontend_message_to_js(side_effect);
236238
}
237-
return;
238-
}
239-
240-
if let FrontendMessage::UpdateDocumentLayerStructure { data_buffer } = message {
241-
message = FrontendMessage::UpdateDocumentLayerStructureJs { data_buffer: data_buffer.into() };
242-
}
243-
244-
let message_type = message.to_discriminant().local_name();
245-
246-
let serializer = serde_wasm_bindgen::Serializer::new().serialize_large_number_types_as_bigints(true);
247-
let message_data = message.serialize(&serializer).expect("Failed to serialize FrontendMessage");
248-
249-
let js_return_value = self.frontend_message_handler_callback.call2(&JsValue::null(), &JsValue::from(message_type), &message_data);
250-
251-
if let Err(error) = js_return_value {
252-
error!("While handling FrontendMessage {:?}, JavaScript threw an error:\n{:?}", message.to_discriminant().local_name(), error,)
253239
}
254240
}
255241

@@ -284,16 +270,18 @@ impl EditorHandle {
284270

285271
// Poll the UI node graph
286272
#[cfg(not(feature = "native"))]
287-
executor_editor_and_handle(|executor, editor, handle| {
288-
for frontend_message in executor
289-
.poll_node_graph_ui_evaluation(editor)
290-
.into_iter()
291-
.flat_map(|runtime_response| editor.handle_message(runtime_response))
292-
{
293-
handle.send_frontend_message_to_js(frontend_message);
273+
let result = editor(|editor| {
274+
let node_graph_response = executor(|executor| executor.poll_node_graph_ui_evaluation(editor));
275+
276+
match node_graph_response {
277+
Ok(node_graph_ui_messages) => handle(|handle| handle.process_messages(node_graph_ui_messages, editor)),
278+
Err(_) => log::error!("Could not get executor in frame loop"),
294279
}
295280
});
296281

282+
if let Err(_) = result {
283+
log::error!("Could not get editor in frame loop");
284+
}
297285
if !EDITOR_HAS_CRASHED.load(Ordering::SeqCst) {
298286
handle(|handle| {
299287
// Process all messages that have been queued up
@@ -1000,64 +988,49 @@ fn set_timeout(f: &Closure<dyn FnMut()>, delay: Duration) {
1000988

1001989
/// Provides access to the `Editor` by calling the given closure with it as an argument.
1002990
#[cfg(not(feature = "native"))]
1003-
fn editor<T: Default>(callback: impl FnOnce(&mut editor::application::Editor) -> T) -> T {
991+
fn editor<T>(callback: impl FnOnce(&mut editor::application::Editor) -> T) -> Result<T, ()> {
1004992
EDITOR.with(|editor| {
1005993
let mut guard = editor.try_lock();
1006994
let Ok(Some(editor)) = guard.as_deref_mut() else {
1007-
log::error!("Failed to borrow editor");
1008-
return T::default();
995+
return Err(());
1009996
};
1010-
1011-
callback(editor)
997+
Ok(callback(editor))
1012998
})
1013999
}
10141000

10151001
#[cfg(not(feature = "native"))]
1016-
fn executor<T: Default>(callback: impl FnOnce(&mut WasmNodeGraphUIExecutor) -> T) -> T {
1002+
fn executor<T>(callback: impl FnOnce(&mut WasmNodeGraphUIExecutor) -> T) -> Result<T, ()> {
10171003
WASM_NODE_GRAPH_EXECUTOR.with(|executor| {
10181004
let mut guard = executor.try_lock();
10191005
let Ok(Some(executor)) = guard.as_deref_mut() else {
1020-
log::error!("Failed to borrow editor");
1021-
return T::default();
1006+
return Err(());
10221007
};
10231008

1024-
callback(executor)
1009+
Ok(callback(executor))
10251010
})
10261011
}
10271012

1028-
#[cfg(not(feature = "native"))]
1029-
pub(crate) fn executor_editor_and_handle(callback: impl FnOnce(&mut WasmNodeGraphUIExecutor, &mut Editor, &mut EditorHandle)) {
1030-
executor(|executor| {
1031-
handle(|editor_handle| {
1032-
editor(|editor| {
1033-
// Call the closure with the editor and its handle
1034-
callback(executor, editor, editor_handle);
1035-
})
1036-
});
1037-
})
1038-
}
1039-
1040-
/// Provides access to the `Editor` and its `EditorHandle` by calling the given closure with them as arguments.
1041-
#[cfg(not(feature = "native"))]
1042-
pub(crate) fn editor_and_handle(callback: impl FnOnce(&mut Editor, &mut EditorHandle)) {
1043-
handle(|editor_handle| {
1044-
editor(|editor| {
1045-
// Call the closure with the editor and its handle
1046-
callback(editor, editor_handle);
1047-
})
1048-
});
1049-
}
10501013
/// Provides access to the `EditorHandle` by calling the given closure with them as arguments.
10511014
pub(crate) fn handle(callback: impl FnOnce(&mut EditorHandle)) {
10521015
EDITOR_HANDLE.with(|editor_handle| {
10531016
let mut guard = editor_handle.try_lock();
10541017
let Ok(Some(editor_handle)) = guard.as_deref_mut() else {
1055-
log::error!("Failed to borrow editor handle");
1056-
return;
1018+
return log::error!("Failed to borrow handle");
10571019
};
10581020

10591021
// Call the closure with the editor and its handle
1060-
callback(editor_handle);
1022+
callback(editor_handle)
1023+
})
1024+
}
1025+
1026+
/// Provides access to the `Editor` and its `EditorHandle` by calling the given closure with them as arguments.
1027+
#[cfg(not(feature = "native"))]
1028+
pub(crate) fn editor_and_handle(callback: impl FnOnce(&mut Editor, &mut EditorHandle)) {
1029+
let _ = handle(|editor_handle| {
1030+
let _ = editor(|editor| {
1031+
// Call the closure with the editor and its handle
1032+
callback(editor, editor_handle);
1033+
});
10611034
});
10621035
}
10631036

@@ -1086,10 +1059,7 @@ async fn poll_node_graph_evaluation() {
10861059
crate::NODE_GRAPH_ERROR_DISPLAYED.store(false, Ordering::SeqCst);
10871060
}
10881061

1089-
// Send each `FrontendMessage` to the JavaScript frontend
1090-
for response in messages.into_iter().flat_map(|message| editor.handle_message(message)) {
1091-
handle.send_frontend_message_to_js(response);
1092-
}
1062+
handle.process_messages(messages, editor);
10931063

10941064
// If the editor cannot be borrowed then it has encountered a panic - we should just ignore new dispatches
10951065
});

frontend/wasm/src/lib.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub fn panic_hook(info: &panic::PanicHookInfo) {
6666
/text>"#
6767
// It's a mystery why the `/text>` tag above needs to be missing its `<`, but when it exists it prints the `<` character in the text. However this works with it removed.
6868
.to_string();
69-
handle.send_frontend_message_to_js_rust_proxy(FrontendMessage::UpdateDocumentArtwork { svg: error });
69+
handle.send_frontend_message_to_js(FrontendMessage::UpdateDocumentArtwork { svg: error });
7070
});
7171
}
7272

@@ -77,11 +77,8 @@ pub fn panic_hook(info: &panic::PanicHookInfo) {
7777

7878
log::error!("{info}");
7979

80-
EDITOR_HANDLE.with(|editor_handle| {
81-
let mut guard = editor_handle.lock();
82-
if let Ok(Some(handle)) = guard.as_deref_mut() {
83-
handle.send_frontend_message_to_js_rust_proxy(FrontendMessage::DisplayDialogPanic { panic_info: info.to_string() });
84-
}
80+
editor_api::handle(|editor_handle| {
81+
editor_handle.send_frontend_message_to_js(FrontendMessage::DisplayDialogPanic { panic_info: info.to_string() });
8582
});
8683
}
8784

frontend/wasm/src/native_communcation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub fn receive_native_message(buffer: ArrayBuffer) {
1111
Ok(messages) => {
1212
let callback = move |handle: &mut EditorHandle| {
1313
for message in messages {
14-
handle.send_frontend_message_to_js_rust_proxy(message);
14+
handle.send_frontend_message_to_js(message);
1515
}
1616
};
1717
editor_api::handle(callback);

0 commit comments

Comments
 (0)