Skip to main content

socorro_cli/models/
processed_crash.rs

1use super::StackFrame;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Serialize, Deserialize)]
5pub struct ProcessedCrash {
6    pub uuid: String,
7    #[serde(default)]
8    pub signature: Option<String>,
9    #[serde(default)]
10    pub product: Option<String>,
11    #[serde(default)]
12    pub version: Option<String>,
13    #[serde(default)]
14    pub os_name: Option<String>,
15    #[serde(default)]
16    pub os_version: Option<String>,
17
18    #[serde(default)]
19    pub crash_info: Option<CrashInfo>,
20    #[serde(default)]
21    pub moz_crash_reason: Option<String>,
22    #[serde(default)]
23    pub abort_message: Option<String>,
24
25    #[serde(default)]
26    pub android_model: Option<String>,
27    #[serde(default)]
28    pub android_version: Option<String>,
29
30    #[serde(default)]
31    pub crashing_thread: Option<usize>,
32    #[serde(default)]
33    pub threads: Option<Vec<Thread>>,
34    #[serde(default)]
35    pub json_dump: Option<serde_json::Value>,
36}
37
38#[derive(Debug, Serialize, Deserialize)]
39pub struct CrashInfo {
40    #[serde(rename = "type")]
41    pub crash_type: Option<String>,
42    pub address: Option<String>,
43    pub crashing_thread: Option<usize>,
44}
45
46#[derive(Debug, Serialize, Deserialize)]
47pub struct Thread {
48    pub thread: Option<usize>,
49    pub thread_name: Option<String>,
50    pub frames: Vec<StackFrame>,
51}
52
53#[derive(Debug, Clone)]
54pub struct ThreadSummary {
55    pub thread_index: usize,
56    pub thread_name: Option<String>,
57    pub frames: Vec<StackFrame>,
58    pub is_crashing: bool,
59}
60
61#[derive(Debug)]
62pub struct CrashSummary {
63    pub crash_id: String,
64    pub signature: String,
65    pub reason: Option<String>,
66    pub address: Option<String>,
67    pub moz_crash_reason: Option<String>,
68    pub abort_message: Option<String>,
69
70    pub product: String,
71    pub version: String,
72    pub platform: String,
73
74    pub android_version: Option<String>,
75    pub android_model: Option<String>,
76
77    pub crashing_thread_name: Option<String>,
78    pub frames: Vec<StackFrame>,
79    pub all_threads: Vec<ThreadSummary>,
80}
81
82impl ProcessedCrash {
83    pub fn to_summary(&self, depth: usize, all_threads: bool) -> CrashSummary {
84        let crashing_thread_idx = self
85            .crashing_thread
86            .or_else(|| self.crash_info.as_ref().and_then(|ci| ci.crashing_thread))
87            .or_else(|| {
88                self.json_dump.as_ref().and_then(|jd| {
89                    jd.get("crashing_thread")
90                        .and_then(|v| v.as_u64())
91                        .map(|v| v as usize)
92                })
93            });
94
95        let json_dump_threads: Option<Vec<Thread>> = self
96            .json_dump
97            .as_ref()
98            .and_then(|jd| jd.get("threads"))
99            .and_then(|t| serde_json::from_value(t.clone()).ok());
100
101        let threads_data = self.threads.as_ref().or(json_dump_threads.as_ref());
102
103        let (thread_name, frames, thread_summaries) = if let Some(threads) = threads_data {
104            let mut all_thread_summaries = Vec::new();
105
106            if all_threads {
107                for (idx, thread) in threads.iter().enumerate() {
108                    let frames: Vec<StackFrame> =
109                        thread.frames.iter().take(depth).cloned().collect();
110                    all_thread_summaries.push(ThreadSummary {
111                        thread_index: idx,
112                        thread_name: thread.thread_name.clone(),
113                        frames,
114                        is_crashing: Some(idx) == crashing_thread_idx,
115                    });
116                }
117            }
118
119            if let Some(idx) = crashing_thread_idx {
120                if let Some(thread) = threads.get(idx) {
121                    let frames: Vec<StackFrame> =
122                        thread.frames.iter().take(depth).cloned().collect();
123                    (thread.thread_name.clone(), frames, all_thread_summaries)
124                } else {
125                    (None, Vec::new(), all_thread_summaries)
126                }
127            } else {
128                (None, Vec::new(), all_thread_summaries)
129            }
130        } else {
131            (None, Vec::new(), Vec::new())
132        };
133
134        let json_dump_crash_info: Option<CrashInfo> = self
135            .json_dump
136            .as_ref()
137            .and_then(|jd| jd.get("crash_info"))
138            .and_then(|ci| serde_json::from_value(ci.clone()).ok());
139
140        let crash_info = self.crash_info.as_ref().or(json_dump_crash_info.as_ref());
141
142        CrashSummary {
143            crash_id: self.uuid.clone(),
144            signature: self
145                .signature
146                .clone()
147                .unwrap_or_else(|| "Unknown".to_string()),
148            reason: crash_info.and_then(|ci| ci.crash_type.clone()),
149            address: crash_info.and_then(|ci| ci.address.clone()),
150            moz_crash_reason: self.moz_crash_reason.clone(),
151            abort_message: self.abort_message.clone(),
152            product: self
153                .product
154                .clone()
155                .unwrap_or_else(|| "Unknown".to_string()),
156            version: self
157                .version
158                .clone()
159                .unwrap_or_else(|| "Unknown".to_string()),
160            platform: format!(
161                "{}{}",
162                self.os_name.as_deref().unwrap_or("Unknown"),
163                self.os_version
164                    .as_ref()
165                    .map(|v| format!(" {}", v))
166                    .unwrap_or_default()
167            ),
168            android_version: self.android_version.clone(),
169            android_model: self.android_model.clone(),
170            crashing_thread_name: thread_name,
171            frames,
172            all_threads: thread_summaries,
173        }
174    }
175}