Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Windows client): fix "Tauri error" to "Firezone is already running" #4364

Merged
merged 1 commit into from
Mar 28, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 94 additions & 83 deletions rust/gui-client/src-tauri/src/client/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ pub(crate) fn run(cli: client::Cli) -> Result<(), Error> {
let tray = SystemTray::new().with_menu(system_tray_menu::signed_out());

tracing::debug!("Setting up Tauri app instance...");
let (setup_result_tx, mut setup_result_rx) =
tokio::sync::oneshot::channel::<Result<(), Error>>();
let app = tauri::Builder::default()
.manage(managed)
.on_window_event(|event| {
Expand Down Expand Up @@ -189,103 +191,112 @@ pub(crate) fn run(cli: client::Cli) -> Result<(), Error> {
.setup(move |app| {
tracing::debug!("Entered Tauri's `setup`");

// Check for updates
let ctlr_tx_clone = ctlr_tx.clone();
let always_show_update_notification = cli.always_show_update_notification;
tokio::spawn(async move {
if let Err(error) = check_for_updates(ctlr_tx_clone, always_show_update_notification).await
{
tracing::error!(?error, "Error in check_for_updates");
}
});

// Make sure we're single-instance
// We register our deep links to call the `open-deep-link` subcommand,
// so if we're at this point, we know we've been launched manually
let server = deep_link::Server::new()?;

if let Some(client::Cmd::SmokeTest) = &cli.command {
let ctlr_tx = ctlr_tx.clone();
let setup_inner = move || {
// Check for updates
let ctlr_tx_clone = ctlr_tx.clone();
let always_show_update_notification = cli.always_show_update_notification;
tokio::spawn(async move {
if let Err(error) = smoke_test(ctlr_tx).await {
tracing::error!(?error, "Error during smoke test");
tracing::error!("Crashing on purpose so a dev can see our stacktraces");
unsafe { sadness_generator::raise_segfault() }
if let Err(error) = check_for_updates(ctlr_tx_clone, always_show_update_notification).await
{
tracing::error!(?error, "Error in check_for_updates");
}
});
}

tracing::debug!(cli.no_deep_links);
if !cli.no_deep_links {
// The single-instance check is done, so register our exe
// to handle deep links
deep_link::register().context("Failed to register deep link handler")?;
tokio::spawn(accept_deep_links(server, ctlr_tx.clone()));
}
// Make sure we're single-instance
// We register our deep links to call the `open-deep-link` subcommand,
// so if we're at this point, we know we've been launched manually
let server = deep_link::Server::new()?;

if let Some(client::Cmd::SmokeTest) = &cli.command {
let ctlr_tx = ctlr_tx.clone();
tokio::spawn(async move {
if let Err(error) = smoke_test(ctlr_tx).await {
tracing::error!(?error, "Error during smoke test");
tracing::error!("Crashing on purpose so a dev can see our stacktraces");
unsafe { sadness_generator::raise_segfault() }
}
});
}

if let Some(failure) = cli.fail_on_purpose() {
let ctlr_tx = ctlr_tx.clone();
tokio::spawn(async move {
let delay = 5;
tracing::info!(
"Will crash / error / panic on purpose in {delay} seconds to test error handling."
);
tokio::time::sleep(Duration::from_secs(delay)).await;
tracing::info!("Crashing / erroring / panicking on purpose");
ctlr_tx.send(ControllerRequest::Fail(failure)).await?;
Ok::<_, anyhow::Error>(())
});
}
tracing::debug!(cli.no_deep_links);
if !cli.no_deep_links {
// The single-instance check is done, so register our exe
// to handle deep links
deep_link::register().context("Failed to register deep link handler")?;
tokio::spawn(accept_deep_links(server, ctlr_tx.clone()));
}

assert_eq!(
BUNDLE_ID,
app.handle().config().tauri.bundle.identifier,
"BUNDLE_ID should match bundle ID in tauri.conf.json"
);

let app_handle = app.handle();
let _ctlr_task = tokio::spawn(async move {
let app_handle_2 = app_handle.clone();
// Spawn two nested Tasks so the outer can catch panics from the inner
let task = tokio::spawn(async move {
run_controller(
app_handle_2,
ctlr_tx,
ctlr_rx,
logging_handles,
advanced_settings,
)
.await
});
if let Some(failure) = cli.fail_on_purpose() {
let ctlr_tx = ctlr_tx.clone();
tokio::spawn(async move {
let delay = 5;
tracing::info!(
"Will crash / error / panic on purpose in {delay} seconds to test error handling."
);
tokio::time::sleep(Duration::from_secs(delay)).await;
tracing::info!("Crashing / erroring / panicking on purpose");
ctlr_tx.send(ControllerRequest::Fail(failure)).await?;
Ok::<_, anyhow::Error>(())
});
}

// See <https://github.com/tauri-apps/tauri/issues/8631>
// This should be the ONLY place we call `app.exit` or `app_handle.exit`,
// because it exits the entire process without dropping anything.
//
// This seems to be a platform limitation that Tauri is unable to hide
// from us. It was the source of much consternation at time of writing.

match task.await {
Err(error) => {
tracing::error!(?error, "run_controller panicked");
app_handle.exit(1);
}
Ok(Err(error)) => {
tracing::error!(?error, "run_controller returned an error");
app_handle.exit(1);
}
Ok(Ok(_)) => {
tracing::info!("GUI controller task exited cleanly. Exiting process");
app_handle.exit(0);
assert_eq!(
BUNDLE_ID,
app.handle().config().tauri.bundle.identifier,
"BUNDLE_ID should match bundle ID in tauri.conf.json"
);

let app_handle = app.handle();
let _ctlr_task = tokio::spawn(async move {
let app_handle_2 = app_handle.clone();
// Spawn two nested Tasks so the outer can catch panics from the inner
let task = tokio::spawn(async move {
run_controller(
app_handle_2,
ctlr_tx,
ctlr_rx,
logging_handles,
advanced_settings,
)
.await
});

// See <https://github.com/tauri-apps/tauri/issues/8631>
// This should be the ONLY place we call `app.exit` or `app_handle.exit`,
// because it exits the entire process without dropping anything.
//
// This seems to be a platform limitation that Tauri is unable to hide
// from us. It was the source of much consternation at time of writing.

match task.await {
Err(error) => {
tracing::error!(?error, "run_controller panicked");
app_handle.exit(1);
}
Ok(Err(error)) => {
tracing::error!(?error, "run_controller returned an error");
app_handle.exit(1);
}
Ok(Ok(_)) => {
tracing::info!("GUI controller task exited cleanly. Exiting process");
app_handle.exit(0);
}
}
}
});
});
Ok(())
};

setup_result_tx.send(setup_inner()).expect("should be able to send setup result");

Ok(())
});
tracing::debug!("Building Tauri app...");
let app = app.build(tauri::generate_context!());

setup_result_rx
.try_recv()
.context("couldn't receive result of setup")??;

let app = match app {
Ok(x) => x,
Err(error) => {
Expand Down
Loading