1#![allow(unused_imports)]
7
8use anyhow::Result;
9
10fn crash_log_dir() -> std::path::PathBuf {
12 let home = std::env::var_os("HOME")
15 .map(std::path::PathBuf::from)
16 .unwrap_or_else(|| std::path::PathBuf::from("/tmp"));
17 home.join(".futu-opend-rs").join("crashes")
18}
19
20pub fn write_crash_log_file(info: &std::panic::PanicHookInfo<'_>) {
25 let dir = crash_log_dir();
26 let _ = std::fs::create_dir_all(&dir);
27
28 let now_secs = std::time::SystemTime::now()
33 .duration_since(std::time::UNIX_EPOCH)
34 .map(|d| d.as_secs())
35 .unwrap_or(0);
36 let path = dir.join(format!("crash-{now_secs}.log"));
37
38 let location = info
39 .location()
40 .map(|l| format!("{}:{}", l.file(), l.line()))
41 .unwrap_or_else(|| "<unknown>".to_string());
42 let payload = info
43 .payload()
44 .downcast_ref::<&str>()
45 .copied()
46 .or_else(|| info.payload().downcast_ref::<String>().map(|s| s.as_str()))
47 .unwrap_or("<non-string panic payload>");
48 let thread = std::thread::current()
49 .name()
50 .unwrap_or("<unnamed>")
51 .to_string();
52 let backtrace = std::backtrace::Backtrace::force_capture();
57
58 let body = format!(
59 "v1.4.97 P1-D-D crash report\n\
60 daemon_version: {}\n\
61 unix_timestamp: {}\n\
62 os: {}\n\
63 arch: {}\n\
64 thread: {}\n\
65 location: {}\n\
66 payload: {}\n\
67 backtrace:\n{}\n",
68 env!("CARGO_PKG_VERSION"),
69 now_secs,
70 std::env::consts::OS,
71 std::env::consts::ARCH,
72 thread,
73 location,
74 payload,
75 backtrace,
76 );
77 let _ = std::fs::write(&path, body);
78}
79
80pub fn warn_if_previous_crash() {
84 let dir = crash_log_dir();
85 let Ok(entries) = std::fs::read_dir(&dir) else {
86 return;
87 };
88 let mut latest: Option<(std::time::SystemTime, std::path::PathBuf)> = None;
90 for entry in entries.flatten() {
91 let path = entry.path();
92 if !path
93 .file_name()
94 .and_then(|s| s.to_str())
95 .is_some_and(|s| s.starts_with("crash-") && s.ends_with(".log"))
96 {
97 continue;
98 }
99 let Ok(meta) = entry.metadata() else { continue };
100 let Ok(mtime) = meta.modified() else { continue };
101 if latest.as_ref().is_none_or(|(t, _)| mtime > *t) {
102 latest = Some((mtime, path));
103 }
104 }
105 if let Some((_, path)) = latest {
106 eprintln!(
108 "⚠️ v1.4.97 P1-D-D: previous crash log detected at {}",
109 path.display()
110 );
111 eprintln!(" inspect for last-known panic payload + backtrace.");
112 }
113}