diff --git a/src/stremio_app/app.rs b/src/stremio_app/app.rs index 414830d..a119c08 100644 --- a/src/stremio_app/app.rs +++ b/src/stremio_app/app.rs @@ -10,7 +10,8 @@ use std::{ process::{self, Command}, str, sync::{Arc, Mutex}, - thread, time, + thread, + time::{self, Duration}, }; use url::Url; use winapi::um::{winbase::CREATE_BREAKAWAY_FROM_JOB, winuser::WS_EX_TOPMOST}; @@ -133,6 +134,10 @@ impl MainWindow { let web_tx_arg = web_tx.clone(); let web_tx_upd = web_tx.clone(); let web_rx = web_rx.clone(); + + let (updater_tx, updater_rx) = flume::unbounded::(); + let updater_tx_web = updater_tx.clone(); + let command_clone = self.command.clone(); // Single application IPC @@ -147,34 +152,40 @@ impl MainWindow { let release_candidate = self.release_candidate; let autoupdater_setup_file = self.autoupdater_setup_file.clone(); thread::spawn(move || loop { - let current_version = env!("CARGO_PKG_VERSION") - .parse() - .expect("Should always be valid"); - let updater_endpoint = if let Some(ref endpoint) = autoupdater_endpoint { - endpoint.clone() - } else { - let mut rng = rand::thread_rng(); - let index = rng.gen_range(0..UPDATE_ENDPOINT.len()); - let mut url = Url::parse(UPDATE_ENDPOINT[index]).unwrap(); - if release_candidate { - url.query_pairs_mut().append_pair("rc", "true"); - } - url - }; - let updater = updater::Updater::new(current_version, &updater_endpoint, force_update); + updater_rx.try_iter().for_each(|message| { + if message.as_str() == "check_for_update" { + let current_version = env!("CARGO_PKG_VERSION") + .parse() + .expect("Should always be valid"); + + let updater_endpoint = if let Some(ref endpoint) = autoupdater_endpoint { + endpoint.clone() + } else { + let mut rng = rand::thread_rng(); + let index = rng.gen_range(0..UPDATE_ENDPOINT.len()); + let mut url = Url::parse(UPDATE_ENDPOINT[index]).unwrap(); + if release_candidate { + url.query_pairs_mut().append_pair("rc", "true"); + } + url + }; - match updater.autoupdate() { - Ok(Some(update)) => { - println!("New version ready to install v{}", update.version); - let mut autoupdater_setup_file = autoupdater_setup_file.lock().unwrap(); - *autoupdater_setup_file = Some(update.file.clone()); - web_tx_upd.send(RPCResponse::update_available()).ok(); + let updater = + updater::Updater::new(current_version, &updater_endpoint, force_update); + match updater.autoupdate() { + Ok(Some(update)) => { + println!("New version ready to install v{}", update.version); + let mut autoupdater_setup_file = autoupdater_setup_file.lock().unwrap(); + *autoupdater_setup_file = Some(update.file.clone()); + web_tx_upd.send(RPCResponse::update_available()).ok(); + } + Ok(None) => println!("No new updates found"), + Err(e) => eprintln!("Failed to fetch updates: {e}"), + } } - Ok(None) => println!("No new updates found"), - Err(e) => eprintln!("Failed to fetch updates: {e}"), - } + }); - thread::sleep(time::Duration::from_secs(UPDATE_INTERVAL)); + thread::sleep(Duration::from_millis(10)); }); // thread if let Ok(mut listener) = PipeServer::bind(socket_path) { @@ -201,109 +212,134 @@ impl MainWindow { .for_each(drop); }); // thread + let mut last_update_check = time::Instant::now(); let toggle_fullscreen_sender = self.toggle_fullscreen_notice.sender(); let quit_sender = self.quit_notice.sender(); let hide_splash_sender = self.hide_splash_notice.sender(); let focus_sender = self.focus_notice.sender(); let autoupdater_setup_mutex = self.autoupdater_setup_file.clone(); thread::spawn(move || loop { - if let Some(msg) = web_rx - .recv() - .ok() - .and_then(|s| serde_json::from_str::(&s).ok()) - { - match msg.get_method() { - // The handshake. Here we send some useful data to the WEB UI - None if msg.is_handshake() => { - web_tx_web.send(RPCResponse::get_handshake()).ok(); - } - Some("win-set-visibility") => toggle_fullscreen_sender.notice(), - Some("quit") => quit_sender.notice(), - Some("app-ready") => { - hide_splash_sender.notice(); - web_tx_web - .send(RPCResponse::visibility_change(true, 1, false)) - .ok(); - let command_ref = command_clone.clone(); - if !command_ref.is_empty() { - web_tx_web.send(RPCResponse::open_media(command_ref)).ok(); - } - } - Some("app-error") => { - hide_splash_sender.notice(); - if let Some(arg) = msg.get_params() { - // TODO: Make this modal dialog - eprintln!("Web App Error: {}", arg); - } - } - Some("open-external") => { - if let Some(arg) = msg.get_params() { - // FIXME: THIS IS NOT SAFE BY ANY MEANS - // open::that("calc").ok(); does exactly that - let arg = arg.as_str().unwrap_or(""); - let arg_lc = arg.to_lowercase(); - if arg_lc.starts_with("http://") - || arg_lc.starts_with("https://") - || arg_lc.starts_with("rtp://") - || arg_lc.starts_with("rtps://") - || arg_lc.starts_with("ftp://") - || arg_lc.starts_with("ipfs://") - { - open::that(arg).ok(); + let now = time::Instant::now(); + if now > (last_update_check + time::Duration::from_secs(UPDATE_INTERVAL)) { + last_update_check = now; + updater_tx_web + .send("check_for_update".to_owned()) + .expect("Failed to send value to updater channel"); + } + + web_rx + .try_iter() + .map(|message| serde_json::from_str::(&message)) + .for_each(|result| { + if let Ok(request) = result { + match request.get_method() { + // The handshake. Here we send some useful data to the WEB UI + None if request.is_handshake() => { + web_tx_web.send(RPCResponse::get_handshake()).ok(); } - } - } - Some("win-focus") => { - focus_sender.notice(); - } - Some("autoupdater-notif-clicked") => { - // We've shown the "Update Available" notification - // and the user clicked on "Restart And Update" - let autoupdater_setup_file = - autoupdater_setup_mutex.lock().unwrap().clone(); - match autoupdater_setup_file { - Some(file_path) => { - println!("Running the setup at {:?}", file_path); + Some("win-set-visibility") => toggle_fullscreen_sender.notice(), + Some("quit") => quit_sender.notice(), + Some("app-ready") => { + hide_splash_sender.notice(); + web_tx_web + .send(RPCResponse::visibility_change(true, 1, false)) + .ok(); + updater_tx_web + .send("check_for_update".to_owned()) + .expect("Failed to send value to updater channel"); + + let command_ref = command_clone.clone(); + if !command_ref.is_empty() { + web_tx_web.send(RPCResponse::open_media(command_ref)).ok(); + } + } + Some("app-error") => { + hide_splash_sender.notice(); + if let Some(arg) = request.get_params() { + // TODO: Make this modal dialog + eprintln!("Web App Error: {}", arg); + } + } + Some("open-external") => { + if let Some(arg) = request.get_params() { + // FIXME: THIS IS NOT SAFE BY ANY MEANS + // open::that("calc").ok(); does exactly that + let arg = arg.as_str().unwrap_or(""); + let arg_lc = arg.to_lowercase(); + if arg_lc.starts_with("http://") + || arg_lc.starts_with("https://") + || arg_lc.starts_with("rtp://") + || arg_lc.starts_with("rtps://") + || arg_lc.starts_with("ftp://") + || arg_lc.starts_with("ipfs://") + { + open::that(arg).ok(); + } + } + } + Some("win-focus") => { + focus_sender.notice(); + } + Some("autoupdater-notif-clicked") => { + // We've shown the "Update Available" notification + // and the user clicked on "Restart And Update" + let autoupdater_setup_file = + autoupdater_setup_mutex.lock().unwrap().clone(); + match autoupdater_setup_file { + Some(file_path) => { + println!("Running the setup at {:?}", file_path); - let command = Command::new(file_path) - .args([ - "/SILENT", - "/NOCANCEL", - "/FORCECLOSEAPPLICATIONS", - "/TASKS=runapp", - ]) - .creation_flags(CREATE_BREAKAWAY_FROM_JOB) - .stdin(process::Stdio::null()) - .stdout(process::Stdio::null()) - .stderr(process::Stdio::null()) - .spawn(); + let command = Command::new(file_path) + .args([ + "/SILENT", + "/NOCANCEL", + "/FORCECLOSEAPPLICATIONS", + "/TASKS=runapp", + ]) + .creation_flags(CREATE_BREAKAWAY_FROM_JOB) + .stdin(process::Stdio::null()) + .stdout(process::Stdio::null()) + .stderr(process::Stdio::null()) + .spawn(); - match command { - Ok(process) => { - println!("Updater started. (PID {:?})", process.id()); - quit_sender.notice(); + match command { + Ok(process) => { + println!( + "Updater started. (PID {:?})", + process.id() + ); + quit_sender.notice(); + } + Err(err) => { + eprintln!("Updater couldn't be started: {err}") + } + }; } - Err(err) => eprintln!("Updater couldn't be started: {err}"), - }; + _ => { + println!("Cannot obtain the setup file path"); + } + } + } + Some(player_command) if player_command.starts_with("mpv-") => { + let resp_json = serde_json::to_string( + &request.args.expect("Cannot have method without args"), + ) + .expect("Cannot build response"); + player_tx.send(resp_json).ok(); } - _ => { - println!("Cannot obtain the setup file path"); + Some(unknown) => { + eprintln!( + "Unsupported command {}({:?})", + unknown, + request.get_params() + ) } + None => {} } } - Some(player_command) if player_command.starts_with("mpv-") => { - let resp_json = serde_json::to_string( - &msg.args.expect("Cannot have method without args"), - ) - .expect("Cannot build response"); - player_tx.send(resp_json).ok(); - } - Some(unknown) => { - eprintln!("Unsupported command {}({:?})", unknown, msg.get_params()) - } - None => {} - } - } // recv + }); + + thread::sleep(Duration::from_millis(10)); }); // thread } fn on_min_max(&self, data: &nwg::EventData) {