Rework wasm initialization and reduce global state (#379)

* wasm: do the async initialization only once

This allows the rest of the app to access wasm synchronously.

This allows removing of a global.

* provide the wasm via vue provide/inject.

There's still code directly accessing the wasm. That will be changed later.

* MenuBarInput: use injected wasm instead of the global instance

* Let the App handle event listeners

* move stateful modules into state/

* state/fullscreen: create per instance

* App: load the initial document list on mount.
This got lost a few commits ago. Now it's back.

* state/dialog: create per instance

* util/input: remove dependency on global dialog instance

* state/documents: create per instance

* reponse-handler: move into EditorWasm

* comingSoon: move into dialog

* wasm: allow instantiating multiple editors

* input handlers: do not look at canvases outside the mounted App

* input: listen on the container instead of the window when possible

* - removed proxy from wasm-loader
- integrated with js-dispatcher
- state functions to classes
- integrated some upstream changes

* fix errors caused by merge

* Getting closer:
- added global state to track all instances
- fix fullscreen close trigger
- wasm-loader is statefull
- panic across instanes

* - fix outline while using editor
- removed circular import rule
- added editorInstance to js message constructor

* - changed input handler to a class
- still need a better way of handeling it in App.vue

* - fixed single instance of inputManager to weakmap

* - fix no-explicit-any in a few places
- removed global state from input.ts

* simplified two long lines

* removed global state

* removed $data from App

* add mut self to functions in api.rs

* Update Workspace.vue

remove outdated import

* fixed missing import

* Changes throughout code review; note this causes some bugs to be fixed in a later commit

* PR review round 1

* - fix coming soon bugs
- changed folder structure

* moved declaration to .d.ts

* - changed from classes to functions
- moved decs back to app.vue

* removed need to export js function to rust

* changed folder structure

* fixed indentation breaking multiline strings

* Fix eslint rule to whitelist @/../

* Simplify strip-indents implementation

* replace type assertions with better annotations or proper runtime checks

* Small tweaks and code rearranging improvements after second code review pass

* maybe fix mouse events

* Add back preventDefault for mouse scroll

* code review round 2

* Comment improvements

* -removed runtime checks
- fixed layers not showing

* - extened proxy to cover classes
- stopped multiple panics from logging
- Stop wasm-bindgen from mut ref counting our struct

* cleaned up messageConstructors exports

* Fix input and fullscreen regressions

Co-authored-by: Max Fisher <maxmfishernj@gmail.com>
Co-authored-by: mfish33 <32677537+mfish33@users.noreply.github.com>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Christian Authmann 2021-12-20 07:37:19 +01:00 committed by Keavon Chambers
parent 6d82672a95
commit 5ec8aaa31d
39 changed files with 1524 additions and 1412 deletions

View file

@ -3,17 +3,15 @@ mod helpers;
pub mod logging;
pub mod type_translators;
use editor::{message_prelude::*, Editor};
use editor::message_prelude::FrontendMessage;
use logging::WasmLog;
use std::cell::RefCell;
use std::panic;
use std::sync::atomic::AtomicBool;
use wasm_bindgen::prelude::*;
// Set up the persistent editor backend state (the thread_local macro provides a way to initialize static variables with non-constant functions)
thread_local! { pub static EDITOR_STATE: RefCell<Editor> = RefCell::new(Editor::new()); }
// Set up the persistent editor backend state
static LOGGER: WasmLog = WasmLog;
static EDITOR_HAS_CRASHED: AtomicBool = AtomicBool::new(false);
thread_local! { pub static EDITOR_HAS_CRASHED: RefCell<Option<FrontendMessage>> = RefCell::new(None); }
// Initialize the backend
#[wasm_bindgen(start)]
@ -30,44 +28,5 @@ fn panic_hook(info: &panic::PanicInfo) {
let title = "The editor crashed — sorry about that".to_string();
let description = "An internal error occurred. Reload the editor to continue. Please report this by filing an issue on GitHub.".to_string();
handle_response(FrontendMessage::DisplayPanic { panic_info, title, description });
EDITOR_HAS_CRASHED.store(true, std::sync::atomic::Ordering::SeqCst);
}
// Sends a message to the dispatcher in the Editor Backend
fn dispatch<T: Into<Message>>(message: T) {
// Process no further messages after a crash to avoid spamming the console
if EDITOR_HAS_CRASHED.load(std::sync::atomic::Ordering::SeqCst) {
return;
}
// Dispatch the message and receive a vector of FrontendMessage responses
let responses = EDITOR_STATE.with(|state| state.try_borrow_mut().ok().map(|mut state| state.handle_message(message.into())));
for response in responses.unwrap_or_default().into_iter() {
// Send each FrontendMessage to the JavaScript frontend
handle_response(response);
}
}
// Sends a FrontendMessage to JavaScript
fn handle_response(message: FrontendMessage) {
let message_type = message.to_discriminant().local_name();
let message_data = JsValue::from_serde(&message).expect("Failed to serialize FrontendMessage");
let js_return_value = handleJsMessage(message_type, message_data);
if let Err(error) = js_return_value {
log::error!(
"While handling FrontendMessage \"{:?}\", JavaScript threw an error: {:?}",
message.to_discriminant().local_name(),
error,
)
}
}
// The JavaScript function to call into with each FrontendMessage
#[wasm_bindgen(module = "/../src/utilities/js-message-dispatcher-binding.ts")]
extern "C" {
#[wasm_bindgen(catch)]
fn handleJsMessage(responseType: String, responseData: JsValue) -> Result<(), JsValue>;
EDITOR_HAS_CRASHED.with(|crash_status| crash_status.borrow_mut().replace(FrontendMessage::DisplayPanic { panic_info, title, description }));
}