Merge: recover a damaged catalog, and capture a crash locally

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-30 13:45:18 +02:00
co-authored by Claude Opus 5
15 changed files with 1954 additions and 14 deletions
+16 -3
View File
@@ -39,9 +39,18 @@ fn android_main(app: slint::android::AndroidApp) {
// worker thread that panics is invisible: the process survives, the
// channel it was writing to closes, and the UI reports only that
// something "failed unexpectedly" with no way to find out what.
std::panic::set_hook(Box::new(|info| {
log::error!("panic: {info}");
}));
//
// This used to be one `log::error!` of the raw panic, which had two
// problems: logcat is a ring buffer that is gone by the time a user
// reports anything, and the raw message can carry a document URI naming
// their library or a credential a library interpolated into an error
// (NFR-SEC-2). `dr_plat::crash` writes a redacted record to disk and logs
// the redacted form. Nothing uploads it.
//
// Before `set_state_dir` on purpose: the hook resolves the directory when
// it fires, so installing it first covers the startup below rather than
// leaving it uncovered.
dr_plat::crash::install(env!("CARGO_PKG_VERSION"));
log::info!("DarkRoom v{}", env!("CARGO_PKG_VERSION"));
@@ -54,6 +63,10 @@ fn android_main(app: slint::android::AndroidApp) {
match app.internal_data_path() {
Some(dir) => {
log::info!("data dir: {}", dir.display());
// Crash records go beside the account data rather than under it:
// both are app-private and neither is a cache, which is the whole
// distinction that matters here (see `dr_plat::crash::state_dir`).
dr_plat::crash::set_state_dir(dir.join("state"));
dr_sync::account::set_data_dir(dir);
}
None => log::error!("no internal data path; settings will not persist"),