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.
// It serves as a thin wrapper over the editor backend API that relies
// on the dispatcher messaging system and more complex Rust data types.
use std::cell::Cell;
use std::sync::atomic::Ordering;
use crate::helpers::Error;
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
// an issue when rust calls into JS which calls back to rust in the same call stack.
#[wasm_bindgen]
#[derive(Clone)]
pub struct JsEditorHandle {
editor_id: u64,
instance_received_crashed: Cell<bool>,
handle_response: js_sys::Function,
}
@ -38,23 +37,15 @@ impl JsEditorHandle {
pub fn new(handle_response: js_sys::Function) -> Self {
let editor_id = generate_uuid();
let editor = Editor::new();
EDITOR_INSTANCES.with(|instances| instances.borrow_mut().insert(editor_id, editor));
JsEditorHandle {
editor_id,
instance_received_crashed: Cell::new(false),
handle_response,
}
let editor_handle = JsEditorHandle { editor_id, handle_response };
EDITOR_INSTANCES.with(|instances| instances.borrow_mut().insert(editor_id, (editor, editor_handle.clone())));
editor_handle
}
// Sends a message to the dispatcher in the Editor Backend
fn dispatch<T: Into<Message>>(&self, message: T) {
// 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 let Some(message) = possible_crash_message {
if !self.instance_received_crashed.get() {
self.handle_response(message);
self.instance_received_crashed.set(true);
}
if EDITOR_HAS_CRASHED.load(Ordering::SeqCst) {
return;
}
@ -63,6 +54,7 @@ impl JsEditorHandle {
.borrow_mut()
.get_mut(&self.editor_id)
.expect("EDITOR_INSTANCES does not contain the current editor_id")
.0
.handle_message(message.into())
});
for response in responses.into_iter() {
@ -94,9 +86,8 @@ impl JsEditorHandle {
// backend from the web frontend.
// ========================================================================
pub fn has_crashed(&self) -> JsValue {
let has_crashed = EDITOR_HAS_CRASHED.with(|crash_state| crash_state.borrow().is_some());
has_crashed.into()
pub fn has_crashed(&self) -> bool {
EDITOR_HAS_CRASHED.load(Ordering::SeqCst)
}
/// 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 {
fn drop(&mut self) {
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::collections::HashMap;
use std::panic;
use std::sync::atomic::AtomicBool;
use wasm_bindgen::prelude::*;
// Set up the persistent editor backend state
static LOGGER: WasmLog = WasmLog;
thread_local! {
pub static EDITOR_HAS_CRASHED: RefCell<Option<FrontendMessage>> = RefCell::new(None);
pub static EDITOR_INSTANCES: RefCell<HashMap<u64, editor::Editor>> = RefCell::new(HashMap::new());
pub static EDITOR_INSTANCES: RefCell<HashMap<u64, (editor::Editor, api::JsEditorHandle)>> = RefCell::new(HashMap::new());
}
pub static EDITOR_HAS_CRASHED: AtomicBool = AtomicBool::new(false);
// Initialize the backend
#[wasm_bindgen(start)]
pub fn init() {
@ -31,5 +33,13 @@ fn panic_hook(info: &panic::PanicInfo) {
let panic_info = info.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();
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(),
})
})
});
}