desktop: Implement crash report dialog when a panic happens
This commit is contained in:
parent
0fd618e80a
commit
ea37d0a3ad
|
@ -0,0 +1,50 @@
|
||||||
|
name: "\U0001f4A5 Crash report"
|
||||||
|
description: File a crash report.
|
||||||
|
labels: ["bug", "panic", "desktop"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
- If you have a question about Ruffle, you can ask for help on our [Discord chat][chat].
|
||||||
|
- Also consult the [Frequently Asked Questions][faq] for common issues and questions.
|
||||||
|
- Please do your best to search for duplicate issues before filing a new issue so we can keep our issue board clean.
|
||||||
|
- Also make sure that you are using the [latest available version of Ruffle][version].
|
||||||
|
- Otherwise, fill out the information below to the best of your ability. Thank you!
|
||||||
|
|
||||||
|
[chat]: https://discord.gg/ruffle
|
||||||
|
[faq]: https://github.com/ruffle-rs/ruffle/wiki/Frequently-Asked-Questions-For-Users
|
||||||
|
[version]: https://github.com/ruffle-rs/ruffle/tags
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Describe what you were doing
|
||||||
|
description: |
|
||||||
|
Provide a clear and concise description of what you were doing when you encountered the crash.
|
||||||
|
- If there are steps to reproduce, list them here.
|
||||||
|
- If this is an issue with a specific SWF file, please provide a link to the SWF file, or you can attach the SWF by zipping it and dragging it onto the issue box.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: panic_text
|
||||||
|
attributes:
|
||||||
|
label: What does the crash message say?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
# Device information
|
||||||
|
- type: input
|
||||||
|
id: operating_system
|
||||||
|
attributes:
|
||||||
|
label: Operating system
|
||||||
|
description: Please list the OS you are using.
|
||||||
|
placeholder: Windows 10, macOS Catalina, Android 11, iOS 14, etc.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: extra_info
|
||||||
|
attributes:
|
||||||
|
label: Additional information
|
||||||
|
description: If you have any additional information for us, such as device logs or renderer info, use the field below.
|
||||||
|
validations:
|
||||||
|
required: false
|
|
@ -2999,6 +2999,16 @@ dependencies = [
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_info"
|
||||||
|
version = "3.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4750134fb6a5d49afc80777394ad5d95b04bc12068c6abb92fae8f43817270f"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.4.1"
|
version = "6.4.1"
|
||||||
|
@ -3534,8 +3544,10 @@ dependencies = [
|
||||||
"embed-resource",
|
"embed-resource",
|
||||||
"generational-arena",
|
"generational-arena",
|
||||||
"isahc",
|
"isahc",
|
||||||
|
"os_info",
|
||||||
"rfd",
|
"rfd",
|
||||||
"ruffle_core",
|
"ruffle_core",
|
||||||
|
"ruffle_render",
|
||||||
"ruffle_render_wgpu",
|
"ruffle_render_wgpu",
|
||||||
"ruffle_video_software",
|
"ruffle_video_software",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|
|
@ -11,6 +11,7 @@ version.workspace = true
|
||||||
clap = { version = "4.0.32", features = ["derive"] }
|
clap = { version = "4.0.32", features = ["derive"] }
|
||||||
cpal = "0.14.2"
|
cpal = "0.14.2"
|
||||||
ruffle_core = { path = "../core", features = ["audio", "mp3", "nellymoser"] }
|
ruffle_core = { path = "../core", features = ["audio", "mp3", "nellymoser"] }
|
||||||
|
ruffle_render = { path = "../render" }
|
||||||
ruffle_render_wgpu = { path = "../render/wgpu", features = ["clap"] }
|
ruffle_render_wgpu = { path = "../render/wgpu", features = ["clap"] }
|
||||||
ruffle_video_software = { path = "../video/software", optional = true }
|
ruffle_video_software = { path = "../video/software", optional = true }
|
||||||
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
||||||
|
@ -25,6 +26,7 @@ isahc = "1.7.2"
|
||||||
rfd = "0.10.0"
|
rfd = "0.10.0"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
bytemuck = "1.12.3"
|
bytemuck = "1.12.3"
|
||||||
|
os_info = { version = "3", default-features = false }
|
||||||
|
|
||||||
# Deliberately held back to match tracy client used by profiling crate
|
# Deliberately held back to match tracy client used by profiling crate
|
||||||
tracing-tracy = { version = "=0.10.0", optional = true }
|
tracing-tracy = { version = "=0.10.0", optional = true }
|
||||||
|
|
|
@ -24,10 +24,12 @@ use ruffle_core::{
|
||||||
config::Letterbox, events::KeyCode, tag_utils::SwfMovie, LoadBehavior, Player, PlayerBuilder,
|
config::Letterbox, events::KeyCode, tag_utils::SwfMovie, LoadBehavior, Player, PlayerBuilder,
|
||||||
PlayerEvent, StageDisplayState, StaticCallstack, ViewportDimensions,
|
PlayerEvent, StageDisplayState, StaticCallstack, ViewportDimensions,
|
||||||
};
|
};
|
||||||
|
use ruffle_render::backend::RenderBackend;
|
||||||
use ruffle_render_wgpu::backend::WgpuRenderBackend;
|
use ruffle_render_wgpu::backend::WgpuRenderBackend;
|
||||||
use ruffle_render_wgpu::clap::{GraphicsBackend, PowerPreference};
|
use ruffle_render_wgpu::clap::{GraphicsBackend, PowerPreference};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
use std::panic::PanicInfo;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
@ -43,6 +45,8 @@ use winit::window::{Fullscreen, Icon, Window, WindowBuilder};
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static CALLSTACK: RefCell<Option<StaticCallstack>> = RefCell::default();
|
static CALLSTACK: RefCell<Option<StaticCallstack>> = RefCell::default();
|
||||||
|
static RENDER_INFO: RefCell<Option<String>> = RefCell::default();
|
||||||
|
static SWF_INFO: RefCell<Option<String>> = RefCell::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tracy")]
|
#[cfg(feature = "tracy")]
|
||||||
|
@ -232,6 +236,7 @@ impl App {
|
||||||
.and_then(|segments| segments.last())
|
.and_then(|segments| segments.last())
|
||||||
.unwrap_or_else(|| movie_url.as_str());
|
.unwrap_or_else(|| movie_url.as_str());
|
||||||
let title = format!("Ruffle - {filename}");
|
let title = format!("Ruffle - {filename}");
|
||||||
|
SWF_INFO.with(|i| *i.borrow_mut() = Some(filename.to_string()));
|
||||||
|
|
||||||
let window = WindowBuilder::new()
|
let window = WindowBuilder::new()
|
||||||
.with_visible(false)
|
.with_visible(false)
|
||||||
|
@ -268,6 +273,7 @@ impl App {
|
||||||
)
|
)
|
||||||
.map_err(|e| anyhow!(e.to_string()))
|
.map_err(|e| anyhow!(e.to_string()))
|
||||||
.context("Couldn't create wgpu rendering backend")?;
|
.context("Couldn't create wgpu rendering backend")?;
|
||||||
|
RENDER_INFO.with(|i| *i.borrow_mut() = Some(renderer.debug_info().to_string()));
|
||||||
|
|
||||||
let window = Rc::new(window);
|
let window = Rc::new(window);
|
||||||
|
|
||||||
|
@ -853,7 +859,7 @@ fn init() {
|
||||||
let prev_hook = std::panic::take_hook();
|
let prev_hook = std::panic::take_hook();
|
||||||
std::panic::set_hook(Box::new(move |info| {
|
std::panic::set_hook(Box::new(move |info| {
|
||||||
prev_hook(info);
|
prev_hook(info);
|
||||||
panic_hook();
|
panic_hook(info);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let subscriber = tracing_subscriber::fmt::Subscriber::builder()
|
let subscriber = tracing_subscriber::fmt::Subscriber::builder()
|
||||||
|
@ -868,12 +874,58 @@ fn init() {
|
||||||
tracing::subscriber::set_global_default(subscriber).expect("Couldn't set up global subscriber");
|
tracing::subscriber::set_global_default(subscriber).expect("Couldn't set up global subscriber");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn panic_hook() {
|
fn panic_hook(info: &PanicInfo) {
|
||||||
CALLSTACK.with(|callstack| {
|
CALLSTACK.with(|callstack| {
|
||||||
if let Some(callstack) = &*callstack.borrow() {
|
if let Some(callstack) = &*callstack.borrow() {
|
||||||
callstack.avm2(|callstack| println!("AVM2 stack trace: {callstack}"))
|
callstack.avm2(|callstack| println!("AVM2 stack trace: {callstack}"))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// [NA] Let me just point out that PanicInfo::message() exists but isn't stable and that sucks.
|
||||||
|
let panic_text = info.to_string();
|
||||||
|
let message = if let Some(text) = panic_text.strip_prefix("panicked at '") {
|
||||||
|
let location = info.location().map(|l| l.to_string()).unwrap_or_default();
|
||||||
|
if let Some(text) = text.strip_suffix(&format!("', {location}")) {
|
||||||
|
text.trim()
|
||||||
|
} else {
|
||||||
|
text.trim()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic_text.trim()
|
||||||
|
};
|
||||||
|
if rfd::MessageDialog::new()
|
||||||
|
.set_level(rfd::MessageLevel::Error)
|
||||||
|
.set_title("Ruffle")
|
||||||
|
.set_description(&format!(
|
||||||
|
"Ruffle has encountered a fatal error, this is a bug.\n\n\
|
||||||
|
{message}\n\n\
|
||||||
|
Please report this to us so that we can fix it. Thank you!\n\
|
||||||
|
Pressing Yes will open a browser window."
|
||||||
|
))
|
||||||
|
.set_buttons(rfd::MessageButtons::YesNo)
|
||||||
|
.show()
|
||||||
|
{
|
||||||
|
let mut params = vec![];
|
||||||
|
params.push(("panic_text", info.to_string()));
|
||||||
|
params.push(("operating_system", os_info::get().to_string()));
|
||||||
|
let mut extra_info = vec![];
|
||||||
|
RENDER_INFO.with(|i| {
|
||||||
|
if let Some(render_info) = i.take() {
|
||||||
|
extra_info.push(render_info);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
SWF_INFO.with(|i| {
|
||||||
|
if let Some(swf_name) = i.take() {
|
||||||
|
extra_info.push(format!("SWF: {swf_name}"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if !extra_info.is_empty() {
|
||||||
|
params.push(("extra_info", extra_info.join("\n")));
|
||||||
|
}
|
||||||
|
if let Ok(url) = Url::parse_with_params("https://github.com/ruffle-rs/ruffle/issues/new?assignees=&labels=bug&template=crash_report.yml", ¶ms) {
|
||||||
|
let _ = webbrowser::open(url.as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shutdown() {
|
fn shutdown() {
|
||||||
|
|
Loading…
Reference in New Issue