diff --git a/src-tauri/src/analytics.rs b/src-tauri/src/analytics.rs deleted file mode 100644 index 0d11f57a5..000000000 --- a/src-tauri/src/analytics.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::sync::Arc; - -use tokio::sync::RwLock; - -use crate::app_config::{self, AppConfig, MiningMode}; - -pub struct AnalyticsManager { - config: Arc>, -} - -impl AnalyticsManager { - pub fn new(config: Arc>) -> Self { - Self { config } - } - - pub async fn get_unique_string(&self) -> String { - let config = self.config.read().await; - if !config.allow_analytics { - return "".to_string(); - } - let os = std::env::consts::OS; - let anon_id = config.anon_id.clone(); - let version = env!("CARGO_PKG_VERSION"); - let mode = MiningMode::to_str(config.mode.clone()); - let auto_mining = config.auto_mining; - let unique_string = format!("v0,{},{},{},{},{}", anon_id, mode, auto_mining, os, version,); - unique_string - } -} diff --git a/src-tauri/src/app_config.rs b/src-tauri/src/app_config.rs index 43e1d8866..dc21535d5 100644 --- a/src-tauri/src/app_config.rs +++ b/src-tauri/src/app_config.rs @@ -18,10 +18,8 @@ pub struct AppConfigFromFile { pub auto_mining: bool, pub user_inactivity_timeout: Duration, pub last_binaries_update_timestamp: SystemTime, - pub allow_analytics: bool, + pub allow_telemetry: bool, pub anon_id: String, - pub telemetry_collection: bool, - pub airdrop_user_refresh_token: Option, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] @@ -55,10 +53,8 @@ pub struct AppConfig { pub auto_mining: bool, pub user_inactivity_timeout: Duration, pub last_binaries_update_timestamp: SystemTime, - pub allow_analytics: bool, + pub allow_telemetry: bool, pub anon_id: String, - pub telemetry_collection: bool, - pub airdrop_user_refresh_token: Option, } impl AppConfig { @@ -70,10 +66,8 @@ impl AppConfig { auto_mining: false, user_inactivity_timeout: Duration::from_secs(60), last_binaries_update_timestamp: SystemTime::now(), - allow_analytics: true, + allow_telemetry: true, anon_id: generate_password(20), - telemetry_collection: true, - airdrop_user_refresh_token: None, } } @@ -90,17 +84,15 @@ impl AppConfig { self.auto_mining = config.auto_mining; self.user_inactivity_timeout = config.user_inactivity_timeout; self.last_binaries_update_timestamp = config.last_binaries_update_timestamp; - self.allow_analytics = config.allow_analytics; + self.allow_telemetry = config.allow_telemetry; self.anon_id = config.anon_id; self.version = config.version; if self.version == 0 { // migrate self.version = 1; - self.allow_analytics = true; + self.allow_telemetry = true; self.anon_id = generate_password(20); } - self.telemetry_collection = config.telemetry_collection; - self.airdrop_user_refresh_token = config.airdrop_user_refresh_token; } Err(e) => { warn!(target: LOG_TARGET, "Failed to parse app config: {}", e.to_string()); @@ -114,10 +106,8 @@ impl AppConfig { user_inactivity_timeout: self.user_inactivity_timeout, last_binaries_update_timestamp: self.last_binaries_update_timestamp, version: self.version, - allow_analytics: self.allow_analytics, + allow_telemetry: self.allow_telemetry, anon_id: self.anon_id.clone(), - telemetry_collection: true, - airdrop_user_refresh_token: None, }; let config = serde_json::to_string(&config)?; fs::write(file, config).await?; @@ -149,30 +139,17 @@ impl AppConfig { self.auto_mining } - pub async fn set_telemetry_collection( + pub async fn set_allow_telemetry( &mut self, - telemetry_collection: bool, + allow_telemetry: bool, ) -> Result<(), anyhow::Error> { - self.telemetry_collection = telemetry_collection; + self.allow_telemetry = allow_telemetry; self.update_config_file().await?; Ok(()) } - pub fn get_telemetry_collection(&self) -> bool { - self.telemetry_collection - } - - pub async fn set_airdrop_user_refresh_token( - &mut self, - airdrop_user_refresh_token: Option, - ) -> Result<(), anyhow::Error> { - self.airdrop_user_refresh_token = airdrop_user_refresh_token; - self.update_config_file().await?; - Ok(()) - } - - pub fn get_airdrop_user_refresh_token(&self) -> Option { - self.airdrop_user_refresh_token.clone() + pub fn get_allow_telemetry(&self) -> bool { + self.allow_telemetry } pub fn get_user_inactivity_timeout(&self) -> Duration { @@ -209,10 +186,8 @@ impl AppConfig { user_inactivity_timeout: self.user_inactivity_timeout, last_binaries_update_timestamp: self.last_binaries_update_timestamp, version: self.version, - allow_analytics: self.allow_analytics, + allow_telemetry: self.allow_telemetry, anon_id: self.anon_id.clone(), - telemetry_collection: self.telemetry_collection, - airdrop_user_refresh_token: self.airdrop_user_refresh_token.clone(), }; let config = serde_json::to_string(config)?; info!(target: LOG_TARGET, "Updating config file: {:?} {:?}", file, self.clone()); diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 8436ff781..c6901ef29 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,7 +1,6 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] -mod analytics; mod app_config; mod binary_resolver; mod consts; @@ -36,7 +35,6 @@ use crate::user_listener::UserListener; use crate::wallet_adapter::WalletBalance; use crate::wallet_manager::WalletManager; use crate::xmrig_adapter::XmrigAdapter; -use analytics::AnalyticsManager; use app_config::{AppConfig, MiningMode}; use binary_resolver::{Binaries, BinaryResolver}; use hardware_monitor::{HardwareMonitor, HardwareStatus}; @@ -110,7 +108,7 @@ async fn set_telemetry_mode<'r>( .config .write() .await - .set_telemetry_collection(telemetry_mode) + .set_allow_telemetry(telemetry_mode) .await .map_err(|e| e.to_string()); Ok(()) @@ -278,10 +276,16 @@ async fn setup_inner<'r>( let base_node_grpc_port = state.node_manager.get_grpc_port().await?; - let mut analytics_id = state.analytics_manager.get_unique_string().await; - if analytics_id.is_empty() { - analytics_id = "unknown_miner_tari_universe".to_string(); + let mut telemetry_id = state + .telemetry_manager + .read() + .await + .get_unique_string() + .await; + if telemetry_id.is_empty() { + telemetry_id = "unknown_miner_tari_universe".to_string(); } + mm_proxy_manager .start( state.shutdown.to_signal().clone(), @@ -289,7 +293,7 @@ async fn setup_inner<'r>( app.path_resolver().app_log_dir().unwrap().clone(), cpu_miner_config.tari_address.clone(), base_node_grpc_port, - analytics_id, + telemetry_id, ) .await?; mm_proxy_manager.wait_ready().await?; @@ -606,7 +610,6 @@ struct UniverseAppState { mm_proxy_manager: MmProxyManager, node_manager: NodeManager, wallet_manager: WalletManager, - analytics_manager: AnalyticsManager, telemetry_manager: Arc>, airdrop_access_token: Arc>>, } @@ -638,7 +641,6 @@ fn main() { })); let app_config = Arc::new(RwLock::new(AppConfig::new())); - let analytics = AnalyticsManager::new(app_config.clone()); let cpu_miner: Arc> = Arc::new(CpuMiner::new().into()); let gpu_miner: Arc> = Arc::new(GpuMiner::new().into()); @@ -661,7 +663,6 @@ fn main() { mm_proxy_manager: mm_proxy_manager.clone(), node_manager, wallet_manager, - analytics_manager: analytics, telemetry_manager: Arc::new(RwLock::new(telemetry_manager)), airdrop_access_token: Arc::new(RwLock::new(None)), }; diff --git a/src-tauri/src/mm_proxy_adapter.rs b/src-tauri/src/mm_proxy_adapter.rs index 4609d4acd..c7000d608 100644 --- a/src-tauri/src/mm_proxy_adapter.rs +++ b/src-tauri/src/mm_proxy_adapter.rs @@ -1,5 +1,4 @@ use crate::binary_resolver::{Binaries, BinaryResolver}; -use crate::consts::PROCESS_CREATION_NO_WINDOW; use crate::process_adapter::{ProcessAdapter, ProcessInstance, StatusMonitor}; use crate::process_utils; use anyhow::Error; @@ -71,12 +70,7 @@ impl ProcessAdapter for MergeMiningProxyAdapter { .resolve_path(Binaries::MergeMiningProxy) .await?; crate::download_utils::set_permissions(&file_path).await?; - let mut child = tokio::process::Command::new(file_path) - .args(args) - .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .kill_on_drop(true) - .spawn()?; + let mut child = process_utils::launch_child_process(&file_path, &args)?; if let Some(id) = child.id() { fs::write(data_dir.join("mmproxy_pid"), id.to_string())?; diff --git a/src-tauri/src/node_adapter.rs b/src-tauri/src/node_adapter.rs index 33430ec69..7e06a4499 100644 --- a/src-tauri/src/node_adapter.rs +++ b/src-tauri/src/node_adapter.rs @@ -97,12 +97,7 @@ impl ProcessAdapter for MinotariNodeAdapter { .resolve_path(Binaries::MinotariNode) .await?; crate::download_utils::set_permissions(&file_path).await?; - let mut child = tokio::process::Command::new(file_path) - .args(args) - .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .kill_on_drop(true) - .spawn()?; + let mut child = process_utils::launch_child_process(&file_path, &args)?; if let Some(id) = child.id() { fs::write(data_dir.join("node_pid"), id.to_string())?; diff --git a/src-tauri/src/telemetry_manager.rs b/src-tauri/src/telemetry_manager.rs index cc7a64f12..d3b5dda9f 100644 --- a/src-tauri/src/telemetry_manager.rs +++ b/src-tauri/src/telemetry_manager.rs @@ -1,6 +1,6 @@ use anyhow::Result; use jsonwebtoken::errors::Error as JwtError; -use jsonwebtoken::{decode, Algorithm, DecodingKey, TokenData, Validation}; +use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; use log::{debug, error, info, warn}; use serde::{Deserialize, Serialize}; use std::{sync::Arc, thread::sleep, time::Duration}; @@ -15,9 +15,10 @@ use crate::{ gpu_miner::GpuMiner, hardware_monitor::HardwareMonitor, node_manager::NodeManager, - UniverseAppState, LOG_TARGET, }; +const LOG_TARGET: &str = "tari::universe::telemetry_manager"; + #[derive(Debug, Deserialize, Serialize)] struct AirdropAccessToken { exp: u64, @@ -38,26 +39,18 @@ pub enum TelemetryResource { } #[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] pub enum TelemetryNetwork { - #[serde(rename(serialize = "mainnet"))] - Main, - #[serde(rename(serialize = "stagenet"))] - Stage, - #[serde(rename(serialize = "nextnet"))] - Next, - #[serde(rename(serialize = "localnet"))] - Local, - #[serde(rename(serialize = "igor"))] + MainNet, + StageNet, + NextNet, + LocalNet, Igor, - #[serde(rename(serialize = "esmeralda"))] Esmeralda, } #[derive(Debug, thiserror::Error)] pub enum TelemetryManagerError { - #[error("telemetry data could not be sent because of an error: {0}")] - ReqwestError(#[from] reqwest::Error), - #[error("Other error: {0}")] Other(#[from] anyhow::Error), @@ -68,10 +61,10 @@ pub enum TelemetryManagerError { impl From for TelemetryNetwork { fn from(value: Network) -> Self { match value { - Network::MainNet => TelemetryNetwork::Main, - Network::StageNet => TelemetryNetwork::Stage, - Network::NextNet => TelemetryNetwork::Next, - Network::LocalNet => TelemetryNetwork::Local, + Network::MainNet => TelemetryNetwork::MainNet, + Network::StageNet => TelemetryNetwork::StageNet, + Network::NextNet => TelemetryNetwork::NextNet, + Network::LocalNet => TelemetryNetwork::LocalNet, Network::Igor => TelemetryNetwork::Igor, Network::Esmeralda => TelemetryNetwork::Esmeralda, } @@ -117,7 +110,6 @@ pub struct TelemetryManager { gpu_miner: Arc>, config: Arc>, pub cancellation_token: CancellationToken, - pub is_collecting_telemetry: bool, node_network: Option, } @@ -136,11 +128,24 @@ impl TelemetryManager { gpu_miner, config, cancellation_token, - is_collecting_telemetry: false, node_network: network, } } + pub async fn get_unique_string(&self) -> String { + let config = self.config.read().await; + if !config.allow_telemetry { + return "".to_string(); + } + let os = std::env::consts::OS; + let anon_id = config.anon_id.clone(); + let version = env!("CARGO_PKG_VERSION"); + let mode = MiningMode::to_str(config.mode.clone()); + let auto_mining = config.auto_mining; + let unique_string = format!("v0,{},{},{},{},{}", anon_id, mode, auto_mining, os, version,); + unique_string + } + pub fn update_network(&mut self, network: Option) { self.node_network = network; } @@ -149,9 +154,7 @@ impl TelemetryManager { &mut self, airdrop_access_token: Arc>>, ) -> Result<()> { - info!("Starting telemetry manager"); - let telemetry_collection_enabled = self.config.read().await.telemetry_collection; - self.is_collecting_telemetry = telemetry_collection_enabled; + info!(target: LOG_TARGET, "Starting telemetry manager"); let _ = self .start_telemetry_process(Duration::from_secs(60), airdrop_access_token) .await; @@ -174,47 +177,19 @@ impl TelemetryManager { tokio::spawn(async move { tokio::select! { _ = async { - info!("TelemetryManager::start_telemetry_process has been started"); + info!(target: LOG_TARGET, "TelemetryManager::start_telemetry_process has been started"); loop { - let telemetry_collection_enabled = config_cloned.read().await.telemetry_collection; - - let airdrop_access_token_internal = airdrop_access_token.read().await.clone(); - let airdrop_access_token_validated = airdrop_access_token_internal.clone().and_then(|t| { - let key = DecodingKey::from_secret(&[]); - let mut validation = Validation::new(Algorithm::HS256); - validation.insecure_disable_signature_validation(); - - let claims = match decode::(&t, &key, &validation) { - Ok(data) => Some(data.claims), - Err(e) => { - warn!("Error decoding access token: {:?}", e); - None - } - }; - - let now = std::time::SystemTime::now(); - let now_unix = now.duration_since(std::time::UNIX_EPOCH).unwrap_or_default().as_secs(); - - if let Some(claims) = claims { - if claims.exp < now_unix { - warn!("Access token has expired"); - None - } else { - Some(t) - } - } else { - None - } - }); + let telemetry_collection_enabled = config_cloned.read().await.allow_telemetry; if telemetry_collection_enabled { + let airdrop_access_token_validated = validate_jwt(airdrop_access_token.clone()).await; let telemetry = get_telemetry_data(cpu_miner.clone(), gpu_miner.clone(), node_manager.clone(), config.clone(), network).await; match telemetry { Ok(telemetry) => { send_telemetry_data(telemetry, airdrop_access_token_validated).await; }, Err(e) => { - error!("Error getting telemetry data: {:?}", e); + error!(target: LOG_TARGET,"Error getting telemetry data: {:?}", e); } } } @@ -222,7 +197,7 @@ impl TelemetryManager { } } => {}, _ = cancellation_token.cancelled() => { - info!("TelemetryManager::start_telemetry_process has been cancelled"); + info!(target: LOG_TARGET,"TelemetryManager::start_telemetry_process has been cancelled"); } } }); @@ -230,6 +205,40 @@ impl TelemetryManager { } } +async fn validate_jwt(airdrop_access_token: Arc>>) -> Option { + let airdrop_access_token_internal = airdrop_access_token.read().await.clone(); + airdrop_access_token_internal.clone().and_then(|t| { + let key = DecodingKey::from_secret(&[]); + let mut validation = Validation::new(Algorithm::HS256); + validation.insecure_disable_signature_validation(); + + let claims = match decode::(&t, &key, &validation) { + Ok(data) => Some(data.claims), + Err(e) => { + warn!(target: LOG_TARGET,"Error decoding access token: {:?}", e); + None + } + }; + + let now = std::time::SystemTime::now(); + let now_unix = now + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_secs(); + + if let Some(claims) = claims { + if claims.exp < now_unix { + warn!(target: LOG_TARGET,"Access token has expired"); + None + } else { + Some(t) + } + } else { + None + } + }) +} + async fn get_telemetry_data( cpu_miner: Arc>, _gpu_miner: Arc>, @@ -290,7 +299,7 @@ fn get_airdrop_url() -> String { } async fn send_telemetry_data(data: TelemetryData, airdrop_access_token: Option) { - debug!("Telemetry data being sent: {:?}", data); + debug!(target:LOG_TARGET, "Telemetry data being sent: {:?}", data); let request = reqwest::Client::new(); let mut request_builder = request @@ -301,21 +310,18 @@ async fn send_telemetry_data(data: TelemetryData, airdrop_access_token: Option { if response.status().is_success() { - info!("Telemetry data sent"); + info!(target: LOG_TARGET,"Telemetry data sent"); } else { - warn!("Error sending telemetry data: {:#?}", response); + warn!(target: LOG_TARGET,"Error sending telemetry data: {:#?}", response); } } Err(e) => { - error!("Error sending telemetry data: {:#?}", e); + error!(target: LOG_TARGET,"Error sending telemetry data: {:#?}", e); } } } diff --git a/src-tauri/src/wallet_adapter.rs b/src-tauri/src/wallet_adapter.rs index e4356b6b4..245e9e02a 100644 --- a/src-tauri/src/wallet_adapter.rs +++ b/src-tauri/src/wallet_adapter.rs @@ -108,12 +108,7 @@ impl ProcessAdapter for WalletAdapter { .resolve_path(Binaries::Wallet) .await?; crate::download_utils::set_permissions(&file_path).await?; - let mut child = tokio::process::Command::new(file_path) - .args(args) - .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .kill_on_drop(true) - .spawn()?; + let mut child = process_utils::launch_child_process(&file_path, &args)?; if let Some(id) = child.id() { std::fs::write(data_dir.join("wallet_pid"), id.to_string())?; diff --git a/src-tauri/src/xmrig_adapter.rs b/src-tauri/src/xmrig_adapter.rs index 6745407d5..82392288b 100644 --- a/src-tauri/src/xmrig_adapter.rs +++ b/src-tauri/src/xmrig_adapter.rs @@ -163,12 +163,7 @@ impl ProcessAdapter for XmrigAdapter { .join(&version) .join(format!("xmrig-{}", version)); let xmrig_bin = xmrig_dir.join("xmrig"); - let mut xmrig = tokio::process::Command::new(xmrig_bin) - .args(args) - .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .kill_on_drop(true) - .spawn()?; + let mut xmrig = process_utils::launch_child_process(&xmrig_bin, &args)?; if let Some(id) = xmrig.id() { std::fs::write(data_dir.join("xmrig_pid"), id.to_string())?;