use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use crate::launch::{DEFAULT_READY_TIMEOUT, LaunchFail, launch, launch_workdir, unique_marker};
use crate::pick::write_pick_in;
#[derive(Default)]
pub struct RunShared {
pub handle: Mutex<Option<std::thread::JoinHandle<()>>>,
pub outcome: Mutex<Option<Result<(), LaunchFail>>>,
}
pub fn run_pick_launcher() -> Result<(), String> {
let program = std::env::current_exe().map_err(|e| format!("current_exe: {e:?}"))?;
let shared = Arc::new(RunShared::default());
let app = crate::launcher_ui::PickApp::new(program.clone(), shared.clone());
let opts = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_inner_size([460.0, 460.0])
.with_title("ek 启动选择"),
..Default::default()
};
let window = eframe::run_native(
"ek-launch",
opts,
Box::new(|cc| {
crate::fonts::apply_cjk_fonts(&cc.egui_ctx); Ok(Box::new(app) as Box<dyn eframe::App>)
}),
);
if let Some(h) = shared.handle.lock().unwrap().take() {
let _ = h.join();
}
window.map_err(|e| format!("pick window: {e:?}"))?;
match shared.outcome.lock().unwrap().take() {
None => Ok(()), Some(Ok(())) => Ok(()), Some(Err(e)) => Err(e.to_string()), }
}
pub fn launch_worker(shared: &RunShared, names: &[String], program: PathBuf) {
let dir = launch_workdir();
let names_ref: Vec<&str> = names.iter().map(String::as_str).collect();
let outcome = (|| -> Result<(), LaunchFail> {
let pick_path = write_pick_in(&dir, &names_ref)?;
let marker = unique_marker(&dir);
let args = vec![
"--from".to_string(),
pick_path.to_string_lossy().into_owned(),
"--ready-file".to_string(),
marker.to_string_lossy().into_owned(),
];
launch(&program, &args, &marker, DEFAULT_READY_TIMEOUT)
})();
*shared.outcome.lock().unwrap() = Some(outcome);
}
pub const POLL: Duration = Duration::from_millis(200);