]> git.seodisparate.com - mpd_info_screen/commitdiff
Refactor MPDHandler to "hide" the Arc/RwLock impl
authorStephen Seo <seo.disparate@gmail.com>
Thu, 30 Dec 2021 13:16:12 +0000 (22:16 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Thu, 30 Dec 2021 13:16:12 +0000 (22:16 +0900)
src/display.rs
src/mpd_handler.rs

index dbfce809fcbd08cb20cb93be090e5c351c6ec892..dd0d49653c5d9fb479e84395d026581e4c374dc2 100644 (file)
@@ -48,7 +48,7 @@ fn seconds_to_time(seconds: f64) -> String {
 
 pub struct MPDDisplay {
     opts: Opt,
-    mpd_handler: Option<Arc<RwLock<MPDHandler>>>,
+    mpd_handler: Option<MPDHandler>,
     is_valid: bool,
     is_initialized: bool,
     is_authenticated: bool,
@@ -119,7 +119,7 @@ impl MPDDisplay {
             self.is_initialized = true;
             loop {
                 self.dirty_flag =
-                    MPDHandler::get_dirty_flag(self.mpd_handler.as_ref().unwrap().clone())
+                    MPDHandler::get_dirty_flag(&self.mpd_handler.as_ref().unwrap().clone())
                         .map_or(None, |f| Some(f));
                 if self.dirty_flag.is_some() {
                     break;
@@ -192,25 +192,25 @@ impl MPDDisplay {
     }
 
     fn get_image_from_data(&mut self, ctx: &mut Context) -> Result<(), String> {
-        let mpd_handle = self.mpd_handler.clone().unwrap();
-        let read_handle = mpd_handle
-            .try_read()
-            .map_err(|_| String::from("ERROR get_image_from_data: Failed to get read_handle"))?;
-
-        if !read_handle.is_art_data_ready() {
-            return Err(String::from(
-                "ERROR get_image_from_data: art data not ready",
-            ));
+        let read_guard = self
+            .mpd_handler
+            .as_ref()
+            .unwrap()
+            .get_state_read_guard()
+            .map_err(|_| String::from("Failed to get read_guard of MPDHandlerState"))?;
+        if !read_guard.is_art_data_ready() {
+            return Err(String::from("MPDHandlerState does not have album art data"));
         }
+        let image_ref = read_guard.get_art_data();
 
         let mut image_format: image::ImageFormat = image::ImageFormat::Png;
-        match read_handle.get_art_type().as_str() {
+        match read_guard.get_art_type().as_str() {
             "image/png" => image_format = image::ImageFormat::Png,
             "image/jpg" | "image/jpeg" => image_format = image::ImageFormat::Jpeg,
             "image/gif" => image_format = image::ImageFormat::Gif,
             _ => (),
         }
-        let img = ImageReader::with_format(Cursor::new(read_handle.get_art_data()), image_format)
+        let img = ImageReader::with_format(Cursor::new(&image_ref), image_format)
             .decode()
             .map_err(|e| format!("ERROR: Failed to decode album art image: {}", e))?;
         let rgba8 = img.to_rgba8();
@@ -467,7 +467,7 @@ impl EventHandler for MPDDisplay {
             }
         } else if self.password_entered {
             'check_state: loop {
-                let result = MPDHandler::is_authenticated(self.mpd_handler.clone().unwrap());
+                let result = self.mpd_handler.as_ref().unwrap().is_authenticated();
                 if let Ok(true) = result {
                     self.is_authenticated = true;
                     break;
@@ -476,14 +476,13 @@ impl EventHandler for MPDDisplay {
                 } else {
                     loop {
                         let check_fail_result =
-                            MPDHandler::failed_to_authenticate(self.mpd_handler.clone().unwrap());
+                            self.mpd_handler.as_ref().unwrap().failed_to_authenticate();
                         if let Ok(true) = check_fail_result {
                             {
                                 let mpd_handler = self.mpd_handler.clone().unwrap();
                                 loop {
-                                    let write_handle_result = mpd_handler.try_write();
-                                    if let Ok(write_handle) = write_handle_result {
-                                        write_handle.stop_flag.store(true, Ordering::Relaxed);
+                                    let stop_thread_result = mpd_handler.stop_thread();
+                                    if stop_thread_result.is_ok() {
                                         break;
                                     }
                                 }
@@ -517,7 +516,11 @@ impl EventHandler for MPDDisplay {
                     debug_log::LogState::DEBUG,
                     self.opts.log_level,
                 );
-                self.shared = MPDHandler::get_current_song_info(self.mpd_handler.clone().unwrap())
+                self.shared = self
+                    .mpd_handler
+                    .as_ref()
+                    .unwrap()
+                    .get_current_song_info()
                     .map_or(None, |f| Some(f));
                 if let Some(shared) = &self.shared {
                     if self.notice_text.contents() != shared.error_text {
index 4a12931de2846f955178b1027e2c94eb2a4fc8ed..4e26139f70b45b68cfe699443fcde37093a38583 100644 (file)
@@ -3,7 +3,7 @@ use std::io::{self, Read, Write};
 use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream};
 use std::str::FromStr;
 use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, Mutex, RwLock};
+use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard};
 use std::thread;
 use std::time::{Duration, Instant};
 
@@ -31,7 +31,12 @@ pub struct InfoFromShared {
     pub error_text: String,
 }
 
+#[derive(Clone)]
 pub struct MPDHandler {
+    state: Arc<RwLock<MPDHandlerState>>,
+}
+
+pub struct MPDHandlerState {
     art_data: Vec<u8>,
     art_data_size: usize,
     art_data_type: String,
@@ -224,50 +229,52 @@ impl MPDHandler {
         port: u16,
         password: String,
         log_level: LogState,
-    ) -> Result<Arc<RwLock<Self>>, String> {
+    ) -> Result<Self, String> {
         let stream = TcpStream::connect_timeout(
             &SocketAddr::new(IpAddr::V4(host), port),
             Duration::from_secs(5),
         )
         .map_err(|_| String::from("Failed to get TCP connection"))?;
 
-        let s = Arc::new(RwLock::new(Self {
-            art_data: Vec::new(),
-            art_data_size: 0,
-            art_data_type: String::new(),
-            current_song_filename: String::new(),
-            current_song_title: String::new(),
-            current_song_artist: String::new(),
-            current_song_length: 0.0,
-            current_song_position: 0.0,
-            current_binary_size: 0,
-            poll_state: PollState::None,
-            stream,
-            password,
-            error_text: String::new(),
-            can_authenticate: true,
-            is_authenticated: false,
-            can_get_album_art: true,
-            can_get_album_art_in_dir: true,
-            can_get_status: true,
-            is_init: true,
-            did_check_overtime: false,
-            force_get_status: false,
-            force_get_current_song: false,
-            song_title_get_time: Instant::now() - Duration::from_secs(10),
-            song_pos_get_time: Instant::now() - Duration::from_secs(10),
-            song_length_get_time: Instant::now() - Duration::from_secs(10),
-            self_thread: None,
-            dirty_flag: Arc::new(AtomicBool::new(true)),
-            stop_flag: Arc::new(AtomicBool::new(false)),
-            log_level,
-        }));
+        let s = MPDHandler {
+            state: Arc::new(RwLock::new(MPDHandlerState {
+                art_data: Vec::new(),
+                art_data_size: 0,
+                art_data_type: String::new(),
+                current_song_filename: String::new(),
+                current_song_title: String::new(),
+                current_song_artist: String::new(),
+                current_song_length: 0.0,
+                current_song_position: 0.0,
+                current_binary_size: 0,
+                poll_state: PollState::None,
+                stream,
+                password,
+                error_text: String::new(),
+                can_authenticate: true,
+                is_authenticated: false,
+                can_get_album_art: true,
+                can_get_album_art_in_dir: true,
+                can_get_status: true,
+                is_init: true,
+                did_check_overtime: false,
+                force_get_status: false,
+                force_get_current_song: false,
+                song_title_get_time: Instant::now() - Duration::from_secs(10),
+                song_pos_get_time: Instant::now() - Duration::from_secs(10),
+                song_length_get_time: Instant::now() - Duration::from_secs(10),
+                self_thread: None,
+                dirty_flag: Arc::new(AtomicBool::new(true)),
+                stop_flag: Arc::new(AtomicBool::new(false)),
+                log_level,
+            })),
+        };
 
         let s_clone = s.clone();
-        let thread = Arc::new(Mutex::new(thread::spawn(|| Self::handler_loop(s_clone))));
+        let thread = Arc::new(Mutex::new(thread::spawn(|| s_clone.handler_loop())));
 
         loop {
-            if let Ok(mut write_handle) = s.try_write() {
+            if let Ok(mut write_handle) = s.state.try_write() {
                 write_handle.self_thread = Some(thread);
                 break;
             } else {
@@ -278,8 +285,8 @@ impl MPDHandler {
         Ok(s)
     }
 
-    pub fn get_current_song_info(h: Arc<RwLock<Self>>) -> Result<InfoFromShared, ()> {
-        if let Ok(read_lock) = h.try_read() {
+    pub fn get_current_song_info(&self) -> Result<InfoFromShared, ()> {
+        if let Ok(read_lock) = self.state.try_read() {
             return Ok(InfoFromShared {
                 filename: read_lock.current_song_filename.clone(),
                 title: read_lock.current_song_title.clone(),
@@ -294,25 +301,25 @@ impl MPDHandler {
         Err(())
     }
 
-    pub fn get_dirty_flag(h: Arc<RwLock<Self>>) -> Result<Arc<AtomicBool>, ()> {
-        if let Ok(read_lock) = h.try_read() {
+    pub fn get_dirty_flag(&self) -> Result<Arc<AtomicBool>, ()> {
+        if let Ok(read_lock) = self.state.try_read() {
             return Ok(read_lock.dirty_flag.clone());
         }
 
         Err(())
     }
 
-    pub fn is_dirty(h: Arc<RwLock<Self>>) -> Result<bool, ()> {
-        if let Ok(write_lock) = h.try_write() {
+    pub fn is_dirty(&self) -> Result<bool, ()> {
+        if let Ok(write_lock) = self.state.try_write() {
             return Ok(write_lock.dirty_flag.swap(false, Ordering::Relaxed));
         }
 
         Err(())
     }
 
-    pub fn force_get_current_song(h: Arc<RwLock<Self>>) -> () {
+    pub fn force_get_current_song(&self) -> () {
         loop {
-            if let Ok(mut write_lock) = h.try_write() {
+            if let Ok(mut write_lock) = self.state.try_write() {
                 write_lock.force_get_current_song = true;
                 break;
             } else {
@@ -321,36 +328,43 @@ impl MPDHandler {
         }
     }
 
-    pub fn get_art_type(&self) -> String {
-        self.art_data_type.clone()
+    pub fn is_authenticated(&self) -> Result<bool, ()> {
+        let read_handle = self.state.try_read().map_err(|_| ())?;
+        Ok(read_handle.is_authenticated)
     }
 
-    pub fn is_art_data_ready(&self) -> bool {
-        self.art_data_size != 0 && self.art_data.len() == self.art_data_size
+    pub fn failed_to_authenticate(&self) -> Result<bool, ()> {
+        let read_handle = self.state.try_read().map_err(|_| ())?;
+        Ok(!read_handle.can_authenticate)
     }
 
-    pub fn get_art_data(&self) -> &[u8] {
-        &self.art_data
+    pub fn has_image_data(&self) -> Result<bool, ()> {
+        let read_handle = self.state.try_read().map_err(|_| ())?;
+        Ok(read_handle.is_art_data_ready())
     }
 
-    pub fn is_authenticated(h: Arc<RwLock<Self>>) -> Result<bool, ()> {
-        let read_handle = h.try_read().map_err(|_| ())?;
-        Ok(read_handle.is_authenticated)
+    pub fn get_state_read_guard<'a>(&'a self) -> Result<RwLockReadGuard<'a, MPDHandlerState>, ()> {
+        Ok(self.state.try_read().map_err(|_| ())?)
     }
 
-    pub fn failed_to_authenticate(h: Arc<RwLock<Self>>) -> Result<bool, ()> {
-        let read_handle = h.try_read().map_err(|_| ())?;
-        Ok(!read_handle.can_authenticate)
+    pub fn stop_thread(&self) -> Result<(), ()> {
+        let read_handle = self.state.try_read().map_err(|_| ())?;
+        read_handle.stop_flag.store(true, Ordering::Relaxed);
+        Ok(())
     }
 
-    fn handler_loop(h: Arc<RwLock<Self>>) -> Result<(), String> {
-        let log_level = h.read().expect("Failed to get log_level").log_level;
+    fn handler_loop(self) -> Result<(), String> {
+        let log_level = self
+            .state
+            .read()
+            .expect("Failed to get log_level")
+            .log_level;
         let mut buf: [u8; BUF_SIZE] = [0; BUF_SIZE];
         let mut saved: Vec<u8> = Vec::new();
         let mut saved_str: String = String::new();
 
         loop {
-            if let Ok(write_handle) = h.try_write() {
+            if let Ok(write_handle) = self.state.try_write() {
                 write_handle
                     .stream
                     .set_nonblocking(true)
@@ -362,9 +376,9 @@ impl MPDHandler {
         }
 
         'main: loop {
-            if !Self::is_reading_picture(h.clone()) {
+            if !self.is_reading_picture() {
                 thread::sleep(SLEEP_DURATION);
-                if let Ok(write_handle) = h.try_write() {
+                if let Ok(write_handle) = self.state.try_write() {
                     if write_handle.self_thread.is_none() {
                         // main thread failed to store handle to this thread
                         log(
@@ -377,15 +391,13 @@ impl MPDHandler {
                 }
             }
 
-            if let Err(err_string) =
-                Self::handler_read_block(h.clone(), &mut buf, &mut saved, &mut saved_str)
-            {
+            if let Err(err_string) = self.handler_read_block(&mut buf, &mut saved, &mut saved_str) {
                 log(
                     format!("read_block error: {}", err_string),
                     LogState::WARNING,
                     log_level,
                 );
-            } else if let Err(err_string) = Self::handler_write_block(h.clone()) {
+            } else if let Err(err_string) = self.handler_write_block() {
                 log(
                     format!("write_block error: {}", err_string),
                     LogState::WARNING,
@@ -393,7 +405,7 @@ impl MPDHandler {
                 );
             }
 
-            if let Ok(read_handle) = h.try_read() {
+            if let Ok(read_handle) = self.state.try_read() {
                 if read_handle.stop_flag.load(Ordering::Relaxed) {
                     break 'main;
                 }
@@ -408,7 +420,7 @@ impl MPDHandler {
             log_level,
         );
         'exit: loop {
-            if let Ok(mut write_handle) = h.try_write() {
+            if let Ok(mut write_handle) = self.state.try_write() {
                 write_handle.self_thread = None;
                 break 'exit;
             }
@@ -419,12 +431,13 @@ impl MPDHandler {
     }
 
     fn handler_read_block(
-        h: Arc<RwLock<Self>>,
+        &self,
         buf: &mut [u8; BUF_SIZE],
         saved: &mut Vec<u8>,
         saved_str: &mut String,
     ) -> Result<(), String> {
-        let mut write_handle = h
+        let mut write_handle = self
+            .state
             .try_write()
             .map_err(|_| String::from("Failed to get MPDHandler write lock (read_block)"))?;
         let mut read_amount: usize = 0;
@@ -674,8 +687,9 @@ impl MPDHandler {
         Ok(())
     }
 
-    fn handler_write_block(h: Arc<RwLock<MPDHandler>>) -> Result<(), String> {
-        let mut write_handle = h
+    fn handler_write_block(&self) -> Result<(), String> {
+        let mut write_handle = self
+            .state
             .try_write()
             .map_err(|_| String::from("Failed to get MPDHandler write lock (write_block)"))?;
         if write_handle.poll_state == PollState::None {
@@ -776,9 +790,9 @@ impl MPDHandler {
         Ok(())
     }
 
-    fn is_reading_picture(h: Arc<RwLock<MPDHandler>>) -> bool {
+    fn is_reading_picture(&self) -> bool {
         loop {
-            if let Ok(read_handle) = h.try_read() {
+            if let Ok(read_handle) = self.state.try_read() {
                 return read_handle.poll_state == PollState::ReadPicture
                     || read_handle.poll_state == PollState::ReadPictureInDir;
             } else {
@@ -787,3 +801,17 @@ impl MPDHandler {
         }
     }
 }
+
+impl MPDHandlerState {
+    pub fn get_art_type(&self) -> String {
+        self.art_data_type.clone()
+    }
+
+    pub fn is_art_data_ready(&self) -> bool {
+        self.art_data_size != 0 && self.art_data.len() == self.art_data_size
+    }
+
+    pub fn get_art_data(&self) -> &[u8] {
+        &self.art_data
+    }
+}