kaspa_daemon/
lib.rs

1pub mod cpu_miner;
2pub mod error;
3pub mod imports;
4pub mod kaspad;
5pub mod result;
6
7use std::fmt::Display;
8
9use crate::imports::*;
10pub use crate::result::Result;
11pub use cpu_miner::{CpuMiner, CpuMinerConfig, CpuMinerCtl};
12pub use kaspad::{Kaspad, KaspadConfig, KaspadCtl};
13use workflow_core::runtime;
14use workflow_node::process::Event as ProcessEvent;
15use workflow_store::fs::*;
16
17pub static LOCATIONS: &[&str] = &[
18    "bin",
19    "../target/release",
20    "../target/debug",
21    "../../kaspa-cpu-miner/target/debug",
22    "../../kaspa-cpu-miner/target/release",
23    "bin/windows-x64",
24    "bin/linux-ia32",
25    "bin/linux-x64",
26    "bin/linux-arm64",
27    "bin/macos-x64",
28    "bin/macos-aarch64",
29];
30
31pub async fn locate_binaries(root: &str, name: &str) -> Result<Vec<PathBuf>> {
32    // log_info!("locating binaries in root: {root} name: {name}");
33
34    if !runtime::is_nw() && !runtime::is_node() && !runtime::is_native() {
35        return Err(Error::Platform);
36    }
37
38    let name = if runtime::is_windows() { name.to_string() + ".exe" } else { name.to_string() };
39
40    let locations = LOCATIONS
41        .iter()
42        .map(|path| PathBuf::from(&root).join(path).join(&name).normalize().map_err(|e| e.into()))
43        .collect::<Result<Vec<_>>>()?;
44
45    let mut list = Vec::new();
46    for path in locations {
47        if exists(&path).await? {
48            list.push(path);
49        }
50    }
51
52    Ok(list)
53}
54
55#[derive(Debug, Clone, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
56pub enum DaemonKind {
57    Kaspad,
58    CpuMiner,
59}
60
61#[derive(Default)]
62pub struct Daemons {
63    pub kaspad: Option<Arc<dyn KaspadCtl + Send + Sync + 'static>>,
64    // pub kaspad_automute : Arc<
65    pub cpu_miner: Option<Arc<dyn CpuMinerCtl + Send + Sync + 'static>>,
66}
67
68impl Daemons {
69    pub fn new() -> Self {
70        Self { kaspad: None, cpu_miner: None }
71    }
72
73    pub fn with_kaspad(mut self, kaspad: Arc<dyn KaspadCtl + Send + Sync + 'static>) -> Self {
74        self.kaspad = Some(kaspad);
75        self
76    }
77
78    pub fn with_cpu_miner(mut self, cpu_miner: Arc<dyn CpuMinerCtl + Send + Sync + 'static>) -> Self {
79        self.cpu_miner = Some(cpu_miner);
80        self
81    }
82
83    pub fn kaspad(&self) -> Arc<dyn KaspadCtl + Send + Sync + 'static> {
84        self.kaspad.as_ref().expect("accessing Daemons::kaspad while kaspad option is None").clone()
85    }
86
87    pub fn try_kaspad(&self) -> Option<Arc<dyn KaspadCtl + Send + Sync + 'static>> {
88        self.kaspad.clone()
89    }
90
91    pub fn cpu_miner(&self) -> Arc<dyn CpuMinerCtl + Send + Sync + 'static> {
92        self.cpu_miner.as_ref().expect("accessing Daemons::cpu_miner while cpu_miner option is None").clone()
93    }
94
95    pub fn try_cpu_miner(&self) -> Option<Arc<dyn CpuMinerCtl + Send + Sync + 'static>> {
96        self.cpu_miner.clone()
97    }
98}
99
100#[derive(Debug, Clone, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
101pub struct DaemonEvent {
102    pub kind: DaemonKind,
103    pub inner: ProcessEvent,
104}
105
106impl DaemonEvent {
107    pub fn new(kind: DaemonKind, inner: ProcessEvent) -> Self {
108        Self { kind, inner }
109    }
110
111    pub fn kind(&self) -> &DaemonKind {
112        &self.kind
113    }
114}
115
116impl From<DaemonEvent> for ProcessEvent {
117    fn from(event: DaemonEvent) -> Self {
118        event.inner
119    }
120}
121
122#[derive(Debug, Clone, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
123pub struct DaemonStatus {
124    pub uptime: Option<u64>,
125}
126
127impl Display for DaemonStatus {
128    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129        if let Some(uptime) = self.uptime {
130            write!(f, "running - uptime: {}", format_duration(uptime))?;
131        } else {
132            write!(f, "not running")?;
133        }
134        Ok(())
135    }
136}
137
138fn format_duration(seconds: u64) -> String {
139    let days = seconds / (24 * 60 * 60);
140    let hours = (seconds / (60 * 60)) % 24;
141    let minutes = (seconds / 60) % 60;
142    let seconds = seconds % 60;
143
144    if days > 0 {
145        format!("{0} days {1:02} hours, {2:02} minutes, {3:02} seconds", days, hours, minutes, seconds)
146    } else {
147        format!("{0:02} hours, {1:02} minutes, {2:02} seconds", hours, minutes, seconds)
148    }
149}