diff --git a/music-player/server/src/core.rs b/music-player/server/src/core.rs index a6eb170..60f614c 100644 --- a/music-player/server/src/core.rs +++ b/music-player/server/src/core.rs @@ -15,20 +15,6 @@ use std::{ time::{Duration, Instant}, }; -#[derive(Debug, Error)] -pub enum ScannerError { - #[error("Cannot scan {0}")] - CannotScan(PathBuf), - #[error("IO error {0}")] - IO(std::io::Error), -} - -impl From for ScannerError { - fn from(err: std::io::Error) -> Self { - Self::IO(err) - } -} - pub enum ControlMsg { Exit, } @@ -53,87 +39,6 @@ pub struct Core { control_tx: Sender, } -fn scan_frequency() -> Duration { - Duration::from_secs(60) -} - -pub struct FileScanner { - db: Arc, - control_rx: Receiver, - tracker_tx: Sender, - next_scan: Instant, - music_directories: Vec, -} - -impl FileScanner { - fn new( - db: Arc, - roots: Vec, - control_rx: Receiver, - tracker_tx: Sender, - ) -> Self { - Self { - db, - control_rx, - tracker_tx, - next_scan: Instant::now(), - music_directories: roots, - } - } - - fn scan(&mut self) { - loop { - match self.control_rx.recv_timeout(Duration::from_millis(100)) { - Ok(ControlMsg::Exit) => return, - Err(RecvTimeoutError::Timeout) => (), - Err(RecvTimeoutError::Disconnected) => return, - } - if Instant::now() >= self.next_scan { - for root in self.music_directories.iter() { - self.scan_dir(vec![root.clone()]); - } - self.next_scan = Instant::now() + scan_frequency(); - } - } - } - - fn scan_dir(&self, mut paths: Vec) -> Flow<(), FatalError, ScannerError> { - while let Some(dir) = paths.pop() { - println!("scanning {:?}", dir); - return_error!(self.scan_dir_(&mut paths, dir)); - } - ok(()) - } - - fn scan_dir_( - &self, - paths: &mut Vec, - dir: PathBuf, - ) -> Flow<(), FatalError, ScannerError> { - let dir_iter = return_error!(Flow::from(dir.read_dir().map_err(ScannerError::from))); - for entry in dir_iter { - match entry { - Ok(entry) if entry.path().is_dir() => paths.push(entry.path()), - Ok(entry) => { - let _ = return_fatal!(self.scan_file(entry.path()).or_else(|err| { - println!("scan_file failed: {:?}", err); - ok::<(), FatalError, ScannerError>(()) - })); - () - } - Err(err) => { - println!("scan_dir could not read path: ({:?})", err); - } - } - } - ok(()) - } - - fn scan_file(&self, path: PathBuf) -> Flow<(), FatalError, ScannerError> { - ok(()) - } -} - impl Core { pub fn new(db: Arc) -> Flow { let (control_tx, control_rx) = channel::(); @@ -141,15 +46,7 @@ impl Core { let (track_handle, track_rx) = { let (track_tx, track_rx) = channel(); let db = db.clone(); - let track_handle = thread::spawn(move || { - FileScanner::new( - db, - vec![PathBuf::from("/home/savanni/Music/")], - control_rx, - track_tx, - ) - .scan(); - }); + let track_handle = thread::spawn(move || {}); (track_handle, track_rx) }; diff --git a/music-player/server/src/lib.rs b/music-player/server/src/lib.rs index 4d885c6..cbf09e5 100644 --- a/music-player/server/src/lib.rs +++ b/music-player/server/src/lib.rs @@ -1,6 +1,7 @@ pub mod audio; pub mod core; pub mod database; +pub mod music_scanner; use database::DatabaseError; use thiserror::Error; diff --git a/music-player/server/src/music_scanner.rs b/music-player/server/src/music_scanner.rs new file mode 100644 index 0000000..d22480e --- /dev/null +++ b/music-player/server/src/music_scanner.rs @@ -0,0 +1,114 @@ +use crate::{ + core::{ControlMsg, TrackMsg}, + database::MusicIndex, + FatalError, +}; +use flow::{ok, return_error, return_fatal, Flow}; +use std::{ + path::PathBuf, + sync::{ + mpsc::{Receiver, RecvTimeoutError, Sender}, + Arc, + }, + time::{Duration, Instant}, +}; +use thiserror::Error; + +fn scan_frequency() -> Duration { + Duration::from_secs(60) +} + +#[derive(Debug, Error)] +pub enum ScannerError { + #[error("Cannot scan {0}")] + CannotScan(PathBuf), + #[error("IO error {0}")] + IO(std::io::Error), +} + +impl From for ScannerError { + fn from(err: std::io::Error) -> Self { + Self::IO(err) + } +} + +pub trait MusicScanner { + fn scan(&self); +} + +pub struct FileScanner { + db: Arc, + control_rx: Receiver, + tracker_tx: Sender, + next_scan: Instant, + music_directories: Vec, +} + +impl FileScanner { + fn new( + db: Arc, + roots: Vec, + control_rx: Receiver, + tracker_tx: Sender, + ) -> Self { + Self { + db, + control_rx, + tracker_tx, + next_scan: Instant::now(), + music_directories: roots, + } + } + + fn scan(&mut self) { + loop { + match self.control_rx.recv_timeout(Duration::from_millis(100)) { + Ok(ControlMsg::Exit) => return, + Err(RecvTimeoutError::Timeout) => (), + Err(RecvTimeoutError::Disconnected) => return, + } + if Instant::now() >= self.next_scan { + for root in self.music_directories.iter() { + self.scan_dir(vec![root.clone()]); + } + self.next_scan = Instant::now() + scan_frequency(); + } + } + } + + fn scan_dir(&self, mut paths: Vec) -> Flow<(), FatalError, ScannerError> { + while let Some(dir) = paths.pop() { + println!("scanning {:?}", dir); + return_error!(self.scan_dir_(&mut paths, dir)); + } + ok(()) + } + + fn scan_dir_( + &self, + paths: &mut Vec, + dir: PathBuf, + ) -> Flow<(), FatalError, ScannerError> { + let dir_iter = return_error!(Flow::from(dir.read_dir().map_err(ScannerError::from))); + for entry in dir_iter { + match entry { + Ok(entry) if entry.path().is_dir() => paths.push(entry.path()), + Ok(entry) => { + let _ = return_fatal!(self.scan_file(entry.path()).or_else(|err| { + println!("scan_file failed: {:?}", err); + ok::<(), FatalError, ScannerError>(()) + })); + () + } + Err(err) => { + println!("scan_dir could not read path: ({:?})", err); + } + } + } + ok(()) + } + + fn scan_file(&self, path: PathBuf) -> Flow<(), FatalError, ScannerError> { + ok(()) + } +}