Skip to content

Commit

Permalink
Merge pull request #175 from J-ZhengLi/dev-zhengli
Browse files Browse the repository at this point in the history
fix an issue where the logger could send log to closed channel in manager mode
  • Loading branch information
J-ZhengLi authored Dec 13, 2024
2 parents b09d0d0 + cead5e9 commit d308871
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 142 deletions.
33 changes: 33 additions & 0 deletions rim_dev/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

use anyhow::{anyhow, bail, Context, Result};

Expand Down Expand Up @@ -134,3 +135,35 @@ pub fn ensure_parent_dir<P: AsRef<Path>>(path: P) -> Result<()> {
}
Ok(())
}

pub fn install_gui_deps() {
println!("running `pnpm i`");
let fail_msg = "unable to run `pnpm i`, \
please manually cd to `rim_gui/` then run the command manually";

let gui_crate_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).with_file_name("rim_gui");
assert!(gui_crate_dir.exists());

cfg_if::cfg_if! {
if #[cfg(windows)] {
let mut status = Command::new("cmd.exe");
status.args(["/C", "pnpm", "i"]);
} else {
let mut status = Command::new("pnpm");
status.arg("i");
}
}
status
.current_dir(gui_crate_dir)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit());

let Ok(st) = status.status() else {
println!("{fail_msg}");
return;
};

if !st.success() {
println!("{fail_msg}: {}", st.code().unwrap_or(-1));
}
}
38 changes: 3 additions & 35 deletions rim_dev/src/dist.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use env::consts::EXE_SUFFIX;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::process::Command;
use std::{env, fs};

use anyhow::{bail, Result};
use cfg_if::cfg_if;

use crate::common::*;
use crate::common::{self, *};

pub const DIST_HELP: &str = r#"
Generate release binaries
Expand Down Expand Up @@ -153,7 +153,7 @@ pub fn dist(mode: DistMode, binary_only: bool) -> Result<()> {
};

if !matches!(mode, DistMode::Cli) {
pnpm_install();
common::install_gui_deps();
}

for worker in workers {
Expand All @@ -179,35 +179,3 @@ pub fn dist(mode: DistMode, binary_only: bool) -> Result<()> {

Ok(())
}

fn pnpm_install() {
println!("running `pnpm i`");
let fail_msg = "unable to run `pnpm i`, \
please manually cd to `rim_gui/` then run the command manually";

let gui_crate_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).with_file_name("rim_gui");
assert!(gui_crate_dir.exists());

cfg_if! {
if #[cfg(windows)] {
let mut status = Command::new("cmd.exe");
status.args(["/C", "pnpm", "i"]);
} else {
let mut status = Command::new("pnpm");
status.arg("i");
}
}
status
.current_dir(gui_crate_dir)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit());

let Ok(st) = status.status() else {
println!("{fail_msg}");
return;
};

if !st.success() {
println!("{fail_msg}: {}", st.code().unwrap_or(-1));
}
}
6 changes: 6 additions & 0 deletions rim_dev/src/mocked/installation.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Module to create a fake installation root, useful to test the `manager` utilities.
use crate::common;

use super::TOOLKIT_NAME;
use anyhow::{bail, Result};
use std::{env::consts::EXE_SUFFIX, fs, path::PathBuf, process::Command};
Expand Down Expand Up @@ -41,6 +43,10 @@ paths = ['{0}/tools/mingw64']
};
cargo_args.extend(args.iter().map(|s| s.as_str()));

if !no_gui {
common::install_gui_deps();
}

