fix(windows): move crash dumps into logs dir so they get exported in the zip, closes #3263 (#3426)

![image](https://github.com/firezone/firezone/assets/13400041/0fffa284-4c37-4b35-a0cf-841442246c66)


![image](https://github.com/firezone/firezone/assets/13400041/2d275cba-5d1f-4289-9214-05804f4477c6)

Screenshots taken on 33737b3a38f7
I also refactored some of the related code.
This commit is contained in:
Reactor Scram
2024-01-29 13:02:16 -06:00
committed by GitHub
parent 0a01d6c03f
commit 3d8ed7f10e
4 changed files with 30 additions and 28 deletions

View File

@@ -50,10 +50,6 @@ pub(crate) struct GuiParams {
inject_faults: bool,
}
/// Newtype for our per-user directory in AppData, e.g.
/// `C:/Users/$USER/AppData/Local/dev.firezone.client`
pub(crate) struct AppLocalDataDir(std::path::PathBuf);
// Hides Powershell's console on Windows
// <https://stackoverflow.com/questions/59692146/is-it-possible-to-use-the-standard-library-to-spawn-a-process-without-showing-th#60958956>
const CREATE_NO_WINDOW: u32 = 0x08000000;

View File

@@ -4,9 +4,8 @@
//!
//! TODO: Capture crash dumps on panic.
use crate::client::BUNDLE_ID;
use crate::client::settings::app_local_data_dir;
use anyhow::{anyhow, bail, Context};
use known_folders::{get_known_folder_path, KnownFolder};
use std::{fs::File, io::Write, path::PathBuf};
const SOCKET_NAME: &str = "dev.firezone.client.crash_handler";
@@ -104,10 +103,10 @@ impl minidumper::ServerHandler for Handler {
/// Called when a crash has been received and a backing file needs to be
/// created to store it.
fn create_minidump_file(&self) -> Result<(File, PathBuf), std::io::Error> {
let dump_path = get_known_folder_path(KnownFolder::ProgramData)
.expect("should be able to find C:/ProgramData")
.join(BUNDLE_ID)
.join("dumps")
let dump_path = app_local_data_dir()
.expect("app_local_data_dir() failed")
.join("data")
.join("logs")
.join("last_crash.dmp");
if let Some(dir) = dump_path.parent() {

View File

@@ -3,12 +3,12 @@
// TODO: `git grep` for unwraps before 1.0, especially this gui module
use crate::client::{self, deep_link, network_changes, AppLocalDataDir, BUNDLE_ID};
use crate::client::{self, deep_link, network_changes, BUNDLE_ID};
use anyhow::{anyhow, bail, Context, Result};
use arc_swap::ArcSwap;
use client::{
about, logging,
settings::{self, AdvancedSettings},
settings::{self, app_local_data_dir, AdvancedSettings},
};
use connlib_client_shared::{file_logger, ResourceDescription};
use connlib_shared::messages::ResourceId;
@@ -29,14 +29,6 @@ const MAX_PARTITION_TIME: Duration = Duration::from_secs(60 * 60 * 24 * 30);
pub(crate) type CtlrTx = mpsc::Sender<ControllerRequest>;
// TODO: Move out of GUI module, shouldn't be here
pub(crate) fn app_local_data_dir() -> Result<AppLocalDataDir> {
let path = known_folders::get_known_folder_path(known_folders::KnownFolder::LocalAppData)
.context("should be able to ask Windows where AppData/Local is")?
.join(BUNDLE_ID);
Ok(AppLocalDataDir(path))
}
/// All managed state that we might need to access from odd places like Tauri commands.
///
/// Note that this never gets Dropped because of
@@ -63,7 +55,9 @@ impl Managed {
/// Runs the Tauri GUI and returns on exit or unrecoverable error
pub(crate) fn run(params: client::GuiParams) -> Result<()> {
// Change to data dir so the file logger will write there and not in System32 if we're launching from an app link
let cwd = app_local_data_dir()?.0.join("data");
let cwd = app_local_data_dir()
.ok_or_else(|| anyhow!("app_local_data_dir() failed"))?
.join("data");
std::fs::create_dir_all(&cwd)?;
std::env::set_current_dir(&cwd)?;

View File

@@ -1,13 +1,24 @@
//! Everything related to the Settings window, including
//! advanced settings and code for manipulating diagnostic logs.
use crate::client::gui::{self, ControllerRequest, Managed};
use anyhow::Result;
use crate::client::gui::{ControllerRequest, Managed};
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::{path::PathBuf, result::Result as StdResult, time::Duration};
use std::{path::PathBuf, time::Duration};
use tokio::sync::oneshot;
use url::Url;
/// Returns e.g. `C:/Users/User/AppData/Local/dev.firezone.client
///
/// This is where we can save config, logs, crash dumps, etc.
/// It's per-user and doesn't roam across different PCs in the same domain.
/// It's read-write for non-elevated processes.
pub(crate) fn app_local_data_dir() -> Option<PathBuf> {
let path = known_folders::get_known_folder_path(known_folders::KnownFolder::LocalAppData)?
.join(crate::client::BUNDLE_ID);
Some(path)
}
#[derive(Clone, Deserialize, Serialize)]
pub(crate) struct AdvancedSettings {
pub auth_base_url: Url,
@@ -43,7 +54,9 @@ struct DirAndPath {
}
fn advanced_settings_path() -> Result<DirAndPath> {
let dir = gui::app_local_data_dir()?.0.join("config");
let dir = app_local_data_dir()
.ok_or_else(|| anyhow!("app_local_data_dir() failed"))?
.join("config");
let path = dir.join("advanced_settings.json");
Ok(DirAndPath { dir, path })
}
@@ -52,7 +65,7 @@ fn advanced_settings_path() -> Result<DirAndPath> {
pub(crate) async fn apply_advanced_settings(
managed: tauri::State<'_, Managed>,
settings: AdvancedSettings,
) -> StdResult<(), String> {
) -> Result<(), String> {
apply_advanced_settings_inner(managed.inner(), &settings)
.await
.map_err(|e| e.to_string())
@@ -61,7 +74,7 @@ pub(crate) async fn apply_advanced_settings(
#[tauri::command]
pub(crate) async fn reset_advanced_settings(
managed: tauri::State<'_, Managed>,
) -> StdResult<AdvancedSettings, String> {
) -> Result<AdvancedSettings, String> {
let settings = AdvancedSettings::default();
apply_advanced_settings_inner(managed.inner(), &settings)
@@ -74,7 +87,7 @@ pub(crate) async fn reset_advanced_settings(
#[tauri::command]
pub(crate) async fn get_advanced_settings(
managed: tauri::State<'_, Managed>,
) -> StdResult<AdvancedSettings, String> {
) -> Result<AdvancedSettings, String> {
let (tx, rx) = oneshot::channel();
if let Err(e) = managed
.ctlr_tx