selene-daemon 0.9.0-alpha.2

Official music player daemon for Selene
Documentation
use std::{
    sync::OnceLock,
    thread::{self, JoinHandle},
    time::Duration,
};

use crossbeam::channel::{self, Receiver, Sender};

use crate::{should_shutdown, shutdown};

static PROCESS_TX: OnceLock<Sender<ProcessRequest>> = OnceLock::new();
pub fn send_process_request(request: ProcessRequest) {
    PROCESS_TX.get().unwrap().send(request).unwrap();
}

mod extract;

pub(crate) enum ProcessRequest {
    Extract { callback: oneshot::Sender<bool> },
}

pub struct ProcessThread {
    rx: Receiver<ProcessRequest>,
}

impl ProcessThread {
    pub fn open() -> JoinHandle<()> {
        let (tx, rx) = channel::unbounded();
        PROCESS_TX.set(tx).expect("Process thread was opened twice");

        thread::spawn(move || {
            let processor = ProcessThread { rx };

            if let Err(err) = processor.run() {
                shutdown(format!("Process thread failed with error: {err}"));
            }
        })
    }

    pub fn run(self) -> anyhow::Result<()> {
        while !should_shutdown() {
            match self.rx.recv_timeout(Duration::from_secs(10)) {
                Ok(request) => self.process_request(request)?,
                Err(channel::RecvTimeoutError::Timeout) => continue,
                Err(err) => return Err(err.into()),
            }
        }

        Ok(())
    }

    pub fn process_request(&self, request: ProcessRequest) -> anyhow::Result<()> {
        match request {
            ProcessRequest::Extract { callback } => {
                let _ = callback.send(true);
                extract::extract()?;
            }
        }

        Ok(())
    }
}