diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 26ddc4382..4f753f03d 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -70,4 +70,4 @@ rand = "0.8.5" custom-protocol = ["tauri/custom-protocol"] [package.metadata.cargo-machete] -ignored = ["log4rs", "xz2"] +ignored = ["log4rs", "xz2", "libsqlite3-sys", "minotari_wallet_grpc_client"] diff --git a/src-tauri/src/cpu_miner.rs b/src-tauri/src/cpu_miner.rs index 3d386c96f..4125fa768 100644 --- a/src-tauri/src/cpu_miner.rs +++ b/src-tauri/src/cpu_miner.rs @@ -151,11 +151,7 @@ impl CpuMiner { // Refresh CPUs again. s.refresh_cpu_all(); - let mut cpu_brand = "Unknown"; - for cpu in s.cpus() { - cpu_brand = cpu.brand(); - break; - } + let cpu_brand = s.cpus().get(0).map(|cpu| cpu.brand()).unwrap_or("Unknown"); let cpu_usage = s.global_cpu_usage() as u32; diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index a71475550..dbf0b538b 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -25,25 +25,43 @@ use crate::mm_proxy_manager::MmProxyManager; use crate::node_manager::NodeManager; use crate::wallet_adapter::WalletBalance; use crate::wallet_manager::WalletManager; -use dirs_next::data_dir; -use futures_util::{FutureExt, TryFutureExt}; +use futures_util::TryFutureExt; use log::{debug, error, info, warn}; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use std::sync::Arc; use std::thread::sleep; use std::{panic, process}; use tari_common_types::tari_address::TariAddress; use tari_core::transactions::tari_amount::MicroMinotari; use tari_shutdown::Shutdown; -use tauri::{api, RunEvent, UpdaterEvent}; +use tauri::{RunEvent, UpdaterEvent}; use tokio::sync::RwLock; -use tokio::{join, try_join}; +use tokio::try_join; + +use std::thread; +use std::time::Duration; + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct SetupStatusEvent { + event_type: String, + title: String, + progress: f64, +} #[tauri::command] -async fn init<'r>( +async fn setup_application<'r>( + window: tauri::Window, state: tauri::State<'r, UniverseAppState>, app: tauri::AppHandle, ) -> Result<(), String> { + let _ = window.emit( + "message", + SetupStatusEvent { + event_type: "setup_status".to_string(), + title: "Downloading Applications".to_string(), + progress: 0.5, + }, + ); let data_dir = app.path_resolver().app_local_data_dir().unwrap(); let task1 = state .node_manager @@ -62,6 +80,16 @@ async fn init<'r>( }); try_join!(task1, task2)?; + _ = window.emit( + "message", + SetupStatusEvent { + event_type: "setup_status".to_string(), + title: "Syncing Blockchain".to_string(), + progress: 1.0, + }, + ); + // TODO: Sync blockchain when p2p mining finished + thread::sleep(Duration::from_secs(5)); Ok(()) } @@ -293,7 +321,7 @@ fn main() { } }) .invoke_handler(tauri::generate_handler![ - init, + setup_application, status, start_mining, stop_mining diff --git a/src-tauri/src/minotari_node_adapter.rs b/src-tauri/src/minotari_node_adapter.rs index f11f8b2d1..2337eedcb 100644 --- a/src-tauri/src/minotari_node_adapter.rs +++ b/src-tauri/src/minotari_node_adapter.rs @@ -197,7 +197,7 @@ impl MinotariNodeStatusMonitor { }) .await?; let mut res = res.into_inner(); - while let Some(difficulty) = res.message().await? { + if let Some(difficulty) = res.message().await? { return Ok(( difficulty.sha3x_estimated_hash_rate, difficulty.randomx_estimated_hash_rate, diff --git a/src/App.tsx b/src/App.tsx index bbae085d6..5ada2b549 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -14,57 +14,66 @@ import useAppStateStore from './store/appStateStore'; import ErrorSnackbar from './containers/Error/ErrorSnackbar'; function App() { - const { - view, background, setHashRate, setCpuUsage, setAppState, setError, - setCpuBrand, setEstimatedEarnings, - setBlockHeight, setBlockTime, setIsSynced, setWallet - } = - useAppStateStore((state) => ({ - view: state.view, - background: state.background, - setHashRate: state.setHashRate, - setCpuUsage: state.setCpuUsage, - setAppState: state.setAppState, - setError: state.setError, - setCpuBrand: state.setCpuBrand, - setEstimatedEarnings: state.setEstimatedEarnings, - setBlockHeight: state.setBlockHeight, - setBlockTime: state.setBlockTime, - setIsSynced: state.setIsSynced, - setWallet: state.setWallet - })); + const { view, background, setHashRate, setCpuUsage, setAppState, setError, + setCpuBrand, setEstimatedEarnings, setBlockHeight, setBlockTime, setIsSynced, + settingUpFinished, setSetupDetails, setWallet + } = + useAppStateStore((state) => ({ + view: state.view, + background: state.background, + isSettingUp: state.isSettingUp, + setHashRate: state.setHashRate, + setCpuUsage: state.setCpuUsage, + setAppState: state.setAppState, + setError: state.setError, + setCpuBrand: state.setCpuBrand, + setEstimatedEarnings: state.setEstimatedEarnings, + settingUpFinished: state.settingUpFinished, + setSetupDetails: state.setSetupDetails, + setBlockHeight: state.setBlockHeight, + setBlockTime: state.setBlockTime, + setIsSynced: state.setIsSynced, + setWallet: state.setWallet, + })); - useEffect(() => { - invoke("init", {}).catch((e) => { - console.error('Could not init', e); - setError(e.toString()); - }); - const unlistenPromise = listen('message', (event) => { - console.log('some kind of event', event.event, event.payload); - }); + useEffect(() => { + const unlistenPromise = listen('message', ({ event, payload }: TauriEvent) => { + console.log('some kind of event', event, payload); + + switch (payload.event_type) { + case "setup_status": + setSetupDetails(payload.title, payload.progress); + break; + default: + console.log("Unknown tauri event: ", { event, payload }); + break; + } + }); - const intervalId = setInterval(() => { - invoke('status', {}) - .then((status: any) => { - console.log('Status', status); - setAppState(status); - setCpuUsage(status.cpu?.cpu_usage); - setHashRate(status.cpu?.hash_rate); - setCpuBrand(status.cpu?.cpu_brand); - setEstimatedEarnings(status.cpu?.estimated_earnings); - setBlockHeight(status.base_node?.block_height); - setBlockTime(status.base_node?.block_time); - setIsSynced(status.base_node?.is_synced); - setWallet({balance: status.wallet_balance?.available_balance + status.wallet_balance?.timelocked_balance + status.wallet_balance?.pending_incoming_balance}); - }) - .catch((e) => { - console.error('Could not get status', e); - setError(e.toString()); - }); + invoke('setup_application').then(() => settingUpFinished()); + + const intervalId = setInterval(() => { + invoke('status', {}) + .then((status: any) => { + console.log('Status', status); + setAppState(status); + setCpuUsage(status.cpu?.cpu_usage); + setHashRate(status.cpu?.hash_rate); + setCpuBrand(status.cpu?.cpu_brand); + setEstimatedEarnings(status.cpu?.estimated_earnings); + setBlockHeight(status.base_node?.block_height); + setBlockTime(status.base_node?.block_time); + setIsSynced(status.base_node?.is_synced); + setWallet({balance: status.wallet_balance?.available_balance + status.wallet_balance?.timelocked_balance + status.wallet_balance?.pending_incoming_balance}); + }) + .catch((e) => { + console.error('Could not get status', e); + setError(e.toString()); + }); }, 1000); return () => { - unlistenPromise.then((unlisten) => unlisten()); - clearInterval(intervalId); + unlistenPromise.then((unlisten) => unlisten()); + clearInterval(intervalId); }; }, []); diff --git a/src/containers/Dashboard/Dashboard.tsx b/src/containers/Dashboard/Dashboard.tsx index 754befdd5..2172cc02a 100644 --- a/src/containers/Dashboard/Dashboard.tsx +++ b/src/containers/Dashboard/Dashboard.tsx @@ -1,15 +1,15 @@ import { DashboardContainer } from './styles'; import MiningView from './MiningView/MiningView'; -import SetupView from './SetupView/SetupView'; import TribesView from './TribesView/TribesView'; import { viewType } from '../../store/types'; +import SetupViewContainer from './SetupView/SetupViewContainer'; function Dashboard({ status }: { status: viewType }) { let view = ; switch (status) { case 'setup': - view = ; + view = ; break; case 'tribes': view = ; diff --git a/src/containers/Dashboard/SetupView/SetupView.tsx b/src/containers/Dashboard/SetupView/SetupView.tsx index 1fcae309b..f525974fc 100644 --- a/src/containers/Dashboard/SetupView/SetupView.tsx +++ b/src/containers/Dashboard/SetupView/SetupView.tsx @@ -3,14 +3,13 @@ import { Stack, Typography } from '@mui/material'; import { StyledLinearProgress, ProgressBox } from '../styles'; import VisualMode from '../components/VisualMode'; -function SetupView() { - const progress = 30; +function SetupView({ title, progressPercentage }: { title: string, progressPercentage: number }) { return ( Setup - Setting up the Tari truth machine... + Setting up the Tari truth machine... This might take a few minutes. @@ -18,9 +17,9 @@ function SetupView() { Don’t worry you’ll only need to do this once. - + - {progress}% + {`${progressPercentage}% - ${title}`} diff --git a/src/containers/Dashboard/SetupView/SetupViewContainer.tsx b/src/containers/Dashboard/SetupView/SetupViewContainer.tsx new file mode 100644 index 000000000..86dc76045 --- /dev/null +++ b/src/containers/Dashboard/SetupView/SetupViewContainer.tsx @@ -0,0 +1,32 @@ +import { useEffect, useMemo } from "react"; +import useAppStateStore from "../../../store/appStateStore"; +import SetupView from "./SetupView"; + +let latestSetupProgress = 0; + +function SetupViewContainer() { + const { setupTitle, setupProgress } = useAppStateStore((state) => ({ + setupTitle: state.setupTitle, + setupProgress: state.setupProgress, + })); + const progressPercentage = useMemo( + () => Math.floor(latestSetupProgress * 100), + [latestSetupProgress] + ); + + useEffect(() => { + const progressInterval = setInterval(() => { + latestSetupProgress += (setupProgress - latestSetupProgress) * 0.25; + }, 500); + + return () => { + clearInterval(progressInterval); + }; + }, [setupProgress]); + + return ( + + ); +} + +export default SetupViewContainer; diff --git a/src/store/appStateStore.ts b/src/store/appStateStore.ts index 352510347..f580b9c7e 100644 --- a/src/store/appStateStore.ts +++ b/src/store/appStateStore.ts @@ -3,115 +3,137 @@ import {invoke} from '@tauri-apps/api/tauri'; import {viewType, backgroundType, modeType} from './types'; interface AppState { - appState: any; - setAppState: (value: any) => void; - error: string; - setError: (value: string) => void; - topStatus: string; - setTopStatus: (value: string) => void; - errorOpen: boolean; - setErrorOpen: (value: boolean) => void; + appState: any; + setAppState: (value: any) => void; + error: string; + setError: (value: string) => void; + topStatus: string; + setTopStatus: (value: string) => void; + errorOpen: boolean; + setErrorOpen: (value: boolean) => void; + setupTitle: string; + setupProgress: number; + setSetupDetails: (setupTitle: string, setupProgress: number) => void; - // gui - background: backgroundType; - setBackground: (value: backgroundType) => void; - view: viewType; - setView: (value: viewType) => void; - visualMode: boolean; - setVisualMode: (value: boolean) => void; - wallet: { - balance: number; - }; - setWallet: (value: { balance: number }) => void; - isMining: boolean; - setIsMining: (value: boolean) => void; - isAutoMining: boolean; - setIsAutoMining: (value: boolean) => void;sidebarOpen: boolean; - setSidebarOpen: (value: boolean) => void; + // gui + background: backgroundType; + setBackground: (value: backgroundType) => void; + view: viewType; + setView: (value: viewType) => void; + visualMode: boolean; + setVisualMode: (value: boolean) => void; + wallet: { + balance: number; + }; + setWallet: (value: { balance: number }) => void; + isMining: boolean; + setIsMining: (value: boolean) => void; + isAutoMining: boolean; + setIsAutoMining: (value: boolean) => void; + sidebarOpen: boolean; + setSidebarOpen: (value: boolean) => void; + isSettingUp: boolean; - // stats - cpuUsage: number; - setCpuUsage: (value: number) => void; - mode: modeType; - setMode: (value: modeType) => void; - hashRate: number; - setHashRate: (value: number) => void; - cpuBrand: string, - setCpuBrand: (value: string) => void; - estimatedEarnings: number, - setEstimatedEarnings: (value: number) => void; + // stats + cpuUsage: number; + setCpuUsage: (value: number) => void; + mode: modeType; + setMode: (value: modeType) => void; + hashRate: number; + setHashRate: (value: number) => void; + cpuBrand: string, + setCpuBrand: (value: string) => void; + estimatedEarnings: number, + setEstimatedEarnings: (value: number) => void; - blockHeight: number, - setBlockHeight: (value: number) => void; + blockHeight: number, + setBlockHeight: (value: number) => void; blockTime: number, - setBlockTime: (value: number) => void; + setBlockTime: (value: number) => void; isSynced: boolean, - setIsSynced: (value: boolean) => void;// functions - startMining: () => Promise; - stopMining: () => Promise; + setIsSynced: (value: boolean) => void; + // functions + startMining: () => Promise; + stopMining: () => Promise; + settingUpFinished: () => Promise; } const useAppStateStore = create((set) => ({ - appState: {}, - setAppState: (value) => set({appState: value}), - error: '', - setError: (value) => set({error: value}), - topStatus: 'Not mining', - setTopStatus: (value) => set({topStatus: value}), - errorOpen: false, - setErrorOpen: (value) => set({errorOpen: value}), + appState: {}, + setAppState: (value) => set({appState: value}), + error: '', + setError: (value) => set({error: value}), + topStatus: 'Not mining', + setTopStatus: (value) => set({topStatus: value}), + errorOpen: false, + setErrorOpen: (value) => set({errorOpen: value}), - // gui - background: 'idle', - setBackground: (value) => set({background: value}), - view: 'mining', - setView: (value) => set({view: value}), - visualMode: true, - setVisualMode: (value) => set({visualMode: value}), - wallet: { - balance: 0 - }, - setWallet: (value) => set({wallet: value}), - isMining: false, - setIsMining: (value) => set({isMining: value}), - isAutoMining: false, - setIsAutoMining: (value) => set({ isAutoMining: value }),sidebarOpen: false, - setSidebarOpen: (value) => set({sidebarOpen: value}), + // gui + background: 'loading', + setBackground: (value) => set({ background: value }), + view: 'setup', + setView: (value) => set({ view: value }), + visualMode: true, + setVisualMode: (value) => set({ visualMode: value }), + wallet: { + balance: 0, + }, + setWallet: (value) => set({ wallet: value }), + isMining: false, + setIsMining: (value) => set({ isMining: value }), + isAutoMining: false, + setIsAutoMining: (value) => set({ isAutoMining: value }), + sidebarOpen: false, + setSidebarOpen: (value) => set({ sidebarOpen: value }), + isSettingUp: true, + setupTitle: "", + setupProgress: 0, + setSetupDetails: (setupTitle: string, setupProgress: number) => set({ setupTitle, setupProgress }), - // stats - cpuUsage: 0, - setCpuUsage: (value) => set({cpuUsage: value}), - mode: 'eco', - setMode: (value) => set({mode: value}), - hashRate: 0, - setHashRate: (value) => set({hashRate: value}), - cpuBrand: '', - setCpuBrand: (value) => set({cpuBrand: value}), - estimatedEarnings: 0, - setEstimatedEarnings: (value) => set({estimatedEarnings: value}), + // stats + cpuUsage: 0, + setCpuUsage: (value) => set({cpuUsage: value}), + mode: 'eco', + setMode: (value) => set({mode: value}), + hashRate: 0, + setHashRate: (value) => set({hashRate: value}), + cpuBrand: '', + setCpuBrand: (value) => set({cpuBrand: value}), + estimatedEarnings: 0, + setEstimatedEarnings: (value) => set({estimatedEarnings: value}), - blockHeight: 0, - setBlockHeight: (value) => set({ blockHeight: value }), - blockTime: 0, - setBlockTime: (value) => set({ blockTime: value }), - isSynced: false, - setIsSynced: (value) => set({ isSynced: value }),// functions - startMining: async () => { - try { - await invoke('start_mining', {}); - console.log('Mining started'); - } catch (e) { - console.error('Could not start mining', e); - } - }, - stopMining: async () => { - try { - await invoke('stop_mining', {}); - console.log('Mining stopped'); - } catch (e) { - console.error('Could not stop mining', e); - } - }, + blockHeight: 0, + setBlockHeight: (value) => set({ blockHeight: value }), + blockTime: 0, + setBlockTime: (value) => set({ blockTime: value }), + isSynced: false, + setIsSynced: (value) => set({ isSynced: value }), + + // functions + settingUpFinished: async () => { + set({ + isSettingUp: false, + view: "mining", + background: "idle" + }); + }, + + startMining: async () => { + try { + await invoke('start_mining', {}); + console.log('Mining started'); + } catch (e) { + console.error('Could not start mining', e); + } + }, + stopMining: async () => { + try { + await invoke('stop_mining', {}); + console.log('Mining stopped'); + } catch (e) { + console.error('Could not stop mining', e); + } + }, })); export default useAppStateStore; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 000000000..910a7d18f --- /dev/null +++ b/src/types.ts @@ -0,0 +1,12 @@ +// Use union type +type TauriEventPayload = +| { + event_type: "setup_status", + title: string, + progress: number, +} + +type TauriEvent = { + event: string; + payload: TauriEventPayload; +}