diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 74982de5d..3ad87267a 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -62,13 +62,13 @@ pub enum NetworkType { #[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] pub struct Config { #[serde(default)] - id: String, + pub id: String, #[serde(default)] password: String, #[serde(default)] salt: String, #[serde(default)] - key_pair: (Vec, Vec), // sk, pk + pub key_pair: (Vec, Vec), // sk, pk #[serde(default)] key_confirmed: bool, #[serde(default)] @@ -199,26 +199,37 @@ impl Config2 { return CONFIG2.read().unwrap().clone(); } - pub fn set(cfg: Config2) { + pub fn set(cfg: Config2) -> bool { let mut lock = CONFIG2.write().unwrap(); + if *lock == cfg { + return false; + } *lock = cfg; lock.store(); + true } } +pub fn load_path( + file: PathBuf, +) -> T { + let cfg = match confy::load_path(&file) { + Ok(config) => config, + Err(err) => { + log::error!("Failed to load config: {}", err); + T::default() + } + }; + cfg +} + impl Config { fn load_( suffix: &str, ) -> T { let file = Self::file_(suffix); log::debug!("Configuration path: {}", file.display()); - let cfg = match confy::load_path(&file) { - Ok(config) => config, - Err(err) => { - log::error!("Failed to load config: {}", err); - T::default() - } - }; + let cfg = load_path(file); if suffix.is_empty() { log::debug!("{:?}", cfg); } @@ -244,28 +255,6 @@ impl Config { Self::file_("") } - pub fn import(from: &str) { - log::info!("import {}", from); - // load first to create path - Self::load(); - crate::allow_err!(std::fs::copy(from, Self::file())); - crate::allow_err!(std::fs::copy( - from.replace(".toml", "2.toml"), - Self::file_("2") - )); - } - - pub fn save_tmp() -> String { - let _lock = CONFIG.read().unwrap(); // do not use let _, which will be dropped immediately - let path = Self::file_("2").to_str().unwrap_or("").to_owned(); - let path2 = format!("{}_tmp", path); - crate::allow_err!(std::fs::copy(&path, &path2)); - let path = Self::file().to_str().unwrap_or("").to_owned(); - let path2 = format!("{}_tmp", path); - crate::allow_err!(std::fs::copy(&path, &path2)); - path2 - } - fn file_(suffix: &str) -> PathBuf { let name = format!("{}{}", APP_NAME, suffix); Self::path(name).with_extension("toml") @@ -645,10 +634,14 @@ impl Config { return CONFIG.read().unwrap().clone(); } - pub fn set(cfg: Config) { + pub fn set(cfg: Config) -> bool { let mut lock = CONFIG.write().unwrap(); + if *lock == cfg { + return false; + } *lock = cfg; lock.store(); + true } } diff --git a/src/ipc.rs b/src/ipc.rs index 600b35dc6..c120cc253 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -278,18 +278,8 @@ async fn handle(data: Data, stream: &mut Connection) { allow_err!(stream.send(&Data::Options(Some(v))).await); } Some(value) => { - let v0 = Config::get_option("stop-service"); - let v1 = Config::get_rendezvous_servers(); - let v2 = Config::get_option("audio-input"); + let _chk = CheckIfRestart::new(); Config::set_options(value); - if v0 != Config::get_option("stop-service") - || v1 != Config::get_rendezvous_servers() - { - RendezvousMediator::restart(); - } - if v2 != Config::get_option("audio-input") { - crate::audio_service::restart(); - } allow_err!(stream.send(&Data::Options(None)).await); } }, @@ -298,6 +288,7 @@ async fn handle(data: Data, stream: &mut Connection) { allow_err!(stream.send(&Data::NatType(Some(t))).await); } Data::SyncConfig(Some((config, config2))) => { + let _chk = CheckIfRestart::new(); Config::set(config); Config2::set(config2); allow_err!(stream.send(&Data::SyncConfig(None)).await); diff --git a/src/main.rs b/src/main.rs index 919e8732d..1e237b804 100644 --- a/src/main.rs +++ b/src/main.rs @@ -95,7 +95,7 @@ fn main() { } } else if args[0] == "--import-config" { if args.len() == 2 { - hbb_common::config::Config::import(&args[1]); + import_config(&args[1]); } return; } else if args[0] == "--password" { @@ -106,6 +106,31 @@ fn main() { } } ui::start(&mut args[..]); + _async_logger_holder.map(|x| x.flush()); +} + +fn import_config(path: &str) { + use hbb_common::{config::*, get_modified_time}; + let path2 = path.replace(".toml", "2.toml"); + let path2 = std::path::Path::new(&path2); + let path = std::path::Path::new(path); + log::info!("import config from {:?} and {:?}", path, path2); + let config: Config = load_path(path.into()); + if config.id.is_empty() || config.key_pair.0.is_empty() { + log::info!("Empty source config, skipped"); + return; + } + if get_modified_time(&path) > get_modified_time(&Config::file()) { + if Config::set(config) { + log::info!("config written"); + } + } + let config2: Config2 = load_path(path2.into()); + if get_modified_time(&path2) > get_modified_time(&Config2::file()) { + if Config2::set(config2) { + log::info!("config2 written"); + } + } } #[cfg(feature = "cli")] diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 306d025ee..abc24ba25 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -879,8 +879,6 @@ copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{start_menu}\\\" let meta = std::fs::symlink_metadata(std::env::current_exe()?)?; let size = meta.len() / 1024; - // save_tmp is for ensuring not copying file while writing - let config_path = Config::save_tmp(); let ext = APP_NAME.to_lowercase(); // https://docs.microsoft.com/zh-cn/windows/win32/msi/uninstall-registry-key?redirectedfrom=MSDNa // https://www.windowscentral.com/how-edit-registry-using-command-prompt-windows-10 @@ -927,8 +925,6 @@ sc stop {app_name} sc delete {app_name} sc create {app_name} binpath= \"\\\"{exe}\\\" --service\" start= auto DisplayName= \"{app_name} Service\" netsh advfirewall firewall add rule name=\"{app_name} Service\" dir=in action=allow program=\"{exe}\" enable=yes -del /f \"{config_path}\" -del /f \"{config2_path}\" sc start {app_name} ", path=path, @@ -946,8 +942,7 @@ sc start {app_name} tray_shortcut=tray_shortcut, tmp_path=tmp_path, shortcuts=shortcuts, - config_path=config_path, - config2_path=config_path.replace(".toml", "2.toml"), + config_path=Config::file().to_str().unwrap_or(""), ext=ext, ); run_cmds(cmds, false)?; diff --git a/src/server.rs b/src/server.rs index 2c3157449..55f4d6648 100644 --- a/src/server.rs +++ b/src/server.rs @@ -4,7 +4,7 @@ use hbb_common::{ allow_err, anyhow::{anyhow, Context}, bail, - config::{Config, CONNECT_TIMEOUT, RELAY_PORT}, + config::{Config, Config2, CONNECT_TIMEOUT, RELAY_PORT}, log, message_proto::*, protobuf::{Message as _, ProtobufEnum}, @@ -289,32 +289,18 @@ pub async fn start_server(is_server: bool, _tray: bool) { } else { match crate::ipc::connect(1000, "").await { Ok(mut conn) => { - allow_err!(conn.send(&Data::SystemInfo(None)).await); - if let Ok(Some(data)) = conn.next_timeout(1000).await { - log::info!("server info: {:?}", data); - } - // sync key pair - let mut n = 0; - loop { - if Config::get_key_confirmed() { - // check ipc::get_id(), key_confirmed may change, so give some chance to correct - n += 1; - if n > 3 { - break; - } else { - sleep(1.).await; - } - } else { - allow_err!(conn.send(&Data::ConfirmedKey(None)).await); - if let Ok(Some(Data::ConfirmedKey(Some(pair)))) = - conn.next_timeout(1000).await - { - Config::set_key_pair(pair); - Config::set_key_confirmed(true); - log::info!("key pair synced"); - break; - } else { - sleep(1.).await; + if conn.send(&Data::SyncConfig(None)).await.is_ok() { + if let Ok(Some(data)) = conn.next_timeout(1000).await { + match data { + Data::SyncConfig(Some((config, config2))) => { + if Config::set(config) { + log::info!("config synced"); + } + if Config2::set(config2) { + log::info!("config2 synced"); + } + } + _ => {} } } } @@ -333,7 +319,6 @@ async fn sync_and_watch_config_dir() { return; } - use hbb_common::config::Config2; let mut cfg0 = (Config::get(), Config2::get()); let mut synced = false; let tries =