diff --git a/src/gui/views/wallets/wallet/transport.rs b/src/gui/views/wallets/wallet/transport.rs index 65af4b2..ba8cde0 100644 --- a/src/gui/views/wallets/wallet/transport.rs +++ b/src/gui/views/wallets/wallet/transport.rs @@ -285,6 +285,19 @@ impl WalletTransport { let os = OperatingSystem::from_target_os(); let show_bridges = os != OperatingSystem::Android; + // Restart running service or rebuild client. + let restart_or_rebuild = || { + let service_id = &wallet.identifier(); + if Tor::is_service_running(service_id) { + if let Ok(key) = wallet.secret_key() { + let api_port = wallet.foreign_api_port().unwrap(); + Tor::restart_service(api_port, key, service_id); + } + } else { + Tor::rebuild_client(); + } + }; + ui.add_space(6.0); if show_bridges { let bridge = TorConfig::get_bridge(); @@ -304,14 +317,8 @@ impl WalletTransport { Some(b) }; TorConfig::save_bridge(value); - // Restart service. - if let Ok(key) = wallet.secret_key() { - let service_id = &wallet.identifier(); - Tor::stop_service(service_id); - Tor::rebuild_client(); - let api_port = wallet.foreign_api_port().unwrap(); - Tor::start_service(api_port, key, service_id); - } + // Restart running service or rebuild client. + restart_or_rebuild(); }); }); @@ -341,14 +348,8 @@ impl WalletTransport { if current_bridge != bridge { TorConfig::save_bridge(Some(bridge.clone())); self.bridge_bin_path_edit = bridge.binary_path(); - // Restart service. - if let Ok(key) = wallet.secret_key() { - let service_id = &wallet.identifier(); - Tor::stop_service(service_id); - Tor::rebuild_client(); - let api_port = wallet.foreign_api_port().unwrap(); - Tor::start_service(api_port, key, service_id); - } + // Restart running service or rebuild client. + restart_or_rebuild(); } // Draw binary path text edit. @@ -370,13 +371,8 @@ impl WalletTransport { } }; TorConfig::save_bridge(Some(b)); - // Restart service. - if let Ok(key) = wallet.secret_key() { - let service_id = &wallet.identifier(); - Tor::stop_service(service_id); - let api_port = wallet.foreign_api_port().unwrap(); - Tor::start_service(api_port, key, service_id); - } + // Restart running service or rebuild client. + restart_or_rebuild(); } ui.add_space(2.0); } diff --git a/src/tor/tor.rs b/src/tor/tor.rs index 1f8e9e6..687cb24 100644 --- a/src/tor/tor.rs +++ b/src/tor/tor.rs @@ -18,7 +18,6 @@ use std::sync::Arc; use std::thread; use std::time::Duration; use arti_client::config::pt::TransportConfigBuilder; -use grin_api::client; use lazy_static::lazy_static; use futures::task::SpawnExt; @@ -34,7 +33,7 @@ use sha2::Sha512; use tokio::time::sleep; use tor_config::CfgPath; use tor_rtcompat::tokio::TokioNativeTlsRuntime; -use tor_rtcompat::{BlockOn, Runtime}; +use tor_rtcompat::Runtime; use tor_hsrproxy::OnionServiceReverseProxy; use tor_hsrproxy::config::{Encapsulation, ProxyAction, ProxyPattern, ProxyRule, TargetAddr, ProxyConfigBuilder}; use tor_hsservice::config::OnionServiceConfigBuilder; @@ -115,7 +114,7 @@ impl Tor { .unwrap(), config) } - /// Recreate Tor client on configuration change. + /// Recreate Tor client. pub fn rebuild_client() { let client_config = Self::build_client(TokioNativeTlsRuntime::create().unwrap()); let mut w_client = TOR_SERVER_STATE.client_config.write(); @@ -182,6 +181,13 @@ impl Tor { r_services.contains(id) } + // Restart Onion service. + pub fn restart_service(port: u16, key: SecretKey, id: &String) { + Self::stop_service(id); + Self::rebuild_client(); + Self::start_service(port, key, id) + } + /// Stop running Onion service. pub fn stop_service(id: &String) { let mut w_services = TOR_SERVER_STATE.running_services.write(); @@ -237,9 +243,9 @@ impl Tor { } let url = format!("http://{}/v2/foreign", service.onion_name().unwrap().to_string()); thread::spawn(move || { - // Wait 5 seconds to start. - thread::sleep(Duration::from_millis(5000)); - let runtime = TokioNativeTlsRuntime::create().unwrap(); + // Wait 1 second to start. + thread::sleep(Duration::from_millis(1000)); + let runtime = client_thread.runtime(); let client_runtime = runtime.clone(); // Put service to checking. { @@ -248,9 +254,10 @@ impl Tor { } runtime .spawn(async move { + const MAX_ERRORS: i32 = 3; + let mut errors_count = 0; loop { - if !Self::is_service_running(&service_id) && - !Self::is_service_starting(&service_id) { + if !Self::is_service_running(&service_id) { // Remove service from checking. let mut w_services = TOR_SERVER_STATE.checking_services.write(); w_services.remove(&service_id); @@ -276,29 +283,37 @@ impl Tor { .body(Body::from(data)) .unwrap(); // Send request. - match http.request(req).await { - Ok(r) => { - match hyper::body::to_bytes(r).await { - Ok(_) => { - // Remove service from starting. - let mut w_services = TOR_SERVER_STATE.starting_services.write(); - w_services.remove(&service_id); - }, - Err(_) => { - // Put service to starting. - let mut w_services = TOR_SERVER_STATE.starting_services.write(); - w_services.insert(service_id.clone()); - }, - } + let duration = match http.request(req).await { + Ok(_) => { + // Remove service from starting. + let mut w_services = TOR_SERVER_STATE.starting_services.write(); + w_services.remove(&service_id); + // Check again after 5 seconds. + Duration::from_millis(5000) }, Err(_) => { - // Put service to starting. - let mut w_services = TOR_SERVER_STATE.starting_services.write(); - w_services.insert(service_id.clone()); + // Restart service on 3rd error. + let duration = if errors_count == MAX_ERRORS - 1 { + errors_count = 0; + let key = key.clone(); + let service_id = service_id.clone(); + let client_runtime = client_runtime.clone(); + thread::spawn(move || { + Self::stop_service(&service_id); + let client_config = Self::build_client(client_runtime); + let mut w_client = TOR_SERVER_STATE.client_config.write(); + *w_client = client_config; + Self::start_service(port, key, &service_id); + }); + Duration::from_millis(5000) + } else { + errors_count += 1; + Duration::from_millis(1000) + }; + duration }, - } - // Check once per 5 second. - sleep(Duration::from_millis(5000)).await; + }; + sleep(duration).await; } }).unwrap(); }); diff --git a/src/wallet/wallet.rs b/src/wallet/wallet.rs index fd8e84b..772deac 100644 --- a/src/wallet/wallet.rs +++ b/src/wallet/wallet.rs @@ -1047,31 +1047,6 @@ fn start_sync(mut wallet: Wallet) -> Thread { } } - // Start Foreign API listener if API server is not running. - let mut api_server_running = { - wallet.foreign_api_server.read().is_some() - }; - if !api_server_running && wallet.is_open() { - match start_api_server(&mut wallet) { - Ok(api_server) => { - let mut api_server_w = wallet.foreign_api_server.write(); - *api_server_w = Some(api_server); - api_server_running = true; - } - Err(_) => {} - } - } - - // Start Tor service if API server is running and wallet is open. - if wallet.auto_start_tor_listener() && wallet.is_open() && api_server_running && - !Tor::is_service_running(&wallet.identifier()) { - let r_foreign_api = wallet.foreign_api_server.read(); - let api = r_foreign_api.as_ref().unwrap(); - if let Ok(sec_key) = wallet.secret_key() { - Tor::start_service(api.1, sec_key, &wallet.identifier()); - } - } - // Scan outputs if repair is needed or sync data if there is no error. if !wallet.sync_error() { if wallet.is_repairing() { @@ -1093,8 +1068,38 @@ fn start_sync(mut wallet: Wallet) -> Thread { return; } - // Repeat after default or attempt delay if synchronization was not successful. + // Setup flag to check if sync was failed. let failed_sync = wallet.sync_error() || wallet.get_sync_attempts() != 0; + + // Start Foreign API server and Tor service only if first sync was successful. + if !failed_sync { + // Start Foreign API listener if API server is not running. + let mut api_server_running = { + wallet.foreign_api_server.read().is_some() + }; + if !api_server_running && wallet.is_open() { + match start_api_server(&mut wallet) { + Ok(api_server) => { + let mut api_server_w = wallet.foreign_api_server.write(); + *api_server_w = Some(api_server); + api_server_running = true; + } + Err(_) => {} + } + } + + // Start Tor service if API server is running and wallet is open. + if wallet.auto_start_tor_listener() && wallet.is_open() && api_server_running && + !Tor::is_service_running(&wallet.identifier()) { + let r_foreign_api = wallet.foreign_api_server.read(); + let api = r_foreign_api.as_ref().unwrap(); + if let Ok(sec_key) = wallet.secret_key() { + Tor::start_service(api.1, sec_key, &wallet.identifier()); + } + } + } + + // Repeat after default or attempt delay if synchronization was not successful. let delay = if failed_sync { ATTEMPT_DELAY } else {