libobs_wrapper\crash_handler/
mod.rs

1//! Contains a default crash handler that is attached by default to the ObsContext.
2//! By default this will handle crashes just by printing them out to console, if the `dialog-crash-handler` feature is disabled.
3//! If you want to implement your own crash handler, make sure that you do the least amount of work possible and access as few global variables as you can,
4//! as it is quite unstable if libobs has crashed.
5use std::{ffi::c_void, sync::Mutex};
6
7use lazy_static::lazy_static;
8
9#[cfg(feature = "dialog_crash_handler")]
10pub mod dialog;
11
12/// Trait for handling OBS crashes.
13/// This is called whenever OBS encounters a fatal error and crashes.
14/// Implementors can define custom behavior for crash handling,
15/// such as logging the error, showing a dialog, or sending reports.
16///
17/// **MAKE SURE** that the `handle_crash` function does the least amount of work possible,
18/// as it is called in a crash context where many resources may be unavailable.
19pub trait ObsCrashHandler: Send {
20    /// Handles an OBS crash with the given message.
21    /// YOU MUST MAKE SURE that this function does the least amount of work possible!
22    fn handle_crash(&self, message: String);
23}
24
25pub struct ConsoleCrashHandler {
26    _private: (),
27}
28
29impl Default for ConsoleCrashHandler {
30    fn default() -> Self {
31        Self::new()
32    }
33}
34
35impl ConsoleCrashHandler {
36    pub fn new() -> Self {
37        Self { _private: () }
38    }
39}
40impl ObsCrashHandler for ConsoleCrashHandler {
41    fn handle_crash(&self, message: String) {
42        #[cfg(not(feature = "logging_crash_handler"))]
43        eprintln!("OBS crashed: {}", message);
44        #[cfg(feature = "logging_crash_handler")]
45        log::error!("OBS crashed: {}", message);
46    }
47}
48
49lazy_static! {
50    /// We are using this as global variable because there can only be one obs context
51    static ref CRASH_HANDLER: Mutex<Box<dyn ObsCrashHandler>> = {
52        #[cfg(feature="dialog_crash_handler")]
53        {
54            Mutex::new(Box::new(dialog::DialogCrashHandler::new()))
55        }
56        #[cfg(not(feature="dialog_crash_handler"))]
57        {
58            Mutex::new(Box::new(ConsoleCrashHandler::new()))
59        }
60    };
61}
62
63/// # Safety
64/// This function is unsafe because it is called from C code in a crash context.
65/// You MUST ensure that the function does the least amount of work possible.
66pub(crate) unsafe extern "C" fn main_crash_handler<V>(
67    format: *const std::os::raw::c_char,
68    args: *mut V,
69    _params: *mut c_void,
70) {
71    let res = vsprintf::vsprintf(format, args);
72    if res.is_err() {
73        eprintln!("Failed to format crash handler message");
74        return;
75    }
76
77    let res = res.unwrap();
78    CRASH_HANDLER.lock().unwrap().handle_crash(res);
79}