Refactor MPDHandler to "hide" the Arc/RwLock impl
This commit is contained in:
parent
d9e371b79b
commit
acdf49dc4b
2 changed files with 126 additions and 95 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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,14 +229,15 @@ 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 {
|
||||||
|
state: Arc::new(RwLock::new(MPDHandlerState {
|
||||||
art_data: Vec::new(),
|
art_data: Vec::new(),
|
||||||
art_data_size: 0,
|
art_data_size: 0,
|
||||||
art_data_type: String::new(),
|
art_data_type: String::new(),
|
||||||
|
@ -261,13 +267,14 @@ impl MPDHandler {
|
||||||
dirty_flag: Arc::new(AtomicBool::new(true)),
|
dirty_flag: Arc::new(AtomicBool::new(true)),
|
||||||
stop_flag: Arc::new(AtomicBool::new(false)),
|
stop_flag: Arc::new(AtomicBool::new(false)),
|
||||||
log_level,
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue