]> git.seodisparate.com - mpd_info_screen/commitdiff
WIP several fixes
authorStephen Seo <seo.disparate@gmail.com>
Wed, 15 Dec 2021 05:30:02 +0000 (14:30 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Wed, 15 Dec 2021 05:30:02 +0000 (14:30 +0900)
info output not implemented yet

src/display.rs
src/main.rs
src/mpd_handler.rs

index bbf766940c65cb91ba80fbb6814fe9bd22a2b6fa..be9aa4762f4c7cccdc61cbca3363e73229096dbb 100644 (file)
@@ -1,11 +1,16 @@
-use crate::mpd_handler::MPDHandler;
+use crate::debug_log::log;
+use crate::mpd_handler::{InfoFromShared, MPDHandler};
 use crate::Opt;
 use ggez::event::{self, EventHandler};
-use ggez::graphics::{self, Color, DrawParam, Drawable, Rect, Text, TextFragment};
-use ggez::timer::{check_update_time, fps};
+use ggez::graphics::{self, Color, DrawParam, Drawable, Text, TextFragment};
 use ggez::Context;
 use ggez::GameError;
+use std::sync::atomic::AtomicBool;
 use std::sync::{Arc, RwLock};
+use std::thread;
+use std::time::{Duration, Instant};
+
+const POLL_TIME: Duration = Duration::from_millis(333);
 
 pub struct MPDDisplay {
     opts: Opt,
@@ -13,23 +18,84 @@ pub struct MPDDisplay {
     is_valid: bool,
     is_initialized: bool,
     notice_text: Text,
+    poll_instant: Instant,
+    shared: Option<InfoFromShared>,
+    password_entered: bool,
+    dirty_flag: Option<Arc<AtomicBool>>,
 }
 
 impl MPDDisplay {
-    pub fn new(ctx: &mut Context, opts: Opt) -> Self {
+    pub fn new(_ctx: &mut Context, opts: Opt) -> Self {
         Self {
             opts,
             mpd_handler: None,
             is_valid: true,
             is_initialized: false,
             notice_text: Text::new(""),
+            poll_instant: Instant::now() - POLL_TIME,
+            shared: None,
+            password_entered: false,
+            dirty_flag: None,
+        }
+    }
+
+    fn init_mpd_handler(&mut self) -> () {
+        self.mpd_handler = MPDHandler::new(
+            self.opts.host,
+            self.opts.port,
+            self.opts.password.clone().map_or(String::new(), |s| s),
+        )
+        .map_or_else(|_| None, |v| Some(v));
+        if self.mpd_handler.is_some() {
+            self.is_initialized = true;
+            loop {
+                self.dirty_flag =
+                    MPDHandler::get_dirty_flag(self.mpd_handler.as_ref().unwrap().clone())
+                        .map_or(None, |f| Some(f));
+                if self.dirty_flag.is_some() {
+                    break;
+                } else {
+                    thread::sleep(POLL_TIME);
+                }
+            }
+            log("Successfully initialized MPDHandler");
+        } else {
+            self.is_valid = false;
+            log("Failed to initialize MPDHandler");
         }
     }
 }
 
 impl EventHandler for MPDDisplay {
-    fn update(&mut self, ctx: &mut ggez::Context) -> Result<(), GameError> {
-        self.notice_text = Text::new(TextFragment::new(format!("fps is {}", fps(ctx))));
+    fn update(&mut self, _ctx: &mut ggez::Context) -> Result<(), GameError> {
+        if !self.is_valid {
+            return Err(GameError::EventLoopError(
+                "Failed to initialize MPDHandler".into(),
+            ));
+        }
+
+        if !self.is_initialized {
+            if self.opts.enable_prompt_password {
+                if self.notice_text.contents().is_empty() {
+                    self.notice_text = Text::new(TextFragment::new("password: "));
+                } else if self.password_entered {
+                    self.init_mpd_handler();
+                }
+            } else {
+                self.init_mpd_handler();
+            }
+        }
+
+        if self.is_valid && self.is_initialized && self.poll_instant.elapsed() > POLL_TIME {
+            self.poll_instant = Instant::now();
+            self.shared = MPDHandler::get_current_song_info(self.mpd_handler.clone().unwrap())
+                .map_or(None, |f| Some(f));
+            if let Some(shared) = &self.shared {
+                if self.notice_text.contents() != shared.error_text {
+                    self.notice_text = Text::new(TextFragment::new(shared.error_text.clone()));
+                }
+            }
+        }
 
         Ok(())
     }
@@ -41,4 +107,37 @@ impl EventHandler for MPDDisplay {
 
         graphics::present(ctx)
     }
+
+    fn text_input_event(&mut self, _ctx: &mut Context, character: char) {
+        if !self.is_initialized && self.opts.enable_prompt_password {
+            if self.opts.password.is_none() {
+                let s = String::from(character);
+                self.opts.password = Some(s);
+                self.notice_text.add('*');
+            } else {
+                self.opts.password.as_mut().unwrap().push(character);
+                self.notice_text.add('*');
+            }
+        }
+    }
+
+    fn key_down_event(
+        &mut self,
+        _ctx: &mut Context,
+        keycode: event::KeyCode,
+        _keymods: event::KeyMods,
+        _repeat: bool,
+    ) {
+        if !self.is_initialized && self.opts.enable_prompt_password {
+            if keycode == event::KeyCode::Back {
+                let s: String = self.notice_text.contents();
+
+                if s.ends_with("*") {
+                    self.notice_text = Text::new(TextFragment::new(s[0..(s.len() - 1)].to_owned()));
+                }
+            } else if keycode == event::KeyCode::Return {
+                self.password_entered = true;
+            }
+        }
+    }
 }
index eb84537185901f6260a5864e82f40a6f3d26aeea..46c74015c3c302c0e005999640aa6329e4180e9b 100644 (file)
@@ -3,10 +3,10 @@ mod display;
 mod mpd_handler;
 
 use ggez::conf::{WindowMode, WindowSetup};
-use ggez::event::winit_event::KeyboardInput;
+use ggez::event::winit_event::{KeyboardInput, ModifiersState};
 use ggez::event::{self, ControlFlow, EventHandler};
 use ggez::graphics::{self, Rect};
-use ggez::ContextBuilder;
+use ggez::{ContextBuilder, GameError};
 use std::net::Ipv4Addr;
 use std::thread;
 use std::time::{Duration, Instant};
@@ -50,6 +50,8 @@ fn main() -> Result<(), String> {
 
     let mut display = display::MPDDisplay::new(&mut ctx, opt);
 
+    let mut modifiers_state: ModifiersState = ModifiersState::default();
+
     event_loop.run(move |mut event, _window_target, control_flow| {
         if !ctx.continuing {
             *control_flow = ControlFlow::Exit;
@@ -64,6 +66,9 @@ fn main() -> Result<(), String> {
         match event {
             event::winit_event::Event::WindowEvent { event, .. } => match event {
                 event::winit_event::WindowEvent::CloseRequested => event::quit(ctx),
+                event::winit_event::WindowEvent::ModifiersChanged(state) => {
+                    modifiers_state = state;
+                }
                 event::winit_event::WindowEvent::KeyboardInput {
                     device_id: _,
                     input:
@@ -72,12 +77,16 @@ fn main() -> Result<(), String> {
                             ..
                         },
                     is_synthetic: _,
-                } => match keycode {
-                    event::KeyCode::Escape | event::KeyCode::Q => {
-                        *control_flow = ControlFlow::Exit;
+                } => {
+                    match keycode {
+                        event::KeyCode::Escape => {
+                            *control_flow = ControlFlow::Exit;
+                            return;
+                        }
+                        _ => (),
                     }
-                    _ => (),
-                },
+                    display.key_down_event(ctx, keycode, modifiers_state.into(), false);
+                }
                 event::winit_event::WindowEvent::Resized(phys_size) => {
                     graphics::set_screen_coordinates(
                         ctx,
@@ -90,13 +99,26 @@ fn main() -> Result<(), String> {
                     )
                     .expect("Failed to handle resizing window");
                 }
+                event::winit_event::WindowEvent::ReceivedCharacter(ch) => {
+                    display.text_input_event(ctx, ch);
+                }
                 x => log(format!("Other window event fired: {:?}", x)),
             },
             event::winit_event::Event::MainEventsCleared => {
                 ctx.timer_context.tick();
 
-                display.update(ctx).expect("Update failed");
-                display.draw(ctx).expect("Draw failed");
+                let mut game_result: Result<(), GameError> = display.update(ctx);
+                if game_result.is_err() {
+                    println!("ERROR update: {}", game_result.unwrap_err());
+                    *control_flow = ControlFlow::Exit;
+                    return;
+                }
+                game_result = display.draw(ctx);
+                if game_result.is_err() {
+                    println!("ERROR draw: {}", game_result.unwrap_err());
+                    *control_flow = ControlFlow::Exit;
+                    return;
+                }
 
                 ctx.mouse_context.reset_delta();
 
index b60baaff011808f84b7408c4947c259e6ff53353..6c80337a7977af11c643281e3667c6fcfc5b3a3c 100644 (file)
@@ -1,4 +1,5 @@
-use std::io::{Read, Write};
+use crate::debug_log::log;
+use std::io::{self, Read, Write};
 use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream};
 use std::str::FromStr;
 use std::sync::atomic::{AtomicBool, Ordering};
@@ -7,7 +8,7 @@ use std::thread;
 use std::time::{Duration, Instant};
 
 const SLEEP_DURATION: Duration = Duration::from_millis(100);
-const POLL_DURATION: Duration = Duration::from_secs(10);
+const POLL_DURATION: Duration = Duration::from_secs(5);
 const BUF_SIZE: usize = 1024 * 4;
 
 #[derive(Debug, PartialEq, Copy, Clone)]
@@ -22,12 +23,12 @@ enum PollState {
 
 #[derive(Debug, Clone)]
 pub struct InfoFromShared {
-    filename: String,
-    title: String,
-    artist: String,
-    length: f64,
-    pos: f64,
-    error_text: String,
+    pub filename: String,
+    pub title: String,
+    pub artist: String,
+    pub length: f64,
+    pub pos: f64,
+    pub error_text: String,
 }
 
 pub struct MPDHandler {
@@ -155,6 +156,13 @@ fn read_line(
     let count = buf.len();
     let mut result = String::new();
 
+    if count == 0 {
+        return Err((
+            String::from("Empty string passed to read_line"),
+            String::new(),
+        ));
+    }
+
     let mut buf_to_read: Vec<u8> = Vec::with_capacity(saved.len() + buf.len());
 
     if !saved.is_empty() {
@@ -274,15 +282,20 @@ impl MPDHandler {
         let s_clone = s.clone();
         let thread = Arc::new(Mutex::new(thread::spawn(|| Self::handler_loop(s_clone))));
 
-        s.write()
-            .map_err(|_| String::from("Failed to store thread handle in MPDHandler"))?
-            .self_thread = Some(thread);
+        loop {
+            if let Ok(mut write_handle) = s.try_write() {
+                write_handle.self_thread = Some(thread);
+                break;
+            } else {
+                thread::sleep(Duration::from_millis(1));
+            }
+        }
 
         Ok(s)
     }
 
     pub fn get_art_data(h: Arc<RwLock<Self>>) -> Result<Vec<u8>, ()> {
-        if let Ok(read_lock) = h.read() {
+        if let Ok(read_lock) = h.try_read() {
             if read_lock.art_data.len() == read_lock.art_data_size {
                 return Ok(read_lock.art_data.clone());
             }
@@ -292,7 +305,7 @@ impl MPDHandler {
     }
 
     pub fn can_get_art_data(h: Arc<RwLock<Self>>) -> bool {
-        if let Ok(read_lock) = h.read() {
+        if let Ok(read_lock) = h.try_read() {
             return read_lock.can_get_album_art || read_lock.can_get_album_art_in_dir;
         }
 
@@ -300,7 +313,7 @@ impl MPDHandler {
     }
 
     pub fn get_current_song_info(h: Arc<RwLock<Self>>) -> Result<InfoFromShared, ()> {
-        if let Ok(read_lock) = h.read() {
+        if let Ok(read_lock) = h.try_read() {
             return Ok(InfoFromShared {
                 filename: read_lock.current_song_filename.clone(),
                 title: read_lock.current_song_title.clone(),
@@ -314,22 +327,54 @@ impl MPDHandler {
         Err(())
     }
 
+    pub fn get_dirty_flag(h: Arc<RwLock<Self>>) -> Result<Arc<AtomicBool>, ()> {
+        if let Ok(read_lock) = h.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.write() {
+        if let Ok(write_lock) = h.try_write() {
             return Ok(write_lock.dirty_flag.swap(false, Ordering::Relaxed));
         }
 
         Err(())
     }
 
+    pub fn force_get_current_song(h: Arc<RwLock<Self>>) -> () {
+        loop {
+            if let Ok(mut write_lock) = h.try_write() {
+                write_lock.force_get_current_song = true;
+                break;
+            } else {
+                thread::sleep(Duration::from_millis(10));
+            }
+        }
+    }
+
     fn handler_loop(h: Arc<RwLock<Self>>) -> Result<(), String> {
         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() {
+                write_handle
+                    .stream
+                    .set_nonblocking(true)
+                    .map_err(|_| String::from("Failed to set non-blocking on TCP stream"))?;
+                break;
+            } else {
+                thread::sleep(POLL_DURATION);
+            }
+        }
+
         'main: loop {
             if !Self::is_reading_picture(h.clone()) {
                 thread::sleep(SLEEP_DURATION);
-                if let Ok(write_handle) = h.write() {
+                if let Ok(write_handle) = h.try_write() {
                     if write_handle.self_thread.is_none() {
                         // main thread failed to store handle to this thread
                         println!("MPDHandle thread stopping due to failed handle storage");
@@ -346,15 +391,18 @@ impl MPDHandler {
                 println!("WARNING: write_block error: {}", err_string);
             }
 
-            if let Ok(read_handle) = h.read() {
+            if let Ok(read_handle) = h.try_read() {
                 if read_handle.stop_flag.load(Ordering::Relaxed) {
                     break 'main;
                 }
             }
+
+            io::stdout().flush().unwrap();
         }
 
+        log("MPDHandler thread entering exit loop");
         'exit: loop {
-            if let Ok(mut write_handle) = h.write() {
+            if let Ok(mut write_handle) = h.try_write() {
                 write_handle.self_thread = None;
                 break 'exit;
             }
@@ -371,29 +419,42 @@ impl MPDHandler {
         saved_str: &mut String,
     ) -> Result<(), String> {
         let mut write_handle = h
-            .write()
+            .try_write()
             .map_err(|_| String::from("Failed to get MPDHandler write lock (read_block)"))?;
-        let read_result = write_handle
-            .stream
-            .read(buf)
-            .map_err(|io_err| format!("Failed to read from TCP stream: {}", io_err))?;
-        if read_result == 0 {
-            return Err(String::from("Got zero bytes from TCP stream"));
+        let mut read_amount: usize = 0;
+        let read_result = write_handle.stream.read(buf);
+        if let Err(io_err) = read_result {
+            if io_err.kind() != io::ErrorKind::WouldBlock {
+                return Err(format!("TCP stream error: {}", io_err));
+            } else {
+                return Ok(());
+            }
+        } else if let Ok(read_amount_result) = read_result {
+            if read_amount_result == 0 {
+                return Err(String::from("Got zero bytes from TCP stream"));
+            }
+            read_amount = read_amount_result;
         }
-        let mut buf_vec: Vec<u8> = Vec::from(&buf[0..read_result]);
+        let mut buf_vec: Vec<u8> = Vec::from(&buf[0..read_amount]);
 
         'handle_buf: loop {
             if write_handle.current_binary_size > 0 {
-                if write_handle.current_binary_size <= buf_vec.len() {
+                if write_handle.current_binary_size < buf_vec.len() {
                     let count = write_handle.current_binary_size;
                     write_handle.art_data.extend_from_slice(&buf_vec[0..count]);
-                    buf_vec = buf_vec.split_off(write_handle.current_binary_size + 1);
+                    buf_vec = buf_vec.split_off(count + 1);
                     write_handle.current_binary_size = 0;
                     write_handle.poll_state = PollState::None;
                     write_handle.dirty_flag.store(true, Ordering::Relaxed);
+                    log("Got complete album art chunk");
                 } else {
                     write_handle.art_data.extend_from_slice(&buf_vec);
                     write_handle.current_binary_size -= buf_vec.len();
+                    log(format!(
+                        "Album art recv progress: {}/{}",
+                        write_handle.art_data.len(),
+                        write_handle.art_data_size
+                    ));
                     break 'handle_buf;
                 }
             }
@@ -413,6 +474,10 @@ impl MPDHandler {
                 } // write_handle.is_init
 
                 if line.starts_with("OK") {
+                    log(format!(
+                        "Got OK when poll state is {:?}",
+                        write_handle.poll_state
+                    ));
                     match write_handle.poll_state {
                         PollState::Password => write_handle.is_authenticated = true,
                         PollState::ReadPicture => {
@@ -518,10 +583,15 @@ impl MPDHandler {
                 } else if line.starts_with("Artist: ") {
                     write_handle.current_song_artist = line.split_off(8);
                 } else {
-                    println!("WARNING: Got unrecognized line: {}", line);
+                    log(format!("WARNING: Got unrecognized/ignored line: {}", line));
                 }
             } else if let Err((msg, read_line_in_progress)) = read_line_result {
-                println!("ERROR read_line: {}", msg);
+                log(format!(
+                    "WARNING read_line: {}, saved size == {}, in_progress size == {}",
+                    msg,
+                    saved.len(),
+                    read_line_in_progress.len()
+                ));
                 *saved_str = read_line_in_progress;
                 break 'handle_buf;
             } else {
@@ -534,7 +604,7 @@ impl MPDHandler {
 
     fn handler_write_block(h: Arc<RwLock<MPDHandler>>) -> Result<(), String> {
         let mut write_handle = h
-            .write()
+            .try_write()
             .map_err(|_| String::from("Failed to get MPDHandler write lock (write_block)"))?;
         if write_handle.poll_state == PollState::None {
             if !write_handle.did_check_overtime
@@ -615,11 +685,13 @@ impl MPDHandler {
     }
 
     fn is_reading_picture(h: Arc<RwLock<MPDHandler>>) -> bool {
-        if let Ok(read_handle) = h.read() {
-            read_handle.poll_state == PollState::ReadPicture
-                || read_handle.poll_state == PollState::ReadPictureInDir
-        } else {
-            false
+        loop {
+            if let Ok(read_handle) = h.try_read() {
+                return read_handle.poll_state == PollState::ReadPicture
+                    || read_handle.poll_state == PollState::ReadPictureInDir;
+            } else {
+                thread::sleep(Duration::from_millis(5));
+            }
         }
     }
 }