diff --git a/src/ipc.rs b/src/ipc.rs index 2385661..235b77d 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -1,11 +1,12 @@ +use serde_json::{self, Value}; +use std::collections::HashMap; use std::error::Error; -use std::io::prelude::*; use std::io::BufReader; +use std::io::prelude::*; +use std::iter::Iterator; use std::os::unix::net::UnixStream; use std::net::Shutdown; -use std::iter::Iterator; -use std::collections::HashMap; -use serde_json::{self, Value}; +use std::sync::mpsc::Sender; #[derive(Debug)] pub struct PlaylistEntry { @@ -284,6 +285,26 @@ pub fn run_mpv_command(socket: &str, command: &str, args: &Vec<&str>) -> Result< } } +pub fn observe_mpv_property(socket: &str, id: &usize, property: &str) -> Result<(), String> { + let ipc_string = format!("{{ \"command\": [\"observe_property\", {}, \"{}\"] }}\n", + id, + property); + match serde_json::from_str::(&send_command_sync(socket, &ipc_string)) { + Ok(feedback) => { + if let Value::String(ref error) = feedback["error"] { + if error == "success" { + Ok(()) + } else { + Err(error.to_string()) + } + } else { + Err("Unexpected result received".to_string()) + } + } + Err(why) => Err(why.description().to_string()), + } +} + /// #Description /// /// Listens on socket for events and prints them in real-time to stdout. @@ -293,83 +314,29 @@ pub fn run_mpv_command(socket: &str, command: &str, args: &Vec<&str>) -> Result< /// ``` /// listen("/tmp/mpvsocket"); /// ``` -pub fn listen(socket: &str) { +pub fn listen(socket: &str, tx: &Sender) { match UnixStream::connect(socket) { Ok(stream) => { let mut response = String::new(); let mut reader = BufReader::new(&stream); - loop { - reader.read_line(&mut response).unwrap(); - match serde_json::from_str::(&response) { - Ok(e) => { - if let Value::String(ref name) = e["event"] { - println!("{}", name); - } + reader.read_line(&mut response).unwrap(); + match serde_json::from_str::(&response) { + Ok(e) => { + if let Value::String(ref name) = e["event"] { + tx.send(name.to_string()).unwrap(); } - Err(why) => panic!("{}", why.description().to_string()), } - response.clear(); + Err(why) => panic!("{}", why.description().to_string()), } + response.clear(); + stream + .shutdown(Shutdown::Both) + .expect("shutdown function failed"); } Err(why) => panic!("Error: Could not connect to socket: {}", why.description()), } } -/// #Description -/// -/// Listens on socket for events quits as soon as event occurs. -/// -/// #Example -/// ``` -/// wait_for_event("/tmp/mpvsocket", "pause"); -/// ``` -pub fn wait_for_event(socket: &str, event: &str) { - match UnixStream::connect(socket) { - Ok(stream) => { - let mut response = String::new(); - let mut reader = BufReader::new(&stream); - loop { - reader.read_line(&mut response).unwrap(); - match serde_json::from_str::(&response) { - Ok(e) => { - if let Value::String(ref name) = e["event"] { - if name.as_str() == event { - break; - } - } - } - Err(why) => panic!("{}", why.description().to_string()), - } - response.clear(); - } - stream.shutdown(Shutdown::Both).expect("socket shutdown"); - } - Err(why) => panic!("Error: Could not connect to socket: {}", why.description()), - } -} - -// pub fn observe_property(socket: &str, property: &str) -> String { -// match UnixStream::connect(socket) { -// Ok(mut stream) => { -// let command = format!("{{ \"command\": [\"observe_property\", 1, \"{}\"] }}\n", -// property); -// match stream.write_all(command.as_bytes()) { -// Err(why) => error!("Error: Could not write to socket: {}", why.description()), -// Ok(_) => { -// let mut response = String::new(); -// let mut reader = BufReader::new(&stream); -// loop { -// reader.read_line(&mut response).unwrap(); -// println!("{}", response); -// response.clear(); -// } -// } -// } -// } -// Err(why) => error!("Error: Could not connect to socket: {}", why.description()), -// } -// } - fn send_command_sync(socket: &str, command: &str) -> String { match UnixStream::connect(socket) { Ok(mut stream) => { diff --git a/src/lib.rs b/src/lib.rs index 53d0a92..90b29aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,8 +3,10 @@ extern crate serde_json; pub mod ipc; -use std::collections::HashMap; use ipc::*; +use std::collections::HashMap; +use std::sync::mpsc::Sender; + pub type Socket = String; @@ -192,46 +194,6 @@ impl PlaylistHandler for Playlist { pub trait Commands { fn get_metadata(&self) -> Result, String>; fn get_playlist(&self) -> Result; - fn get_property(&self, property: &str) -> Result; - fn get_property_string(&self, property: &str) -> Result; - fn kill(&self) -> Result<(), String>; - fn next(&self) -> Result<(), String>; - fn pause(&self) -> Result<(), String>; - fn playlist_add(&self, file: &str, option: PlaylistAddOptions) -> Result<(), String>; - fn playlist_clear(&self) -> Result<(), String>; - fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), String>; - fn playlist_play_id(&self, id: usize) -> Result<(), String>; - fn playlist_play_next(&self, id: usize) -> Result<(), String>; - fn playlist_shuffle(&self) -> Result<(), String>; - fn playlist_remove_id(&self, id: usize) -> Result<(), String>; - fn prev(&self) -> Result<(), String>; - fn restart(&self) -> Result<(), String>; - fn run_command(&self, command: &str, args: &Vec<&str>) -> Result<(), String>; - fn seek(&self, seconds: f64, option: SeekOptions) -> Result<(), String>; - fn set_loop_file(&self, option: Switch) -> Result<(), String>; - fn set_loop_playlist(&self, option: Switch) -> Result<(), String>; - fn set_mute(&self, option: Switch) -> Result<(), String>; - fn set_property>(&self, - property: &str, - value: T) - -> Result<(), String>; - fn set_speed(&self, input_volume: f64, option: NumberChangeOptions) -> Result<(), String>; - fn set_volume(&self, input_volume: f64, option: NumberChangeOptions) -> Result<(), String>; - fn stop(&self) -> Result<(), String>; - fn toggle(&self) -> Result<(), String>; -} - -impl Commands for Socket { - fn get_metadata(&self) -> Result, String> { - match get_mpv_property(self, "metadata") { - Ok(map) => Ok(map), - Err(err) => Err(err), - } - } - - fn get_playlist(&self) -> Result { - Playlist::get_from(self.to_string()) - } /// #Description /// @@ -254,9 +216,7 @@ impl Commands for Socket { /// let paused: bool = mpv.get_property("pause").unwrap(); /// let title: String = mpv.get_property("media-title").unwrap(); /// ``` - fn get_property(&self, property: &str) -> Result { - T::get_property_generic(self, property) - } + fn get_property(&self, property: &str) -> Result; /// #Description /// @@ -274,29 +234,21 @@ impl Commands for Socket { /// let mpv: Socket = String::from(matches.value_of("socket").unwrap()); /// let title = mpv.get_property_string("media-title").unwrap(); /// ``` - fn get_property_string(&self, property: &str) -> Result { - get_mpv_property_string(self, property) - } - - fn kill(&self) -> Result<(), String> { - run_mpv_command(self, "quit", &vec![]) - } - - fn next(&self) -> Result<(), String> { - run_mpv_command(self, "playlist-next", &vec![]) - } - - fn pause(&self) -> Result<(), String> { - set_mpv_property(self, "pause", true) - } - - fn prev(&self) -> Result<(), String> { - run_mpv_command(self, "playlist-prev", &vec![]) - } - - fn restart(&self) -> Result<(), String> { - run_mpv_command(self, "seek", &vec!["0", "absolute"]) - } + fn get_property_string(&self, property: &str) -> Result; + fn kill(&self) -> Result<(), String>; + fn listen(&self, tx: &Sender); + fn next(&self) -> Result<(), String>; + fn observe_property(&self, id: &usize, property: &str) -> Result<(), String>; + fn pause(&self) -> Result<(), String>; + fn playlist_add(&self, file: &str, option: PlaylistAddOptions) -> Result<(), String>; + fn playlist_clear(&self) -> Result<(), String>; + fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), String>; + fn playlist_play_id(&self, id: usize) -> Result<(), String>; + fn playlist_play_next(&self, id: usize) -> Result<(), String>; + fn playlist_shuffle(&self) -> Result<(), String>; + fn playlist_remove_id(&self, id: usize) -> Result<(), String>; + fn prev(&self) -> Result<(), String>; + fn restart(&self) -> Result<(), String>; /// #Description /// @@ -312,6 +264,90 @@ impl Commands for Socket { /// //Run command 'seek' which in this case takes two arguments /// mpv.run_command("seek", &vec!["0", "absolute"]); /// ``` + fn run_command(&self, command: &str, args: &Vec<&str>) -> Result<(), String>; + fn seek(&self, seconds: f64, option: SeekOptions) -> Result<(), String>; + fn set_loop_file(&self, option: Switch) -> Result<(), String>; + fn set_loop_playlist(&self, option: Switch) -> Result<(), String>; + fn set_mute(&self, option: Switch) -> Result<(), String>; + + /// #Description + /// + /// Sets the mpv property __ to __. + /// + /// ##Supported types + /// - String + /// - bool + /// - f64 + /// - usize + /// + /// ##Input arguments + /// + /// - **property** defines the mpv property that should be retrieved + /// - **value** defines the value of the given mpv property __ + /// + /// #Example + /// ``` + /// let mpv: Socket = String::from(matches.value_of("socket").unwrap()); + /// mpv.set_property("pause", true); + /// ``` + fn set_property>(&self, + property: &str, + value: T) + -> Result<(), String>; + fn set_speed(&self, input_volume: f64, option: NumberChangeOptions) -> Result<(), String>; + fn set_volume(&self, input_volume: f64, option: NumberChangeOptions) -> Result<(), String>; + fn stop(&self) -> Result<(), String>; + fn toggle(&self) -> Result<(), String>; +} + +impl Commands for Socket { + fn get_metadata(&self) -> Result, String> { + match get_mpv_property(self, "metadata") { + Ok(map) => Ok(map), + Err(err) => Err(err), + } + } + + fn get_playlist(&self) -> Result { + Playlist::get_from(self.to_string()) + } + + fn get_property(&self, property: &str) -> Result { + T::get_property_generic(self, property) + } + + fn get_property_string(&self, property: &str) -> Result { + get_mpv_property_string(self, property) + } + + fn kill(&self) -> Result<(), String> { + run_mpv_command(self, "quit", &vec![]) + } + + fn listen(&self, tx: &Sender) { + listen(self, tx); + } + + fn next(&self) -> Result<(), String> { + run_mpv_command(self, "playlist-next", &vec![]) + } + + fn observe_property(&self, id: &usize, property: &str) -> Result<(), String> { + observe_mpv_property(self, id, property) + } + + fn pause(&self) -> Result<(), String> { + set_mpv_property(self, "pause", true) + } + + fn prev(&self) -> Result<(), String> { + run_mpv_command(self, "playlist-prev", &vec![]) + } + + fn restart(&self) -> Result<(), String> { + run_mpv_command(self, "seek", &vec!["0", "absolute"]) + } + fn run_command(&self, command: &str, args: &Vec<&str>) -> Result<(), String> { run_mpv_command(self, command, args) } @@ -451,26 +487,6 @@ impl Commands for Socket { set_mpv_property(self, "mute", enabled) } - /// #Description - /// - /// Sets the mpv property __ to __. - /// - /// ##Supported types - /// - String - /// - bool - /// - f64 - /// - usize - /// - /// ##Input arguments - /// - /// - **property** defines the mpv property that should be retrieved - /// - **value** defines the value of the given mpv property __ - /// - /// #Example - /// ``` - /// let mpv: Socket = String::from(matches.value_of("socket").unwrap()); - /// mpv.set_property("pause", true); - /// ``` fn set_property>(&self, property: &str, value: T)