rustpm 0.2.15

A fast, friendly APT frontend with kernel, desktop, and sources management
use anyhow::Result;
use crossterm::event::{self, Event, KeyEvent};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

use crate::apt::parser::PackageChange;
use crate::remote::server::RemoteEvent;

pub enum AppEvent {
    Key(KeyEvent),
    AptOutput(String),
    UpdatesRefreshed(Vec<PackageChange>),
    Remote(RemoteEvent),
    Tick,
}

pub struct EventHandler {
    rx: mpsc::Receiver<AppEvent>,
}

impl EventHandler {
    pub fn new(
        apt_rx: Option<mpsc::Receiver<String>>,
        refresh_rx: Option<mpsc::Receiver<Vec<PackageChange>>>,
        remote_rx: Option<mpsc::Receiver<RemoteEvent>>,
    ) -> Self {
        let (tx, rx) = mpsc::channel();

        let key_tx = tx.clone();
        thread::spawn(move || loop {
            if event::poll(Duration::from_millis(50)).unwrap_or(false) {
                if let Ok(Event::Key(key)) = event::read() {
                    if key_tx.send(AppEvent::Key(key)).is_err() {
                        break;
                    }
                }
            } else if key_tx.send(AppEvent::Tick).is_err() {
                break;
            }
        });

        if let Some(apt_rx) = apt_rx {
            let out_tx = tx.clone();
            thread::spawn(move || {
                for line in apt_rx {
                    if out_tx.send(AppEvent::AptOutput(line)).is_err() {
                        break;
                    }
                }
            });
        }

        if let Some(refresh_rx) = refresh_rx {
            let ref_tx = tx.clone();
            thread::spawn(move || {
                for changes in refresh_rx {
                    if ref_tx.send(AppEvent::UpdatesRefreshed(changes)).is_err() {
                        break;
                    }
                }
            });
        }

        if let Some(remote_rx) = remote_rx {
            let rem_tx = tx;
            thread::spawn(move || {
                for ev in remote_rx {
                    if rem_tx.send(AppEvent::Remote(ev)).is_err() {
                        break;
                    }
                }
            });
        }

        Self { rx }
    }

    pub fn next(&self) -> Result<AppEvent> {
        Ok(self.rx.recv()?)
    }
}