From f4745b5d68c8bc966e2dbf7800e0adab0c82d8ae Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Sat, 21 Sep 2024 15:54:22 +0200 Subject: [PATCH] Hide Job structs behind trait --- src/main.rs | 6 +- src/tui/app/machine/fetch_state.rs | 23 ++-- src/tui/app/machine/mod.rs | 17 +-- .../lib/external/musicbrainz/daemon/mod.rs | 103 ++++++++++++++---- 4 files changed, 103 insertions(+), 46 deletions(-) diff --git a/src/main.rs b/src/main.rs index a307943..4577ea6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -94,13 +94,13 @@ fn with( let listener = EventListener::new(listener_sender); let handler = EventHandler::new(channel.receiver()); - let mb_request_channel = JobChannel::new(); - thread::spawn(|| MusicBrainzDaemon::run(musicbrainz, mb_request_channel.receiver, app_sender)); + let mb_job_channel = JobChannel::new(); - let app = App::new(music_hoard, mb_request_channel.sender); + let app = App::new(music_hoard, mb_job_channel.sender()); let ui = Ui; // Run the TUI application. + thread::spawn(|| MusicBrainzDaemon::run(musicbrainz, mb_job_channel.receiver(), app_sender)); Tui::run(terminal, app, ui, handler, listener).expect("failed to run tui"); } diff --git a/src/tui/app/machine/fetch_state.rs b/src/tui/app/machine/fetch_state.rs index 56f80d6..b0f9f92 100644 --- a/src/tui/app/machine/fetch_state.rs +++ b/src/tui/app/machine/fetch_state.rs @@ -11,7 +11,7 @@ use crate::tui::{ AppPublicState, AppState, IAppEventFetch, IAppInteractFetch, MatchStateInfo, }, lib::{ - external::musicbrainz::daemon::{ApiParams, Job, JobInstance, JobPriority, ResultSender}, + external::musicbrainz::daemon::{MbParams, ResultSender}, interface::musicbrainz::api::Error as MbError, }, }; @@ -80,21 +80,18 @@ impl AppMachine { } fn submit_fetch_job(inner: &AppInner, artist: &Artist, tx: ResultSender) { - let mut queue = VecDeque::new(); - match artist.meta.musicbrainz { + let queue = match artist.meta.musicbrainz { Some(ref arid) => { let arid = arid.mbid(); - for album in artist.albums.iter() { - let meta = &album.meta; - queue.push_back(ApiParams::search_release_group(arid.clone(), meta.clone())); - } + artist + .albums + .iter() + .map(|album| MbParams::search_release_group(arid.clone(), album.meta.clone())) + .collect() } - None => { - queue.push_back(ApiParams::search_artist(artist.meta.clone())); - } - } - let job = Job::new(JobPriority::Background, JobInstance::new(tx, queue)); - inner.musicbrainz.send(job); + None => VecDeque::from([MbParams::search_artist(artist.meta.clone())]), + }; + inner.musicbrainz.submit_background_job(tx, queue); } } diff --git a/src/tui/app/machine/mod.rs b/src/tui/app/machine/mod.rs index 3cbf138..0f1853b 100644 --- a/src/tui/app/machine/mod.rs +++ b/src/tui/app/machine/mod.rs @@ -8,14 +8,12 @@ mod match_state; mod reload_state; mod search_state; -use std::sync::mpsc; - use crate::tui::{ app::{ selection::Selection, AppMode, AppPublic, AppPublicInner, AppPublicState, AppState, IApp, IAppAccess, IAppBase, IAppState, }, - lib::{external::musicbrainz::daemon::Job, IMusicHoard}, + lib::{external::musicbrainz::daemon::IMbJobSender, IMusicHoard}, }; use browse_state::BrowseState; @@ -48,7 +46,7 @@ pub struct AppMachine { pub struct AppInner { running: bool, music_hoard: Box, - musicbrainz: mpsc::Sender, + musicbrainz: Box, selection: Selection, } @@ -83,9 +81,9 @@ macro_rules! app_field_mut { } impl App { - pub fn new( + pub fn new( mut music_hoard: MH, - musicbrainz: mpsc::Sender, + musicbrainz: MB, ) -> Self { let init_result = Self::init(&mut music_hoard); let inner = AppInner::new(music_hoard, musicbrainz); @@ -171,12 +169,15 @@ impl IAppAccess for App { } impl AppInner { - pub fn new(music_hoard: MH, musicbrainz: mpsc::Sender) -> Self { + pub fn new( + music_hoard: MH, + musicbrainz: MB, + ) -> Self { let selection = Selection::new(music_hoard.get_collection()); AppInner { running: true, music_hoard: Box::new(music_hoard), - musicbrainz, + musicbrainz: Box::new(musicbrainz), selection, } } diff --git a/src/tui/lib/external/musicbrainz/daemon/mod.rs b/src/tui/lib/external/musicbrainz/daemon/mod.rs index 10980b5..c559879 100644 --- a/src/tui/lib/external/musicbrainz/daemon/mod.rs +++ b/src/tui/lib/external/musicbrainz/daemon/mod.rs @@ -10,7 +10,7 @@ use crate::tui::{ pub enum Error { EventChannelDisconnected, - RequestChannelDisconnected, + JobChannelDisconnected, } pub struct MusicBrainzDaemon { @@ -30,7 +30,7 @@ struct JobQueue { background_queue: VecDeque, } -pub struct Job { +struct Job { priority: JobPriority, instance: JobInstance, } @@ -41,15 +41,15 @@ impl Job { } } -pub enum JobPriority { +enum JobPriority { Foreground, Background, } pub type ResultSender = mpsc::Sender>; -pub struct JobInstance { +struct JobInstance { result_sender: ResultSender, - call_queue: VecDeque, + requests: VecDeque, } enum JobInstanceStatus { @@ -63,25 +63,25 @@ enum JobInstanceError { } impl JobInstance { - pub fn new(result_sender: ResultSender, call_queue: VecDeque) -> Self { + fn new(result_sender: ResultSender, requests: VecDeque) -> Self { JobInstance { result_sender, - call_queue, + requests, } } } -pub enum ApiParams { +pub enum MbParams { Search(SearchParams), } -impl ApiParams { +impl MbParams { pub fn search_artist(artist: ArtistMeta) -> Self { - ApiParams::Search(SearchParams::Artist(SearchArtistParams { artist })) + MbParams::Search(SearchParams::Artist(SearchArtistParams { artist })) } pub fn search_release_group(arid: Mbid, album: AlbumMeta) -> Self { - ApiParams::Search(SearchParams::ReleaseGroup(SearchReleaseGroupParams { + MbParams::Search(SearchParams::ReleaseGroup(SearchReleaseGroupParams { arid, album, })) @@ -103,8 +103,16 @@ pub struct SearchReleaseGroupParams { } pub struct JobChannel { - pub receiver: mpsc::Receiver, - pub sender: mpsc::Sender, + sender: mpsc::Sender, + receiver: mpsc::Receiver, +} + +pub struct JobSender { + sender: mpsc::Sender, +} + +pub struct JobReceiver { + receiver: mpsc::Receiver, } impl JobChannel { @@ -112,17 +120,68 @@ impl JobChannel { let (sender, receiver) = mpsc::channel(); JobChannel { receiver, sender } } + + pub fn sender(&self) -> JobSender { + JobSender { + sender: self.sender.clone(), + } + } + + pub fn receiver(self) -> JobReceiver { + JobReceiver { + receiver: self.receiver, + } + } +} + +pub trait IMbJobSender { + fn submit_background_job( + &self, + result_sender: ResultSender, + requests: VecDeque, + ) -> Result<(), Error>; +} + +impl IMbJobSender for JobSender { + fn submit_background_job( + &self, + result_sender: ResultSender, + requests: VecDeque, + ) -> Result<(), Error> { + self.send_background_job(result_sender, requests) + } +} + +impl JobSender { + fn send_background_job( + &self, + result_sender: ResultSender, + requests: VecDeque, + ) -> Result<(), Error> { + self.send_job(JobPriority::Background, result_sender, requests) + } + + fn send_job( + &self, + priority: JobPriority, + result_sender: ResultSender, + requests: VecDeque, + ) -> Result<(), Error> { + let instance = JobInstance::new(result_sender, requests); + let job = Job::new(priority, instance); + self.sender.send(job).or(Err(Error::JobChannelDisconnected)) + } } impl MusicBrainzDaemon { pub fn run( musicbrainz: MB, - job_receiver: mpsc::Receiver, + job_receiver: JobReceiver, event_sender: ES, ) -> Result<(), Error> { let daemon = MusicBrainzDaemon { musicbrainz: Box::new(musicbrainz), - job_receiver, + job_receiver: job_receiver.receiver, job_queue: JobQueue::new(), event_sender: Box::new(event_sender), }; @@ -155,7 +214,7 @@ impl MusicBrainzDaemon { Ok(job) => self.job_queue.push_back(job), Err(mpsc::TryRecvError::Empty) => return Ok(()), Err(mpsc::TryRecvError::Disconnected) => { - return Err(Error::RequestChannelDisconnected); + return Err(Error::JobChannelDisconnected); } } } @@ -184,7 +243,7 @@ impl MusicBrainzDaemon { match self.job_receiver.recv() { Ok(job) => self.job_queue.push_back(job), - Err(mpsc::RecvError) => return Err(Error::RequestChannelDisconnected), + Err(mpsc::RecvError) => return Err(Error::JobChannelDisconnected), } Ok(()) @@ -197,12 +256,12 @@ impl JobInstance { musicbrainz: &mut Box, event_sender: &mut Box, ) -> Result { - // self.call_queue can be empty if the caller submits an empty job. - if let Some(params) = self.call_queue.pop_front() { + // self.requests can be empty if the caller submits an empty job. + if let Some(params) = self.requests.pop_front() { self.execute(musicbrainz, event_sender, params)? } - if self.call_queue.is_empty() { + if self.requests.is_empty() { Ok(JobInstanceStatus::Complete) } else { Ok(JobInstanceStatus::Continue) @@ -213,10 +272,10 @@ impl JobInstance { &mut self, musicbrainz: &mut Box, event_sender: &mut Box, - api_params: ApiParams, + api_params: MbParams, ) -> Result<(), JobInstanceError> { match api_params { - ApiParams::Search(search) => match search { + MbParams::Search(search) => match search { SearchParams::Artist(params) => { let result = musicbrainz.search_artist(¶ms.artist); let result = result.map(|list| MatchStateInfo::artist(params.artist, list));