use std::fmt;
use std::path::Path;
#[cfg(unix)]
mod native {
#![allow(warnings, clippy::all)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
pub type Transport = fn(envelope: &[u8]);
#[cfg(unix)]
unsafe extern "C" fn transport_proxy(
envelope: *const native::sentry_envelope_s,
tx_pointer: *mut std::ffi::c_void,
) {
if envelope.is_null() || tx_pointer.is_null() {
return;
}
let mut len = 0;
let buf = native::sentry_envelope_serialize(envelope, &mut len);
if !buf.is_null() && len > 0 {
let transport: Transport = std::mem::transmute(tx_pointer);
transport(std::slice::from_raw_parts(buf as *const u8, len));
}
native::sentry_free(buf as _);
}
#[derive(Default)]
#[cfg_attr(not(unix), allow(dead_code))]
pub struct CrashHandler<'a> {
dsn: &'a str,
database: &'a str,
transport: Option<Transport>,
release: Option<&'a str>,
environment: Option<&'a str>,
}
impl<'a> fmt::Debug for CrashHandler<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let transport = match self.transport {
Some(_) => "Some(fn)",
None => "None",
};
f.debug_struct("CrashHandler")
.field("dsn", &self.dsn)
.field("database", &self.database)
.field("transport", &format_args!("{transport}"))
.field("release", &self.release)
.field("environment", &self.environment)
.finish()
}
}
impl<'a> CrashHandler<'a> {
pub fn new(dsn: &'a str, database: &'a Path) -> Self {
Self {
dsn,
database: database.to_str().unwrap(),
transport: None,
release: None,
environment: None,
}
}
pub fn transport(&mut self, transport: Transport) -> &mut Self {
self.transport = Some(transport);
self
}
pub fn release(&mut self, release: Option<&'a str>) -> &mut Self {
self.release = release;
self
}
pub fn environment(&mut self, environment: Option<&'a str>) -> &mut Self {
self.environment = environment;
self
}
#[cfg(unix)]
pub fn install(&self) {
use std::ffi::CString;
unsafe {
let options = native::sentry_options_new();
let dsn_cstr = CString::new(self.dsn).unwrap();
native::sentry_options_set_dsn(options, dsn_cstr.as_ptr());
let db_cstr = CString::new(self.database).unwrap();
native::sentry_options_set_database_path(options, db_cstr.as_ptr());
if let Some(release) = self.release {
let release_cstr = CString::new(release).unwrap();
native::sentry_options_set_release(options, release_cstr.as_ptr());
}
if let Some(environment) = self.environment {
let env_cstr = CString::new(environment).unwrap();
native::sentry_options_set_environment(options, env_cstr.as_ptr());
}
if let Some(f) = self.transport {
let tx = native::sentry_new_function_transport(Some(transport_proxy), f as _);
native::sentry_options_set_transport(options, tx);
}
native::sentry_init(options);
}
}
#[cfg(not(unix))]
pub fn install(&self) {
unimplemented!("crash handler not supported on this platform");
}
}