Refactor MPDHandler to "hide" the Arc/RwLock impl

This commit is contained in:
Stephen Seo 2021-12-30 22:16:12 +09:00
parent d9e371b79b
commit acdf49dc4b
2 changed files with 126 additions and 95 deletions

View file

@ -48,7 +48,7 @@ fn seconds_to_time(seconds: f64) -> String {
pub struct MPDDisplay { pub struct MPDDisplay {
opts: Opt, opts: Opt,
mpd_handler: Option<Arc<RwLock<MPDHandler>>>, mpd_handler: Option<MPDHandler>,
is_valid: bool, is_valid: bool,
is_initialized: bool, is_initialized: bool,
is_authenticated: bool, is_authenticated: bool,
@ -119,7 +119,7 @@ impl MPDDisplay {
self.is_initialized = true; self.is_initialized = true;
loop { loop {
self.dirty_flag = 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)); .map_or(None, |f| Some(f));
if self.dirty_flag.is_some() { if self.dirty_flag.is_some() {
break; break;
@ -192,25 +192,25 @@ impl MPDDisplay {
} }
fn get_image_from_data(&mut self, ctx: &mut Context) -> Result<(), String> { fn get_image_from_data(&mut self, ctx: &mut Context) -> Result<(), String> {
let mpd_handle = self.mpd_handler.clone().unwrap(); let read_guard = self
let read_handle = mpd_handle .mpd_handler
.try_read() .as_ref()
.map_err(|_| String::from("ERROR get_image_from_data: Failed to get read_handle"))?; .unwrap()
.get_state_read_guard()
if !read_handle.is_art_data_ready() { .map_err(|_| String::from("Failed to get read_guard of MPDHandlerState"))?;
return Err(String::from( if !read_guard.is_art_data_ready() {
"ERROR get_image_from_data: art data not 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; 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/png" => image_format = image::ImageFormat::Png,
"image/jpg" | "image/jpeg" => image_format = image::ImageFormat::Jpeg, "image/jpg" | "image/jpeg" => image_format = image::ImageFormat::Jpeg,
"image/gif" => image_format = image::ImageFormat::Gif, "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() .decode()
.map_err(|e| format!("ERROR: Failed to decode album art image: {}", e))?; .map_err(|e| format!("ERROR: Failed to decode album art image: {}", e))?;
let rgba8 = img.to_rgba8(); let rgba8 = img.to_rgba8();
@ -467,7 +467,7 @@ impl EventHandler for MPDDisplay {
} }
} else if self.password_entered { } else if self.password_entered {
'check_state: loop { '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 { if let Ok(true) = result {
self.is_authenticated = true; self.is_authenticated = true;
break; break;
@ -476,14 +476,13 @@ impl EventHandler for MPDDisplay {
} else { } else {
loop { loop {
let check_fail_result = 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 { if let Ok(true) = check_fail_result {
{ {
let mpd_handler = self.mpd_handler.clone().unwrap(); let mpd_handler = self.mpd_handler.clone().unwrap();
loop { loop {
let write_handle_result = mpd_handler.try_write(); let stop_thread_result = mpd_handler.stop_thread();
if let Ok(write_handle) = write_handle_result { if stop_thread_result.is_ok() {
write_handle.stop_flag.store(true, Ordering::Relaxed);
break; break;
} }
} }
@ -517,7 +516,11 @@ impl EventHandler for MPDDisplay {
debug_log::LogState::DEBUG, debug_log::LogState::DEBUG,
self.opts.log_level, 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)); .map_or(None, |f| Some(f));
if let Some(shared) = &self.shared { if let Some(shared) = &self.shared {
if self.notice_text.contents() != shared.error_text { if self.notice_text.contents() != shared.error_text {

View file

@ -3,7 +3,7 @@ use std::io::{self, Read, Write};
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream}; use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream};
use std::str::FromStr; use std::str::FromStr;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard};
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@ -31,7 +31,12 @@ pub struct InfoFromShared {
pub error_text: String, pub error_text: String,
} }
#[derive(Clone)]
pub struct MPDHandler { pub struct MPDHandler {
state: Arc<RwLock<MPDHandlerState>>,
}
pub struct MPDHandlerState {
art_data: Vec<u8>, art_data: Vec<u8>,
art_data_size: usize, art_data_size: usize,
art_data_type: String, art_data_type: String,
@ -224,50 +229,52 @@ impl MPDHandler {
port: u16, port: u16,
password: String, password: String,
log_level: LogState, log_level: LogState,
) -> Result<Arc<RwLock<Self>>, String> { ) -> Result<Self, String> {
let stream = TcpStream::connect_timeout( let stream = TcpStream::connect_timeout(
&SocketAddr::new(IpAddr::V4(host), port), &SocketAddr::new(IpAddr::V4(host), port),
Duration::from_secs(5), Duration::from_secs(5),
) )
.map_err(|_| String::from("Failed to get TCP connection"))?; .map_err(|_| String::from("Failed to get TCP connection"))?;
let s = Arc::new(RwLock::new(Self { let s = MPDHandler {
art_data: Vec::new(), state: Arc::new(RwLock::new(MPDHandlerState {
art_data_size: 0, art_data: Vec::new(),
art_data_type: String::new(), art_data_size: 0,
current_song_filename: String::new(), art_data_type: String::new(),
current_song_title: String::new(), current_song_filename: String::new(),
current_song_artist: String::new(), current_song_title: String::new(),
current_song_length: 0.0, current_song_artist: String::new(),
current_song_position: 0.0, current_song_length: 0.0,
current_binary_size: 0, current_song_position: 0.0,
poll_state: PollState::None, current_binary_size: 0,
stream, poll_state: PollState::None,
password, stream,
error_text: String::new(), password,
can_authenticate: true, error_text: String::new(),
is_authenticated: false, can_authenticate: true,
can_get_album_art: true, is_authenticated: false,
can_get_album_art_in_dir: true, can_get_album_art: true,
can_get_status: true, can_get_album_art_in_dir: true,
is_init: true, can_get_status: true,
did_check_overtime: false, is_init: true,
force_get_status: false, did_check_overtime: false,
force_get_current_song: false, force_get_status: false,
song_title_get_time: Instant::now() - Duration::from_secs(10), force_get_current_song: false,
song_pos_get_time: Instant::now() - Duration::from_secs(10), song_title_get_time: Instant::now() - Duration::from_secs(10),
song_length_get_time: Instant::now() - Duration::from_secs(10), song_pos_get_time: Instant::now() - Duration::from_secs(10),
self_thread: None, song_length_get_time: Instant::now() - Duration::from_secs(10),
dirty_flag: Arc::new(AtomicBool::new(true)), self_thread: None,
stop_flag: Arc::new(AtomicBool::new(false)), dirty_flag: Arc::new(AtomicBool::new(true)),
log_level, stop_flag: Arc::new(AtomicBool::new(false)),
})); log_level,
})),
};
let s_clone = s.clone(); 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 { 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); write_handle.self_thread = Some(thread);
break; break;
} else { } else {
@ -278,8 +285,8 @@ impl MPDHandler {
Ok(s) Ok(s)
} }
pub fn get_current_song_info(h: Arc<RwLock<Self>>) -> Result<InfoFromShared, ()> { pub fn get_current_song_info(&self) -> Result<InfoFromShared, ()> {
if let Ok(read_lock) = h.try_read() { if let Ok(read_lock) = self.state.try_read() {
return Ok(InfoFromShared { return Ok(InfoFromShared {
filename: read_lock.current_song_filename.clone(), filename: read_lock.current_song_filename.clone(),
title: read_lock.current_song_title.clone(), title: read_lock.current_song_title.clone(),
@ -294,25 +301,25 @@ impl MPDHandler {
Err(()) Err(())
} }
pub fn get_dirty_flag(h: Arc<RwLock<Self>>) -> Result<Arc<AtomicBool>, ()> { pub fn get_dirty_flag(&self) -> Result<Arc<AtomicBool>, ()> {
if let Ok(read_lock) = h.try_read() { if let Ok(read_lock) = self.state.try_read() {
return Ok(read_lock.dirty_flag.clone()); return Ok(read_lock.dirty_flag.clone());
} }
Err(()) Err(())
} }
pub fn is_dirty(h: Arc<RwLock<Self>>) -> Result<bool, ()> { pub fn is_dirty(&self) -> Result<bool, ()> {
if let Ok(write_lock) = h.try_write() { if let Ok(write_lock) = self.state.try_write() {
return Ok(write_lock.dirty_flag.swap(false, Ordering::Relaxed)); return Ok(write_lock.dirty_flag.swap(false, Ordering::Relaxed));
} }
Err(()) Err(())
} }
pub fn force_get_current_song(h: Arc<RwLock<Self>>) -> () { pub fn force_get_current_song(&self) -> () {
loop { 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; write_lock.force_get_current_song = true;
break; break;
} else { } else {
@ -321,36 +328,43 @@ impl MPDHandler {
} }
} }
pub fn get_art_type(&self) -> String { pub fn is_authenticated(&self) -> Result<bool, ()> {
self.art_data_type.clone() let read_handle = self.state.try_read().map_err(|_| ())?;
}
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
}
pub fn is_authenticated(h: Arc<RwLock<Self>>) -> Result<bool, ()> {
let read_handle = h.try_read().map_err(|_| ())?;
Ok(read_handle.is_authenticated) Ok(read_handle.is_authenticated)
} }
pub fn failed_to_authenticate(h: Arc<RwLock<Self>>) -> Result<bool, ()> { pub fn failed_to_authenticate(&self) -> Result<bool, ()> {
let read_handle = h.try_read().map_err(|_| ())?; let read_handle = self.state.try_read().map_err(|_| ())?;
Ok(!read_handle.can_authenticate) Ok(!read_handle.can_authenticate)
} }
fn handler_loop(h: Arc<RwLock<Self>>) -> Result<(), String> { pub fn has_image_data(&self) -> Result<bool, ()> {
let log_level = h.read().expect("Failed to get log_level").log_level; let read_handle = self.state.try_read().map_err(|_| ())?;
Ok(read_handle.is_art_data_ready())
}
pub fn get_state_read_guard<'a>(&'a self) -> Result<RwLockReadGuard<'a, MPDHandlerState>, ()> {
Ok(self.state.try_read().map_err(|_| ())?)
}
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(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 buf: [u8; BUF_SIZE] = [0; BUF_SIZE];
let mut saved: Vec<u8> = Vec::new(); let mut saved: Vec<u8> = Vec::new();
let mut saved_str: String = String::new(); let mut saved_str: String = String::new();
loop { loop {
if let Ok(write_handle) = h.try_write() { if let Ok(write_handle) = self.state.try_write() {
write_handle write_handle
.stream .stream
.set_nonblocking(true) .set_nonblocking(true)
@ -362,9 +376,9 @@ impl MPDHandler {
} }
'main: loop { 'main: loop {
if !Self::is_reading_picture(h.clone()) { if !self.is_reading_picture() {
thread::sleep(SLEEP_DURATION); 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() { if write_handle.self_thread.is_none() {
// main thread failed to store handle to this thread // main thread failed to store handle to this thread
log( log(
@ -377,15 +391,13 @@ impl MPDHandler {
} }
} }
if let Err(err_string) = if let Err(err_string) = self.handler_read_block(&mut buf, &mut saved, &mut saved_str) {
Self::handler_read_block(h.clone(), &mut buf, &mut saved, &mut saved_str)
{
log( log(
format!("read_block error: {}", err_string), format!("read_block error: {}", err_string),
LogState::WARNING, LogState::WARNING,
log_level, 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( log(
format!("write_block error: {}", err_string), format!("write_block error: {}", err_string),
LogState::WARNING, 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) { if read_handle.stop_flag.load(Ordering::Relaxed) {
break 'main; break 'main;
} }
@ -408,7 +420,7 @@ impl MPDHandler {
log_level, log_level,
); );
'exit: loop { '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; write_handle.self_thread = None;
break 'exit; break 'exit;
} }
@ -419,12 +431,13 @@ impl MPDHandler {
} }
fn handler_read_block( fn handler_read_block(
h: Arc<RwLock<Self>>, &self,
buf: &mut [u8; BUF_SIZE], buf: &mut [u8; BUF_SIZE],
saved: &mut Vec<u8>, saved: &mut Vec<u8>,
saved_str: &mut String, saved_str: &mut String,
) -> Result<(), String> { ) -> Result<(), String> {
let mut write_handle = h let mut write_handle = self
.state
.try_write() .try_write()
.map_err(|_| String::from("Failed to get MPDHandler write lock (read_block)"))?; .map_err(|_| String::from("Failed to get MPDHandler write lock (read_block)"))?;
let mut read_amount: usize = 0; let mut read_amount: usize = 0;
@ -674,8 +687,9 @@ impl MPDHandler {
Ok(()) Ok(())
} }
fn handler_write_block(h: Arc<RwLock<MPDHandler>>) -> Result<(), String> { fn handler_write_block(&self) -> Result<(), String> {
let mut write_handle = h let mut write_handle = self
.state
.try_write() .try_write()
.map_err(|_| String::from("Failed to get MPDHandler write lock (write_block)"))?; .map_err(|_| String::from("Failed to get MPDHandler write lock (write_block)"))?;
if write_handle.poll_state == PollState::None { if write_handle.poll_state == PollState::None {
@ -776,9 +790,9 @@ impl MPDHandler {
Ok(()) Ok(())
} }
fn is_reading_picture(h: Arc<RwLock<MPDHandler>>) -> bool { fn is_reading_picture(&self) -> bool {
loop { 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 return read_handle.poll_state == PollState::ReadPicture
|| read_handle.poll_state == PollState::ReadPictureInDir; || read_handle.poll_state == PollState::ReadPictureInDir;
} else { } 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
}
}