// build rim
let build_status = Command::new("cargo").args(cargo_args).status()?;
if !build_status.success() {
Expand Down
90 changes: 35 additions & 55 deletions rim_gui/src-tauri/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{
path::PathBuf,
sync::{mpsc, Arc},
thread::{self, JoinHandle},
sync::mpsc::{self, Receiver},
thread,
time::Duration,
};

Expand All @@ -18,42 +18,47 @@ pub(crate) const PROGRESS_UPDATE_EVENT: &str = "update-progress";
pub(crate) const ON_COMPLETE_EVENT: &str = "on-complete";
pub(crate) const ON_FAILED_EVENT: &str = "on-failed";

pub(crate) fn install_components(
window: tauri::Window,
components_list: Vec<Component>,
install_dir: PathBuf,
manifest: &ToolsetManifest,
is_update: bool,
) -> Result<()> {
/// Configure the logger to use a communication channel ([`mpsc`]),
/// allowing us to send logs accrossing threads.
///
/// This will return a log message's receiver which can be used to emitting
/// messages onto [`tauri::Window`]
pub(crate) fn setup_logger() -> Result<Receiver<String>> {
let (msg_sendr, msg_recvr) = mpsc::channel::<String>();
// config logger to use the `msg_sendr` we just created
utils::Logger::new().sender(msg_sendr).setup()?;
Ok(msg_recvr)
}

// 使用 Arc 来共享
// NB (J-ZhengLi): Threads don't like 'normal' references
let window = Arc::new(window);
let window_clone = Arc::clone(&window);
let manifest = Arc::new(manifest.to_owned());

// 在一个新线程中执行安装过程
let install_thread =
spawn_install_thread(window, components_list, install_dir, manifest, is_update);
// 在主线程中接收进度并发送事件
let gui_thread = spawn_gui_update_thread(window_clone, install_thread, msg_recvr);
pub(crate) fn spawn_gui_update_thread(window: tauri::Window, msg_recv: Receiver<String>) {
thread::spawn(move || loop {
// Note: `recv()` will block, therefore it's important to check thread execution atfirst
if let Ok(msg) = msg_recv.recv() {
if msg.starts_with("error:") {
emit(&window, ON_FAILED_EVENT, msg);
break;
} else {
emit(&window, MESSAGE_UPDATE_EVENT, msg);
}
}
});
}

if gui_thread.is_finished() {
gui_thread.join().expect("unable to join GUI thread")?;
}
Ok(())
fn emit(window: &tauri::Window, event: &str, msg: String) {
window.emit(event, msg).unwrap_or_else(|e| {
log::error!(
"unexpected error occurred \
while emiting tauri event: {e}"
)
});
}

fn spawn_install_thread(
window: Arc<tauri::Window>,
pub(crate) fn install_toolkit_in_new_thread(
window: tauri::Window,
components_list: Vec<Component>,
install_dir: PathBuf,
manifest: Arc<ToolsetManifest>,
manifest: ToolsetManifest,
is_update: bool,
) -> JoinHandle<anyhow::Result<()>> {
) {
thread::spawn(move || -> anyhow::Result<()> {
// FIXME: this is needed to make sure the other thread could recieve the first couple messages
// we sent in this thread. But it feels very wrong, there has to be better way.
Expand All @@ -77,32 +82,7 @@ fn spawn_install_thread(
window.emit(ON_COMPLETE_EVENT, ())?;

Ok(())
})
}

pub(crate) fn spawn_gui_update_thread(
win: Arc<tauri::Window>,
install_handle: thread::JoinHandle<anyhow::Result<()>>,
msg_recvr: mpsc::Receiver<String>,
) -> JoinHandle<anyhow::Result<()>> {
thread::spawn(move || loop {
for pending_message in msg_recvr.try_iter() {
win.emit(MESSAGE_UPDATE_EVENT, pending_message)?;
}

if install_handle.is_finished() {
return if let Err(known_error) = install_handle
.join()
.expect("unexpected error occurs when attempting to join thread.")
{
let error_str = known_error.to_string();
win.emit(ON_FAILED_EVENT, error_str.clone())?;
Err(known_error)
} else {
Ok(())
};
}
})
});
}

#[derive(serde::Serialize)]
Expand Down
16 changes: 8 additions & 8 deletions rim_gui/src-tauri/src/installer_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use rim::{try_it, utils};
static TOOLSET_MANIFEST: OnceLock<ToolsetManifest> = OnceLock::new();

pub(super) fn main() -> Result<()> {
let msg_recv = common::setup_logger()?;

tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
super::close_window,
Expand Down Expand Up @@ -41,6 +43,8 @@ pub(super) fn main() -> Result<()> {
.build()?;

common::set_window_shadow(&window);
common::spawn_gui_update_thread(window, msg_recv);

Ok(())
})
.run(tauri::generate_context!())
Expand Down Expand Up @@ -118,19 +122,15 @@ fn load_manifest_and_ret_version() -> Result<String> {
}

#[tauri::command(rename_all = "snake_case")]
fn install_toolchain(
window: tauri::Window,
components_list: Vec<Component>,
install_dir: String,
) -> Result<()> {
fn install_toolchain(window: tauri::Window, components_list: Vec<Component>, install_dir: String) {
let install_dir = PathBuf::from(install_dir);
common::install_components(
common::install_toolkit_in_new_thread(
window,
components_list,
install_dir,
cached_manifest(),
cached_manifest().to_owned(),
false,
)
);
}

/// Retrieve cached toolset manifest.
Expand Down
38 changes: 18 additions & 20 deletions rim_gui/src-tauri/src/manager_mode.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::{
sync::{mpsc, Arc, Mutex, MutexGuard, OnceLock},
sync::{Arc, Mutex, MutexGuard},
thread,
time::Duration,
};

use crate::{
common::{self, spawn_gui_update_thread, ON_COMPLETE_EVENT, PROGRESS_UPDATE_EVENT},
common::{self, ON_COMPLETE_EVENT, PROGRESS_UPDATE_EVENT},
error::Result,
};
use anyhow::Context;
Expand All @@ -20,7 +20,6 @@ use rim::{
use tauri::{api::dialog, AppHandle, Manager};

static SELECTED_TOOLSET: Mutex<Option<ToolsetManifest>> = Mutex::new(None);
static LOGGER_SETUP: OnceLock<()> = OnceLock::new();

fn selected_toolset<'a>() -> MutexGuard<'a, Option<ToolsetManifest>> {
SELECTED_TOOLSET
Expand All @@ -29,6 +28,8 @@ fn selected_toolset<'a>() -> MutexGuard<'a, Option<ToolsetManifest>> {
}

pub(super) fn main() -> Result<()> {
let msg_recv = common::setup_logger()?;

tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
super::close_window,
Expand Down Expand Up @@ -56,6 +57,8 @@ pub(super) fn main() -> Result<()> {
.build()?;

common::set_window_shadow(&window);
common::spawn_gui_update_thread(window, msg_recv);

Ok(())
})
.run(tauri::generate_context!())
Expand All @@ -73,13 +76,13 @@ fn window_title() -> String {
}

#[tauri::command]
fn get_installed_kit() -> Result<Option<Toolkit>> {
Ok(Toolkit::installed()?.cloned())
fn get_installed_kit(reload: bool) -> Result<Option<Toolkit>> {
Ok(Toolkit::installed(reload)?.map(|guard| guard.clone()))
}

#[tauri::command]
fn get_available_kits() -> Result<Vec<Toolkit>> {
Ok(toolkit::installable_toolkits()?
fn get_available_kits(reload: bool) -> Result<Vec<Toolkit>> {
Ok(toolkit::installable_toolkits(reload)?
.into_iter()
.cloned()
.collect())
Expand All @@ -92,15 +95,9 @@ fn get_install_dir() -> String {

#[tauri::command(rename_all = "snake_case")]
fn uninstall_toolkit(window: tauri::Window, remove_self: bool) -> Result<()> {
let (msg_sendr, msg_recvr) = mpsc::channel::<String>();
// config logger to use the `msg_sendr` we just created, use OnceLock to make sure it run
// exactly once.
LOGGER_SETUP.get_or_init(|| _ = utils::Logger::new().sender(msg_sendr).setup());

let window = Arc::new(window);
let window_clone = Arc::clone(&window);

let uninstall_thread = thread::spawn(move || -> anyhow::Result<()> {
thread::spawn(move || -> anyhow::Result<()> {
// FIXME: this is needed to make sure the other thread could recieve the first couple messages
// we sent in this thread. But it feels very wrong, there has to be better way.
thread::sleep(Duration::from_millis(500));
Expand All @@ -116,11 +113,6 @@ fn uninstall_toolkit(window: tauri::Window, remove_self: bool) -> Result<()> {
Ok(())
});

let gui_thread = spawn_gui_update_thread(window_clone, uninstall_thread, msg_recvr);

if gui_thread.is_finished() {
gui_thread.join().expect("failed to join GUI thread")?;
}
Ok(())
}

Expand All @@ -131,7 +123,13 @@ fn install_toolkit(window: tauri::Window, components_list: Vec<Component>) -> Re
let manifest = guard
.as_ref()
.expect("internal error: a toolkit must be selected to install");
common::install_components(window, components_list, p.to_path_buf(), manifest, true)?;
common::install_toolkit_in_new_thread(
window,
components_list,
p.to_path_buf(),
manifest.to_owned(),
true,
);
Ok(())
})?;
Ok(())
Expand Down
9 changes: 8 additions & 1 deletion rim_gui/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ export function useCustomRouter() {
if (typeof deep === 'number') newRouter.go(deep);
else newRouter.back();
}
function routerPushAndClearCache(path: RouteLocationRaw) {
newRouter.push(path).then(() => {
setTimeout(() => {
window.location.reload();
}, 500);
});
}

return { isBack, routerPush, routerBack };
return { isBack, routerPush, routerBack, routerPushAndClearCache };
}
Loading

0 comments on commit d308871

Please sign in to comment.