sentry_contrib_breakpad/
transport.rs1use sentry_core::{ClientOptions, Envelope, Transport, TransportFactory};
2use std::{sync::Arc, time::Duration};
3
4#[derive(Copy, Clone)]
6pub enum CrashSendStyle {
7 SendImmediately,
11 SendNextSession,
15}
16
17pub struct BreakpadTransportFactory {
21 inner: Arc<dyn TransportFactory>,
22 style: CrashSendStyle,
23}
24
25impl BreakpadTransportFactory {
26 pub fn new(style: CrashSendStyle, transport: Arc<dyn TransportFactory>) -> Self {
27 Self {
28 style,
29 inner: transport,
30 }
31 }
32}
33
34impl TransportFactory for BreakpadTransportFactory {
35 fn create_transport(&self, options: &ClientOptions) -> Arc<dyn Transport> {
36 Arc::new(BreakpadTransport {
37 inner: self.inner.create_transport(options),
38 style: self.style,
39 })
40 }
41}
42
43struct BreakpadTransport {
44 inner: Arc<dyn Transport>,
45 style: CrashSendStyle,
46}
47
48impl BreakpadTransport {
49 fn process(&self, envelope: Envelope) -> Option<Envelope> {
50 use sentry_core::protocol as proto;
51
52 match envelope.event() {
53 Some(eve) if !eve.extra.contains_key("__breakpad_minidump_path") => Some(envelope),
55 None => Some(envelope),
56 Some(eve) => {
57 let mut event = eve.clone();
58
59 event.exception.values.clear();
62
63 let mut minidump_path = match event.extra.remove("__breakpad_minidump_path") {
64 Some(sentry_core::protocol::Value::String(s)) => std::path::PathBuf::from(s),
65 other => unreachable!(
66 "__breakpad_minidump_path should be a String, but was {:?}",
67 other
68 ),
69 };
70
71 let session_update = envelope.items().find_map(|ei| match ei {
72 proto::EnvelopeItem::SessionUpdate(su) => {
73 let mut su = su.clone();
74 su.status = proto::SessionStatus::Crashed;
75
76 Some(su)
77 }
78 _ => None,
79 });
80
81 let md = crate::shared::CrashMetadata {
82 event: Some(event),
83 session_update,
84 };
85
86 match self.style {
87 CrashSendStyle::SendImmediately => {
88 let envelope = crate::shared::assemble_envelope(md, &minidump_path);
89
90 if let Err(e) = std::fs::remove_file(&minidump_path) {
91 debug_print!(
92 "failed to remove crashdump {}: {}",
93 minidump_path.display(),
94 e
95 );
96 }
97
98 Some(envelope)
99 }
100 CrashSendStyle::SendNextSession => {
101 let serialized = md.serialize();
102
103 minidump_path.set_extension("metadata");
104 if let Err(e) = std::fs::write(&minidump_path, serialized) {
105 debug_print!(
106 "failed to write crash metadata {}: {}",
107 minidump_path.display(),
108 e
109 );
110 }
111
112 None
113 }
114 }
115 }
116 }
117 }
118}
119
120impl Transport for BreakpadTransport {
121 fn send_envelope(&self, envelope: Envelope) {
122 if let Some(envelope) = self.process(envelope) {
123 self.inner.send_envelope(envelope);
124 }
125 }
126
127 fn flush(&self, timeout: Duration) -> bool {
128 self.inner.flush(timeout)
129 }
130
131 fn shutdown(&self, timeout: Duration) -> bool {
132 self.inner.shutdown(timeout)
133 }
134}