Fix to send panic message to all editor instances immediately upon crash (#460)
This commit is contained in:
parent
5518384ec1
commit
a805120638
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue