crabtop 0.1.0

Terminal-based Linux system monitor with CPU, memory, GPU and thermal metrics
use std::sync::Arc;
use std::time::Duration;

use tokio::sync::RwLock;
use tokio::task::JoinHandle;

use crate::config::Config;
use crate::metrics::{Collectors, Histories, Snapshot};

pub struct AppState {
    pub snapshot: Snapshot,
    pub history: Histories,
    pub config: Config,
    pub paused: bool,
}

impl AppState {
    pub fn new(config: Config) -> Self {
        let history = Histories::new(config.history);
        Self {
            snapshot: Snapshot::default(),
            history,
            config,
            paused: false,
        }
    }
}

pub type SharedState = Arc<RwLock<AppState>>;

pub fn spawn_poller(state: SharedState) -> JoinHandle<()> {
    tokio::task::spawn_blocking(move || {
        let mut collectors = Collectors::new();
        let rt = tokio::runtime::Handle::current();

        let initial_interval = rt.block_on(async {
            let s = state.read().await;
            s.config.interval
        });
        std::thread::sleep(initial_interval);

        loop {
            let (interval, paused) = rt.block_on(async {
                let s = state.read().await;
                (s.config.interval, s.paused)
            });

            if !paused {
                collectors.refresh();
                let snap = Snapshot {
                    cpu: collectors.cpu(),
                    mem: collectors.mem(),
                    temp: collectors.temp(),
                    gpus: collectors.gpu(),
                };

                rt.block_on(async {
                    let mut s = state.write().await;
                    s.history.push(&snap);
                    s.snapshot = snap;
                });
            }

            std::thread::sleep(interval);
        }
    })
}

pub fn render_interval() -> Duration {
    Duration::from_millis(100)
}