chore(gui-client): delete unused file (#9152)

This must be a left-over from when we moved some of the GUI client
modules around.
This commit is contained in:
Thomas Eizinger
2025-05-15 21:51:04 +10:00
committed by GitHub
parent 7f4b20ab7f
commit b6d8657cb2

View File

@@ -1,281 +0,0 @@
use anyhow::{Context as _, Result, bail};
use clap::{Args, Parser};
use controller::Failure;
use firezone_telemetry::Telemetry;
use settings::AdvancedSettings;
use tracing::instrument;
use tracing_subscriber::EnvFilter;
mod about;
mod auth;
mod controller;
mod debug_commands;
mod deep_link;
mod elevation;
mod gui;
mod ipc;
mod logging;
mod settings;
mod updates;
mod welcome;
/// The program's entry point, equivalent to `main`
#[instrument(skip_all)]
pub(crate) fn run() -> Result<()> {
let cli = Cli::parse();
// TODO: Remove, this is only needed for Portal connections and the GUI process doesn't connect to the Portal. Unless it's also needed for update checks.
rustls::crypto::ring::default_provider()
.install_default()
.expect("Calling `install_default` only once per process should always succeed");
match cli.command {
None => {
if cli.no_deep_links {
return run_gui(cli);
}
match elevation::gui_check() {
// Our elevation is correct (not elevated), just run the GUI
Ok(true) => run_gui(cli),
Ok(false) => bail!("The GUI should run as a normal user, not elevated"),
#[cfg(target_os = "linux")] // Windows/MacOS elevation check never fails.
Err(error) => {
show_error_dialog(&error.user_friendly_msg())?;
Err(error.into())
}
}
}
Some(Cmd::Debug { command }) => debug_commands::run(command),
// If we already tried to elevate ourselves, don't try again
Some(Cmd::Elevated) => run_gui(cli),
Some(Cmd::OpenDeepLink(deep_link)) => {
let rt = tokio::runtime::Runtime::new()?;
if let Err(error) = rt.block_on(deep_link::open(&deep_link.url)) {
tracing::error!("Error in `OpenDeepLink`: {error:#}");
}
Ok(())
}
Some(Cmd::SmokeTest) => {
// Can't check elevation here because the Windows CI is always elevated
let settings = settings::load_advanced_settings().unwrap_or_default();
let mut telemetry = Telemetry::default();
telemetry.start(
settings.api_url.as_ref(),
crate::RELEASE,
firezone_telemetry::GUI_DSN,
);
// Don't fix the log filter for smoke tests
let logging::Handles {
logger: _logger,
reloader,
} = start_logging(&settings.log_filter)?;
let result = gui::run(cli, settings, reloader, telemetry);
if let Err(error) = &result {
// In smoke-test mode, don't show the dialog, since it might be running
// unattended in CI and the dialog would hang forever
// Because of <https://github.com/firezone/firezone/issues/3567>,
// errors returned from `gui::run` may not be logged correctly
tracing::error!("{error:#}");
}
Ok(result?)
}
}
}
/// `gui::run` but wrapped in `anyhow::Result`
///
/// Automatically logs or shows error dialogs for important user-actionable errors
// Can't `instrument` this because logging isn't running when we enter it.
fn run_gui(cli: Cli) -> Result<()> {
let mut settings = settings::load_advanced_settings().unwrap_or_default();
let mut telemetry = Telemetry::default();
// In the future telemetry will be opt-in per organization, that's why this isn't just at the top of `main`
telemetry.start(
settings.api_url.as_ref(),
crate::RELEASE,
firezone_telemetry::GUI_DSN,
);
// Get the device ID before starting Tokio, so that all the worker threads will inherit the correct scope.
// Technically this means we can fail to get the device ID on a newly-installed system, since the IPC service may not have fully started up when the GUI process reaches this point, but in practice it's unlikely.
if let Ok(id) = firezone_headless_client::device_id::get() {
Telemetry::set_firezone_id(id.id);
}
fix_log_filter(&mut settings)?;
let logging::Handles {
logger: _logger,
reloader,
} = start_logging(&settings.log_filter)?;
match gui::run(cli, settings, reloader, telemetry) {
Ok(()) => Ok(()),
Err(anyhow) => {
if anyhow
.chain()
.find_map(|e| e.downcast_ref::<tauri_runtime::Error>())
.is_some_and(|e| matches!(e, tauri_runtime::Error::CreateWebview(_)))
{
show_error_dialog(
"Firezone cannot start because WebView2 is not installed. Follow the instructions at <https://www.firezone.dev/kb/client-apps/windows-gui-client>.",
)?;
return Err(anyhow);
}
if anyhow.root_cause().is::<deep_link::CantListen>() {
show_error_dialog(
"Firezone is already running. If it's not responding, force-stop it.",
)?;
return Err(anyhow);
}
if anyhow
.root_cause()
.is::<firezone_headless_client::ipc::NotFound>()
{
show_error_dialog("Couldn't find Firezone IPC service. Is the service running?")?;
return Err(anyhow);
}
show_error_dialog(
"An unexpected error occurred. Please try restarting Firezone. If the issue persists, contact your administrator.",
)?;
tracing::error!("GUI failed: {anyhow:#}");
Err(anyhow)
}
}
}
/// Parse the log filter from settings, showing an error and fixing it if needed
fn fix_log_filter(settings: &mut AdvancedSettings) -> Result<()> {
if EnvFilter::try_new(&settings.log_filter).is_ok() {
return Ok(());
}
settings.log_filter = AdvancedSettings::default().log_filter;
native_dialog::MessageDialog::new()
.set_title("Log filter error")
.set_text("The custom log filter is not parsable. Using the default log filter.")
.set_type(native_dialog::MessageType::Error)
.show_alert()
.context("Can't show log filter error dialog")?;
Ok(())
}
/// Blocks the thread and shows an error dialog
///
/// Doesn't play well with async, only use this if we're bailing out of the
/// entire process.
fn show_error_dialog(msg: &str) -> Result<()> {
// I tried the Tauri dialogs and for some reason they don't show our
// app icon.
native_dialog::MessageDialog::new()
.set_title("Firezone Error")
.set_text(msg)
.set_type(native_dialog::MessageType::Error)
.show_alert()?;
Ok(())
}
/// Starts logging
///
/// Don't drop the log handle or logging will stop.
fn start_logging(directives: &str) -> Result<logging::Handles> {
let logging_handles = logging::setup(directives)?;
let system_uptime_seconds = firezone_bin_shared::uptime::get().map(|dur| dur.as_secs());
tracing::info!(
arch = std::env::consts::ARCH,
os = std::env::consts::OS,
version = env!("CARGO_PKG_VERSION"),
?directives,
?system_uptime_seconds,
"`gui-client` started logging"
);
Ok(logging_handles)
}
/// The debug / test flags like `crash_on_purpose` and `test_update_notification`
/// don't propagate when we use `RunAs` to elevate ourselves. So those must be run
/// from an admin terminal, or with "Run as administrator" in the right-click menu.
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
/// If true, check for updates every 30 seconds and pretend our current version is 1.0.0, so we'll always show the notification dot.
#[arg(long, hide = true)]
debug_update_check: bool,
#[command(subcommand)]
command: Option<Cmd>,
/// Crash the `Controller` task to test error handling
/// Formerly `--crash-on-purpose`
#[arg(long, hide = true)]
crash: bool,
/// Error out of the `Controller` task to test error handling
#[arg(long, hide = true)]
error: bool,
/// Panic the `Controller` task to test error handling
#[arg(long, hide = true)]
panic: bool,
/// Quit gracefully after a given number of seconds
#[arg(long, hide = true)]
quit_after: Option<u64>,
/// If true, slow down I/O operations to test how the GUI handles slow I/O
#[arg(long, hide = true)]
inject_faults: bool,
/// If true, show a fake update notification that opens the Firezone release page when clicked
#[arg(long, hide = true)]
test_update_notification: bool,
/// For headless CI, disable deep links and allow the GUI to run as admin
#[arg(long, hide = true)]
no_deep_links: bool,
}
impl Cli {
fn fail_on_purpose(&self) -> Option<Failure> {
if self.crash {
Some(Failure::Crash)
} else if self.error {
Some(Failure::Error)
} else if self.panic {
Some(Failure::Panic)
} else {
None
}
}
}
#[derive(clap::Subcommand)]
pub enum Cmd {
Debug {
#[command(subcommand)]
command: debug_commands::Cmd,
},
Elevated,
OpenDeepLink(DeepLink),
/// SmokeTest gets its own subcommand for historical reasons.
SmokeTest,
}
#[derive(Args)]
pub struct DeepLink {
// TODO: Should be `Secret`?
pub url: url::Url,
}
#[cfg(test)]
mod tests {
use anyhow::Result;
#[test]
fn exe_path() -> Result<()> {
// e.g. `\\\\?\\C:\\cygwin64\\home\\User\\projects\\firezone\\rust\\target\\debug\\deps\\firezone_windows_client-5f44800b2dafef90.exe`
let path = tauri_utils::platform::current_exe()?.display().to_string();
assert!(path.contains("target"));
assert!(!path.contains('\"'), "`{}`", path);
Ok(())
}
}