Fix to send panic message to all editor instances immediately upon crash (#460)

This commit is contained in:
mfish33 2022-01-03 13:15:43 -08:00 committed by Keavon Chambers
parent 5518384ec1
commit a805120638
2 changed files with 30 additions and 21 deletions

View File

@ -1,8 +1,7 @@
// This file is where functions are defined to be called directly from JS. // This file is where functions are defined to be called directly from JS.
// It serves as a thin wrapper over the editor backend API that relies // It serves as a thin wrapper over the editor backend API that relies
// on the dispatcher messaging system and more complex Rust data types. // on the dispatcher messaging system and more complex Rust data types.
use std::sync::atomic::Ordering;
use std::cell::Cell;
use crate::helpers::Error; use crate::helpers::Error;
use crate::type_translators::{translate_blend_mode, translate_key, translate_tool_type, translate_view_mode}; use crate::type_translators::{translate_blend_mode, translate_key, translate_tool_type, translate_view_mode};
@ -25,9 +24,9 @@ use wasm_bindgen::prelude::*;
// we must make all methods take a non mutable reference to self. Not doing this creates // we must make all methods take a non mutable reference to self. Not doing this creates
// an issue when rust calls into JS which calls back to rust in the same call stack. // an issue when rust calls into JS which calls back to rust in the same call stack.
#[wasm_bindgen] #[wasm_bindgen]
#[derive(Clone)]
pub struct JsEditorHandle { pub struct JsEditorHandle {
editor_id: u64, editor_id: u64,
instance_received_crashed: Cell<bool>,
handle_response: js_sys::Function, handle_response: js_sys::Function,
} }
@ -38,23 +37,15 @@ impl JsEditorHandle {
pub fn new(handle_response: js_sys::Function) -> Self { pub fn new(handle_response: js_sys::Function) -> Self {
let editor_id = generate_uuid(); let editor_id = generate_uuid();
let editor = Editor::new(); let editor = Editor::new();
EDITOR_INSTANCES.with(|instances| instances.borrow_mut().insert(editor_id, editor)); let editor_handle = JsEditorHandle { editor_id, handle_response };
JsEditorHandle { EDITOR_INSTANCES.with(|instances| instances.borrow_mut().insert(editor_id, (editor, editor_handle.clone())));
editor_id, editor_handle
instance_received_crashed: Cell::new(false),
handle_response,
}
} }
// Sends a message to the dispatcher in the Editor Backend // Sends a message to the dispatcher in the Editor Backend
fn dispatch<T: Into<Message>>(&self, message: T) { fn dispatch<T: Into<Message>>(&self, message: T) {
// Process no further messages after a crash to avoid spamming the console // Process no further messages after a crash to avoid spamming the console
let possible_crash_message = EDITOR_HAS_CRASHED.with(|crash_state| crash_state.borrow().clone()); if EDITOR_HAS_CRASHED.load(Ordering::SeqCst) {
if let Some(message) = possible_crash_message {
if !self.instance_received_crashed.get() {
self.handle_response(message);
self.instance_received_crashed.set(true);
}
return; return;
} }
@ -63,6 +54,7 @@ impl JsEditorHandle {
.borrow_mut() .borrow_mut()
.get_mut(&self.editor_id) .get_mut(&self.editor_id)
.expect("EDITOR_INSTANCES does not contain the current editor_id") .expect("EDITOR_INSTANCES does not contain the current editor_id")
.0
.handle_message(message.into()) .handle_message(message.into())
}); });
for response in responses.into_iter() { for response in responses.into_iter() {
@ -94,9 +86,8 @@ impl JsEditorHandle {
// backend from the web frontend. // backend from the web frontend.
// ======================================================================== // ========================================================================
pub fn has_crashed(&self) -> JsValue { pub fn has_crashed(&self) -> bool {
let has_crashed = EDITOR_HAS_CRASHED.with(|crash_state| crash_state.borrow().is_some()); EDITOR_HAS_CRASHED.load(Ordering::SeqCst)
has_crashed.into()
} }
/// Modify the currently selected tool in the document state store /// Modify the currently selected tool in the document state store
@ -514,6 +505,14 @@ impl JsEditorHandle {
} }
} }
// Needed to make JsEditorHandle functions pub to rust. Do not fully
// understand reason but has to do with #[wasm_bindgen] procedural macro.
impl JsEditorHandle {
pub fn handle_response_rust_proxy(&self, message: FrontendMessage) {
self.handle_response(message);
}
}
impl Drop for JsEditorHandle { impl Drop for JsEditorHandle {
fn drop(&mut self) { fn drop(&mut self) {
EDITOR_INSTANCES.with(|instances| instances.borrow_mut().remove(&self.editor_id)); EDITOR_INSTANCES.with(|instances| instances.borrow_mut().remove(&self.editor_id));

View File

@ -8,15 +8,17 @@ use logging::WasmLog;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::panic; use std::panic;
use std::sync::atomic::AtomicBool;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
// Set up the persistent editor backend state // Set up the persistent editor backend state
static LOGGER: WasmLog = WasmLog; static LOGGER: WasmLog = WasmLog;
thread_local! { thread_local! {
pub static EDITOR_HAS_CRASHED: RefCell<Option<FrontendMessage>> = RefCell::new(None); pub static EDITOR_INSTANCES: RefCell<HashMap<u64, (editor::Editor, api::JsEditorHandle)>> = RefCell::new(HashMap::new());
pub static EDITOR_INSTANCES: RefCell<HashMap<u64, editor::Editor>> = RefCell::new(HashMap::new());
} }
pub static EDITOR_HAS_CRASHED: AtomicBool = AtomicBool::new(false);
// Initialize the backend // Initialize the backend
#[wasm_bindgen(start)] #[wasm_bindgen(start)]
pub fn init() { pub fn init() {
@ -31,5 +33,13 @@ fn panic_hook(info: &panic::PanicInfo) {
let panic_info = info.to_string(); let panic_info = info.to_string();
let title = "The editor crashed — sorry about that".to_string(); 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(); let description = "An internal error occurred. Reload the editor to continue. Please report this by filing an issue on GitHub.".to_string();
EDITOR_HAS_CRASHED.with(|crash_status| crash_status.borrow_mut().replace(FrontendMessage::DisplayPanic { panic_info, title, description })); EDITOR_INSTANCES.with(|instances| {
instances.borrow_mut().values_mut().for_each(|instance| {
instance.1.handle_response_rust_proxy(FrontendMessage::DisplayPanic {
panic_info: panic_info.clone(),
title: title.clone(),
description: description.clone(),
})
})
});
} }