From 98354aec7179882cda9bb7a47566996003f23163 Mon Sep 17 00:00:00 2001 From: thewh1teagle <61390950+thewh1teagle@users.noreply.github.com> Date: Mon, 26 Aug 2024 02:28:07 +0300 Subject: [PATCH] fix(windows): redirect stdout and stderr from c++ to get whisper errors --- Cargo.lock | 16 +++++++++-- desktop/src-tauri/Cargo.toml | 7 ++++- desktop/src-tauri/src/cli.rs | 42 +++++++++++++++-------------- desktop/src-tauri/src/panic_hook.rs | 11 +++++--- desktop/src-tauri/src/setup.rs | 6 ++--- 5 files changed, 53 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0855bf02..297a53cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2661,9 +2661,19 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libc-stdhandle" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dac2473dc28934c5e0b82250dab231c9d3b94160d91fe9ff483323b05797551" +dependencies = [ + "cc", + "libc", +] [[package]] name = "libloading" @@ -6264,6 +6274,8 @@ dependencies = [ "eyre 1.0.0", "futures", "hound", + "libc", + "libc-stdhandle", "objc_id", "once_cell", "open", diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index ff34b9b1..21f14524 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -59,11 +59,16 @@ openssl = { version = "0.10.63", features = ["vendored"] } # Windows [target.'cfg(windows)'.dependencies] vibe_core = { path = "../../core", features = [] } +winreg = "0.52.0" +# Used to attach to console windows = { version = "0.56.0", features = [ "Win32_System_Console", "Win32_Foundation", ] } -winreg = "0.52.0" +# Used to redirect stdout/stderr from c++ to the attached console. otherwise whisper errors won't show +libc = "0.2.158" +libc-stdhandle = "0.1.0" + # macOS [target.'cfg(target_os = "macos")'.dependencies] diff --git a/desktop/src-tauri/src/cli.rs b/desktop/src-tauri/src/cli.rs index 96d9fce8..1410757f 100644 --- a/desktop/src-tauri/src/cli.rs +++ b/desktop/src-tauri/src/cli.rs @@ -1,41 +1,43 @@ use clap::Parser; use eyre::{Context, ContextCompat, Result}; +use once_cell::sync::Lazy; use serde_json::Value; use std::path::{Path, PathBuf}; +use std::process; use std::time::Instant; -use std::{env, process}; use tauri::AppHandle; use vibe_core::config::TranscribeOptions; use vibe_core::transcribe; use crate::cmd::get_models_folder; use crate::server; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering; + +pub static IS_CLI: Lazy = Lazy::new(|| AtomicBool::new(false)); /// Attach to console if cli detected in Windows #[cfg(windows)] pub fn attach_console() { use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS}; - if env::var("RUST_LOG").is_ok() || is_cli_detected() { - // we ignore the result here because - // if the app started from a command line, like cmd or powershell, - // it will attach sucessfully which is what we want - // but if we were started from something like explorer, - // it will fail to attach console which is also what we want. - let _ = unsafe { AttachConsole(ATTACH_PARENT_PROCESS) }; - } -} - -pub fn is_cli_detected() -> bool { - // Get the command-line arguments as an iterator - let args: Vec = env::args().collect(); - - // Check if any argument starts with "--" - for arg in &args { - if arg.starts_with("--") || arg == "-h" { - return true; + let attach_result = unsafe { AttachConsole(ATTACH_PARENT_PROCESS) }; + if attach_result.is_ok() { + IS_CLI.store(true, Ordering::Relaxed); + // Wer'e in CLI + // Experimental: redirect stdout and stderr to the new console. otherwise c++ bindings writes won't show. + // https://users.rust-lang.org/t/stderr-write-from-c-bindings-missing-on-windows/116582 + unsafe { + let conout = std::ffi::CString::new("CONOUT$").expect("CString::new failed"); + let stdout = libc_stdhandle::stdout(); + let stderr = libc_stdhandle::stderr(); + let mode = std::ffi::CString::new("w").unwrap(); + libc::freopen(conout.as_ptr(), mode.as_ptr(), stdout); + libc::freopen(conout.as_ptr(), mode.as_ptr(), stderr); } + tracing::debug!("CLI detected. attached console successfuly"); + } else { + tracing::debug!("No CLI detected."); } - false } /// Simple program to greet a person diff --git a/desktop/src-tauri/src/panic_hook.rs b/desktop/src-tauri/src/panic_hook.rs index f3ce0e4b..77986323 100644 --- a/desktop/src-tauri/src/panic_hook.rs +++ b/desktop/src-tauri/src/panic_hook.rs @@ -1,12 +1,16 @@ use crate::{ - cli, + cli::IS_CLI, cmd::is_portable, config, utils::{get_current_dir, LogError}, }; use chrono::Local; use eyre::{eyre, Context, Result}; -use std::{panic, path::PathBuf, sync::Arc}; +use std::{ + panic, + path::PathBuf, + sync::{atomic::Ordering, Arc}, +}; use tauri::{AppHandle, Manager}; fn get_log_path(app: &AppHandle) -> Result { @@ -46,7 +50,8 @@ pub fn set_panic_hook(app: &AppHandle) -> Result<()> { .context("write") .map_err(|e| eyre!("{:?}", e)) .log_error(); - if !cli::is_cli_detected() { + // Open the log path in release mode + if !cfg!(debug_assertions) && !IS_CLI.load(Ordering::Relaxed) { showfile::show_path_in_file_manager(log_path.as_path()); } })); diff --git a/desktop/src-tauri/src/setup.rs b/desktop/src-tauri/src/setup.rs index 28d3203a..9d20db60 100644 --- a/desktop/src-tauri/src/setup.rs +++ b/desktop/src-tauri/src/setup.rs @@ -1,12 +1,12 @@ use crate::{ - cli, + cli::{self, IS_CLI}, config::STORE_FILENAME, panic_hook, utils::{get_issue_url, LogError}, }; use eyre::eyre; use once_cell::sync::Lazy; -use std::fs; +use std::{fs, sync::atomic::Ordering}; use tauri::{App, Manager}; use tauri_plugin_dialog::DialogExt; use tauri_plugin_shell::ShellExt; @@ -105,7 +105,7 @@ pub fn setup(app: &App) -> Result<(), Box> { tracing::debug!("COMMIT_HASH: {}", env!("COMMIT_HASH")); let app_handle = app.app_handle().clone(); - if cli::is_cli_detected() { + if IS_CLI.load(Ordering::Relaxed) { tauri::async_runtime::spawn(async move { cli::run(&app_handle).await.map_err(|e| eyre!("{:?}", e)).log_error(); });