Replaced string errors with a proper Error struct. Changed run_command arguments to a slice instead of vector.

This commit is contained in:
Jonas Frei 2017-05-31 19:32:46 +02:00
parent 4ffa94357a
commit 57d7226373
2 changed files with 212 additions and 151 deletions

View File

@ -1,11 +1,10 @@
use serde_json::{self, Value}; use serde_json::{self, Value};
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error;
use std::io::BufReader; use std::io::BufReader;
use std::io::prelude::*; use std::io::prelude::*;
use std::iter::Iterator; use std::iter::Iterator;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
use super::Mpv; use super::{Mpv, Error, ErrorCode};
#[derive(Debug)] #[derive(Debug)]
pub struct PlaylistEntry { pub struct PlaylistEntry {
@ -16,28 +15,28 @@ pub struct PlaylistEntry {
} }
pub trait TypeHandler: Sized { pub trait TypeHandler: Sized {
fn get_value(value: Value) -> Result<Self, String>; fn get_value(value: Value) -> Result<Self, Error>;
fn as_string(&self) -> String; fn as_string(&self) -> String;
} }
impl TypeHandler for String { impl TypeHandler for String {
fn get_value(value: Value) -> Result<String, String> { fn get_value(value: Value) -> Result<String, Error> {
if let Value::Object(map) = value { if let Value::Object(map) = value {
if let Value::String(ref error) = map["error"] { if let Value::String(ref error) = map["error"] {
if error == "success" && map.contains_key("data") { if error == "success" && map.contains_key("data") {
if let Value::String(ref s) = map["data"] { if let Value::String(ref s) = map["data"] {
Ok(s.to_string()) Ok(s.to_string())
} else { } else {
Err("Value did not contain a String".to_string()) Err(Error(ErrorCode::ValueDoesNotContainString))
} }
} else { } else {
Err(error.to_string()) Err(Error(ErrorCode::MpvError(error.to_string())))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} }
@ -47,23 +46,23 @@ impl TypeHandler for String {
} }
impl TypeHandler for bool { impl TypeHandler for bool {
fn get_value(value: Value) -> Result<bool, String> { fn get_value(value: Value) -> Result<bool, Error> {
if let Value::Object(map) = value { if let Value::Object(map) = value {
if let Value::String(ref error) = map["error"] { if let Value::String(ref error) = map["error"] {
if error == "success" && map.contains_key("data") { if error == "success" && map.contains_key("data") {
if let Value::Bool(ref b) = map["data"] { if let Value::Bool(ref b) = map["data"] {
Ok(*b) Ok(*b)
} else { } else {
Err("Value did not contain a bool".to_string()) Err(Error(ErrorCode::ValueDoesNotContainBool))
} }
} else { } else {
Err(error.to_string()) Err(Error(ErrorCode::MpvError(error.to_string())))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} }
fn as_string(&self) -> String { fn as_string(&self) -> String {
@ -76,23 +75,23 @@ impl TypeHandler for bool {
} }
impl TypeHandler for f64 { impl TypeHandler for f64 {
fn get_value(value: Value) -> Result<f64, String> { fn get_value(value: Value) -> Result<f64, Error> {
if let Value::Object(map) = value { if let Value::Object(map) = value {
if let Value::String(ref error) = map["error"] { if let Value::String(ref error) = map["error"] {
if error == "success" && map.contains_key("data") { if error == "success" && map.contains_key("data") {
if let Value::Number(ref num) = map["data"] { if let Value::Number(ref num) = map["data"] {
Ok(num.as_f64().unwrap()) Ok(num.as_f64().unwrap())
} else { } else {
Err("Value did not contain a f64".to_string()) Err(Error(ErrorCode::ValueDoesNotContainF64))
} }
} else { } else {
Err(error.to_string()) Err(Error(ErrorCode::MpvError(error.to_string())))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} }
@ -102,23 +101,23 @@ impl TypeHandler for f64 {
} }
impl TypeHandler for usize { impl TypeHandler for usize {
fn get_value(value: Value) -> Result<usize, String> { fn get_value(value: Value) -> Result<usize, Error> {
if let Value::Object(map) = value { if let Value::Object(map) = value {
if let Value::String(ref error) = map["error"] { if let Value::String(ref error) = map["error"] {
if error == "success" && map.contains_key("data") { if error == "success" && map.contains_key("data") {
if let Value::Number(ref num) = map["data"] { if let Value::Number(ref num) = map["data"] {
Ok(num.as_u64().unwrap() as usize) Ok(num.as_u64().unwrap() as usize)
} else { } else {
Err("Value did not contain an usize".to_string()) Err(Error(ErrorCode::ValueDoesNotContainUsize))
} }
} else { } else {
Err(error.to_string()) Err(Error(ErrorCode::MpvError(error.to_string())))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} }
@ -128,7 +127,7 @@ impl TypeHandler for usize {
} }
impl TypeHandler for HashMap<String, String> { impl TypeHandler for HashMap<String, String> {
fn get_value(value: Value) -> Result<HashMap<String, String>, String> { fn get_value(value: Value) -> Result<HashMap<String, String>, Error> {
if let Value::Object(map) = value { if let Value::Object(map) = value {
if let Value::String(ref error) = map["error"] { if let Value::String(ref error) = map["error"] {
if error == "success" && map.contains_key("data") { if error == "success" && map.contains_key("data") {
@ -142,16 +141,16 @@ impl TypeHandler for HashMap<String, String> {
let output_map = output_map; let output_map = output_map;
Ok(output_map) Ok(output_map)
} else { } else {
Err("Value did not contain a HashMap".to_string()) Err(Error(ErrorCode::ValueDoesNotContainHashMap))
} }
} else { } else {
Err(error.to_string()) Err(Error(ErrorCode::MpvError(error.to_string())))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} }
@ -161,7 +160,7 @@ impl TypeHandler for HashMap<String, String> {
} }
impl TypeHandler for Vec<PlaylistEntry> { impl TypeHandler for Vec<PlaylistEntry> {
fn get_value(value: Value) -> Result<Vec<PlaylistEntry>, String> { fn get_value(value: Value) -> Result<Vec<PlaylistEntry>, Error> {
if let Value::Object(map) = value { if let Value::Object(map) = value {
if let Value::String(ref error) = map["error"] { if let Value::String(ref error) = map["error"] {
if error == "success" && map.contains_key("data") { if error == "success" && map.contains_key("data") {
@ -190,16 +189,16 @@ impl TypeHandler for Vec<PlaylistEntry> {
let output = output; let output = output;
Ok(output) Ok(output)
} else { } else {
Err("Value did not contain a playlist".to_string()) Err(Error(ErrorCode::ValueDoesNotContainPlaylist))
} }
} else { } else {
Err(error.to_string()) Err(Error(ErrorCode::MpvError(error.to_string())))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} }
@ -208,16 +207,16 @@ impl TypeHandler for Vec<PlaylistEntry> {
} }
} }
pub fn get_mpv_property<T: TypeHandler>(instance: &Mpv, property: &str) -> Result<T, String> { pub fn get_mpv_property<T: TypeHandler>(instance: &Mpv, property: &str) -> Result<T, Error> {
let ipc_string = format!("{{ \"command\": [\"get_property\",\"{}\"] }}\n", property); let ipc_string = format!("{{ \"command\": [\"get_property\",\"{}\"] }}\n", property);
match serde_json::from_str::<Value>(&send_command_sync(instance, &ipc_string)) { match serde_json::from_str::<Value>(&send_command_sync(instance, &ipc_string)) {
Ok(val) => T::get_value(val), Ok(val) => T::get_value(val),
Err(why) => Err(format!("Error while getting property: {}", why)), Err(why) => Err(Error(ErrorCode::JsonParseError(why.to_string()))),
} }
} }
pub fn get_mpv_property_string(instance: &Mpv, property: &str) -> Result<String, String> { pub fn get_mpv_property_string(instance: &Mpv, property: &str) -> Result<String, Error> {
let ipc_string = format!("{{ \"command\": [\"get_property\",\"{}\"] }}\n", property); let ipc_string = format!("{{ \"command\": [\"get_property\",\"{}\"] }}\n", property);
match serde_json::from_str::<Value>(&send_command_sync(instance, &ipc_string)) { match serde_json::from_str::<Value>(&send_command_sync(instance, &ipc_string)) {
Ok(val) => { Ok(val) => {
@ -230,39 +229,39 @@ pub fn get_mpv_property_string(instance: &Mpv, property: &str) -> Result<String,
Value::String(ref s) => Ok(s.to_string()), Value::String(ref s) => Ok(s.to_string()),
Value::Array(ref array) => Ok(format!("{:?}", array)), Value::Array(ref array) => Ok(format!("{:?}", array)),
Value::Object(ref map) => Ok(format!("{:?}", map)), Value::Object(ref map) => Ok(format!("{:?}", map)),
_ => Err("Value contains an unsupported type".to_string()), _ => Err(Error(ErrorCode::UnsupportedType)),
} }
} else { } else {
Err(error.to_string()) Err(Error(ErrorCode::MpvError(error.to_string())))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} else { } else {
Err("Unexpected value received".to_string()) Err(Error(ErrorCode::UnexpectedValueReceived))
} }
} }
Err(why) => Err(format!("Error while getting property: {}", why)), Err(why) => Err(Error(ErrorCode::JsonParseError(why.to_string()))),
} }
} }
pub fn set_mpv_property<T: TypeHandler>(instance: &Mpv, pub fn set_mpv_property<T: TypeHandler>(instance: &Mpv,
property: &str, property: &str,
value: T) value: T)
-> Result<(), String> { -> Result<(), Error> {
let ipc_string = format!("{{ \"command\": [\"set_property\", \"{}\", {}] }}\n", let ipc_string = format!("{{ \"command\": [\"set_property\", \"{}\", {}] }}\n",
property, property,
value.as_string()); value.as_string());
match serde_json::from_str::<Value>(&send_command_sync(instance, &ipc_string)) { match serde_json::from_str::<Value>(&send_command_sync(instance, &ipc_string)) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(why) => Err(why.description().to_string()), Err(why) => Err(Error(ErrorCode::JsonParseError(why.to_string()))),
} }
} }
pub fn run_mpv_command(instance: &Mpv, command: &str, args: &Vec<&str>) -> Result<(), String> { pub fn run_mpv_command(instance: &Mpv, command: &str, args: &[&str]) -> Result<(), Error> {
let mut ipc_string = format!("{{ \"command\": [\"{}\"", command); let mut ipc_string = format!("{{ \"command\": [\"{}\"", command);
if args.len() > 0 { if args.len() > 0 {
for arg in args.iter() { for arg in args {
ipc_string.push_str(&format!(", \"{}\"", arg)); ipc_string.push_str(&format!(", \"{}\"", arg));
} }
} }
@ -274,18 +273,17 @@ pub fn run_mpv_command(instance: &Mpv, command: &str, args: &Vec<&str>) -> Resul
if error == "success" { if error == "success" {
Ok(()) Ok(())
} else { } else {
Err(error.to_string()) Err(Error(ErrorCode::MpvError(error.to_string())))
} }
} else { } else {
//Ok(()) Err(Error(ErrorCode::UnexpectedResult))
Err("Error: Unexpected result received".to_string())
} }
} }
Err(why) => Err(why.description().to_string()), Err(why) => Err(Error(ErrorCode::JsonParseError(why.to_string()))),
} }
} }
pub fn observe_mpv_property(instance: &Mpv, id: &usize, property: &str) -> Result<(), String> { pub fn observe_mpv_property(instance: &Mpv, id: &usize, property: &str) -> Result<(), Error> {
let ipc_string = format!("{{ \"command\": [\"observe_property\", {}, \"{}\"] }}\n", let ipc_string = format!("{{ \"command\": [\"observe_property\", {}, \"{}\"] }}\n",
id, id,
property); property);
@ -295,13 +293,13 @@ pub fn observe_mpv_property(instance: &Mpv, id: &usize, property: &str) -> Resul
if error == "success" { if error == "success" {
Ok(()) Ok(())
} else { } else {
Err(error.to_string()) Err(Error(ErrorCode::MpvError(error.to_string())))
} }
} else { } else {
Err("Unexpected result received".to_string()) Err(Error(ErrorCode::UnexpectedResult))
} }
} }
Err(why) => Err(why.description().to_string()), Err(why) => Err(Error(ErrorCode::JsonParseError(why.to_string()))),
} }
} }
@ -324,15 +322,23 @@ pub fn listen(instance: &Mpv, tx: &Sender<String>) {
tx.send(name.to_string()).unwrap(); tx.send(name.to_string()).unwrap();
} }
} }
Err(why) => panic!("{}", why.description().to_string()), Err(why) => panic!("{}", why.to_string()),
} }
response.clear(); response.clear();
} }
pub fn listen_raw(instance: &Mpv, tx: &Sender<String>) {
let mut response = String::new();
let mut reader = BufReader::new(instance);
reader.read_line(&mut response).unwrap();
tx.send(response.clone()).unwrap();
response.clear();
}
fn send_command_sync(instance: &Mpv, command: &str) -> String { fn send_command_sync(instance: &Mpv, command: &str) -> String {
let mut stream = instance; let mut stream = instance;
match stream.write_all(command.as_bytes()) { match stream.write_all(command.as_bytes()) {
Err(why) => panic!("Error: Could not write to socket: {}", why.description()), Err(why) => panic!("Error: Could not write to socket: {}", why),
Ok(_) => { Ok(_) => {
let mut response = String::new(); let mut response = String::new();
{ {

View File

@ -5,6 +5,7 @@ pub mod ipc;
use ipc::*; use ipc::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::{self, Display};
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
use std::sync::mpsc::Sender; use std::sync::mpsc::Sender;
@ -35,51 +36,108 @@ pub enum Switch {
Toggle, Toggle,
} }
#[derive(Debug)]
pub enum ErrorCode {
MpvError(String),
JsonParseError(String),
ConnectError(String),
UnexpectedResult,
UnexpectedValueReceived,
UnsupportedType,
ValueDoesNotContainBool,
ValueDoesNotContainF64,
ValueDoesNotContainHashMap,
ValueDoesNotContainPlaylist,
ValueDoesNotContainString,
ValueDoesNotContainUsize,
}
pub struct Playlist(pub Vec<PlaylistEntry>); pub struct Playlist(pub Vec<PlaylistEntry>);
#[derive(Debug)]
pub struct Error(pub ErrorCode);
pub trait MpvConnector { pub trait MpvConnector {
fn connect(socket: &str) -> Result<Mpv, String>; fn connect(socket: &str) -> Result<Mpv, Error>;
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ErrorCode::ConnectError(ref msg) => f.write_str(&format!("ConnectError: {}", msg)),
ErrorCode::JsonParseError(ref msg) => f.write_str(&format!("JsonParseError: {}", msg)),
ErrorCode::MpvError(ref msg) => {
f.write_str(&format!("mpv returned an error value: {}", msg))
}
ErrorCode::UnexpectedResult => f.write_str("Unexpected result received"),
ErrorCode::UnexpectedValueReceived => f.write_str("Unexpected value received"),
ErrorCode::UnsupportedType => f.write_str("Unsupported type received"),
ErrorCode::ValueDoesNotContainBool => {
f.write_str("The received value is not of type \'std::bool\'")
}
ErrorCode::ValueDoesNotContainF64 => {
f.write_str("The received value is not of type \'std::f64\'")
}
ErrorCode::ValueDoesNotContainHashMap => {
f.write_str("The received value is not of type \'std::collections::HashMap\'")
}
ErrorCode::ValueDoesNotContainPlaylist => {
f.write_str("The received value is not of type \'mpvipc::Playlist\'")
}
ErrorCode::ValueDoesNotContainString => {
f.write_str("The received value is not of type \'std::string::String\'")
}
ErrorCode::ValueDoesNotContainUsize => {
f.write_str("The received value is not of type \'std::usize\'")
}
}
}
} }
impl MpvConnector for Mpv { impl MpvConnector for Mpv {
fn connect(socket: &str) -> Result<Mpv, String> { fn connect(socket: &str) -> Result<Mpv, Error> {
match UnixStream::connect(socket) { match UnixStream::connect(socket) {
Ok(stream) => Ok(stream), Ok(stream) => Ok(stream),
Err(msg) => Err(msg.to_string()), Err(internal_error) => Err(Error(ErrorCode::ConnectError(internal_error.to_string()))),
} }
} }
} }
pub trait GetPropertyTypeHandler: Sized { pub trait GetPropertyTypeHandler: Sized {
fn get_property_generic(instance: &Mpv, property: &str) -> Result<Self, String>; fn get_property_generic(instance: &Mpv, property: &str) -> Result<Self, Error>;
} }
impl GetPropertyTypeHandler for bool { impl GetPropertyTypeHandler for bool {
fn get_property_generic(instance: &Mpv, property: &str) -> Result<bool, String> { fn get_property_generic(instance: &Mpv, property: &str) -> Result<bool, Error> {
get_mpv_property::<bool>(instance, property) get_mpv_property::<bool>(instance, property)
} }
} }
impl GetPropertyTypeHandler for String { impl GetPropertyTypeHandler for String {
fn get_property_generic(instance: &Mpv, property: &str) -> Result<String, String> { fn get_property_generic(instance: &Mpv, property: &str) -> Result<String, Error> {
get_mpv_property::<String>(instance, property) get_mpv_property::<String>(instance, property)
} }
} }
impl GetPropertyTypeHandler for f64 { impl GetPropertyTypeHandler for f64 {
fn get_property_generic(instance: &Mpv, property: &str) -> Result<f64, String> { fn get_property_generic(instance: &Mpv, property: &str) -> Result<f64, Error> {
get_mpv_property::<f64>(instance, property) get_mpv_property::<f64>(instance, property)
} }
} }
impl GetPropertyTypeHandler for usize { impl GetPropertyTypeHandler for usize {
fn get_property_generic(instance: &Mpv, property: &str) -> Result<usize, String> { fn get_property_generic(instance: &Mpv, property: &str) -> Result<usize, Error> {
get_mpv_property::<usize>(instance, property) get_mpv_property::<usize>(instance, property)
} }
} }
impl GetPropertyTypeHandler for Vec<PlaylistEntry> { impl GetPropertyTypeHandler for Vec<PlaylistEntry> {
fn get_property_generic(instance: &Mpv, property: &str) -> Result<Vec<PlaylistEntry>, String> { fn get_property_generic(instance: &Mpv, property: &str) -> Result<Vec<PlaylistEntry>, Error> {
get_mpv_property::<Vec<PlaylistEntry>>(instance, property) get_mpv_property::<Vec<PlaylistEntry>>(instance, property)
} }
} }
@ -87,42 +145,42 @@ impl GetPropertyTypeHandler for Vec<PlaylistEntry> {
impl GetPropertyTypeHandler for HashMap<String, String> { impl GetPropertyTypeHandler for HashMap<String, String> {
fn get_property_generic(instance: &Mpv, fn get_property_generic(instance: &Mpv,
property: &str) property: &str)
-> Result<HashMap<String, String>, String> { -> Result<HashMap<String, String>, Error> {
get_mpv_property::<HashMap<String, String>>(instance, property) get_mpv_property::<HashMap<String, String>>(instance, property)
} }
} }
pub trait SetPropertyTypeHandler<T> { pub trait SetPropertyTypeHandler<T> {
fn set_property_generic(instance: &Mpv, property: &str, value: T) -> Result<(), String>; fn set_property_generic(instance: &Mpv, property: &str, value: T) -> Result<(), Error>;
} }
impl SetPropertyTypeHandler<bool> for bool { impl SetPropertyTypeHandler<bool> for bool {
fn set_property_generic(instance: &Mpv, property: &str, value: bool) -> Result<(), String> { fn set_property_generic(instance: &Mpv, property: &str, value: bool) -> Result<(), Error> {
set_mpv_property::<bool>(instance, property, value) set_mpv_property::<bool>(instance, property, value)
} }
} }
impl SetPropertyTypeHandler<String> for String { impl SetPropertyTypeHandler<String> for String {
fn set_property_generic(instance: &Mpv, property: &str, value: String) -> Result<(), String> { fn set_property_generic(instance: &Mpv, property: &str, value: String) -> Result<(), Error> {
set_mpv_property::<String>(instance, property, value) set_mpv_property::<String>(instance, property, value)
} }
} }
impl SetPropertyTypeHandler<f64> for f64 { impl SetPropertyTypeHandler<f64> for f64 {
fn set_property_generic(instance: &Mpv, property: &str, value: f64) -> Result<(), String> { fn set_property_generic(instance: &Mpv, property: &str, value: f64) -> Result<(), Error> {
set_mpv_property::<f64>(instance, property, value) set_mpv_property::<f64>(instance, property, value)
} }
} }
impl SetPropertyTypeHandler<usize> for usize { impl SetPropertyTypeHandler<usize> for usize {
fn set_property_generic(instance: &Mpv, property: &str, value: usize) -> Result<(), String> { fn set_property_generic(instance: &Mpv, property: &str, value: usize) -> Result<(), Error> {
set_mpv_property::<usize>(instance, property, value) set_mpv_property::<usize>(instance, property, value)
} }
} }
pub trait Commands { pub trait Commands {
fn get_metadata(&self) -> Result<HashMap<String, String>, String>; fn get_metadata(&self) -> Result<HashMap<String, String>, Error>;
fn get_playlist(&self) -> Result<Playlist, String>; fn get_playlist(&self) -> Result<Playlist, Error>;
/// #Description /// #Description
/// ///
@ -138,7 +196,6 @@ pub trait Commands {
/// ///
/// ##Input arguments /// ##Input arguments
/// ///
/// - **socket** defines the socket that ipc connects to
/// - **property** defines the mpv property that should be retrieved /// - **property** defines the mpv property that should be retrieved
/// ///
/// #Example /// #Example
@ -147,7 +204,7 @@ pub trait Commands {
/// let paused: bool = mpv.get_property("pause").unwrap(); /// let paused: bool = mpv.get_property("pause").unwrap();
/// let title: String = mpv.get_property("media-title").unwrap(); /// let title: String = mpv.get_property("media-title").unwrap();
/// ``` /// ```
fn get_property<T: GetPropertyTypeHandler>(&self, property: &str) -> Result<T, String>; fn get_property<T: GetPropertyTypeHandler>(&self, property: &str) -> Result<T, Error>;
/// #Description /// #Description
/// ///
@ -156,7 +213,6 @@ pub trait Commands {
/// ///
/// ##Input arguments /// ##Input arguments
/// ///
/// - **socket** defines the socket that ipc connects to
/// - **property** defines the mpv property that should be retrieved /// - **property** defines the mpv property that should be retrieved
/// ///
/// #Example /// #Example
@ -165,21 +221,22 @@ pub trait Commands {
/// let mpv = Mpv::connect("/tmp/mpvsocket").unwrap(); /// let mpv = Mpv::connect("/tmp/mpvsocket").unwrap();
/// let title = mpv.get_property_string("media-title").unwrap(); /// let title = mpv.get_property_string("media-title").unwrap();
/// ``` /// ```
fn get_property_string(&self, property: &str) -> Result<String, String>; fn get_property_string(&self, property: &str) -> Result<String, Error>;
fn kill(&self) -> Result<(), String>; fn kill(&self) -> Result<(), Error>;
fn listen(&self, tx: &Sender<String>); fn listen(&self, tx: &Sender<String>);
fn next(&self) -> Result<(), String>; fn listen_raw(&self, tx: &Sender<String>);
fn observe_property(&self, id: &usize, property: &str) -> Result<(), String>; fn next(&self) -> Result<(), Error>;
fn pause(&self) -> Result<(), String>; fn observe_property(&self, id: &usize, property: &str) -> Result<(), Error>;
fn playlist_add(&self, file: &str, option: PlaylistAddOptions) -> Result<(), String>; fn pause(&self) -> Result<(), Error>;
fn playlist_clear(&self) -> Result<(), String>; fn playlist_add(&self, file: &str, option: PlaylistAddOptions) -> Result<(), Error>;
fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), String>; fn playlist_clear(&self) -> Result<(), Error>;
fn playlist_play_id(&self, id: usize) -> Result<(), String>; fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), Error>;
fn playlist_play_next(&self, id: usize) -> Result<(), String>; fn playlist_play_id(&self, id: usize) -> Result<(), Error>;
fn playlist_shuffle(&self) -> Result<(), String>; fn playlist_play_next(&self, id: usize) -> Result<(), Error>;
fn playlist_remove_id(&self, id: usize) -> Result<(), String>; fn playlist_shuffle(&self) -> Result<(), Error>;
fn prev(&self) -> Result<(), String>; fn playlist_remove_id(&self, id: usize) -> Result<(), Error>;
fn restart(&self) -> Result<(), String>; fn prev(&self) -> Result<(), Error>;
fn restart(&self) -> Result<(), Error>;
/// #Description /// #Description
/// ///
@ -190,16 +247,16 @@ pub trait Commands {
/// let mpv = Mpv::connect("/tmp/mpvsocket").unwrap(); /// let mpv = Mpv::connect("/tmp/mpvsocket").unwrap();
/// ///
/// //Run command 'playlist-shuffle' which takes no arguments /// //Run command 'playlist-shuffle' which takes no arguments
/// mpv.run_command("playlist-shuffle", &vec![]); /// mpv.run_command("playlist-shuffle", &[]);
/// ///
/// //Run command 'seek' which in this case takes two arguments /// //Run command 'seek' which in this case takes two arguments
/// mpv.run_command("seek", &vec!["0", "absolute"]); /// mpv.run_command("seek", &["0", "absolute"]);
/// ``` /// ```
fn run_command(&self, command: &str, args: &Vec<&str>) -> Result<(), String>; fn run_command(&self, command: &str, args: &[&str]) -> Result<(), Error>;
fn seek(&self, seconds: f64, option: SeekOptions) -> Result<(), String>; fn seek(&self, seconds: f64, option: SeekOptions) -> Result<(), Error>;
fn set_loop_file(&self, option: Switch) -> Result<(), String>; fn set_loop_file(&self, option: Switch) -> Result<(), Error>;
fn set_loop_playlist(&self, option: Switch) -> Result<(), String>; fn set_loop_playlist(&self, option: Switch) -> Result<(), Error>;
fn set_mute(&self, option: Switch) -> Result<(), String>; fn set_mute(&self, option: Switch) -> Result<(), Error>;
/// #Description /// #Description
/// ///
@ -224,135 +281,133 @@ pub trait Commands {
fn set_property<T: SetPropertyTypeHandler<T>>(&self, fn set_property<T: SetPropertyTypeHandler<T>>(&self,
property: &str, property: &str,
value: T) value: T)
-> Result<(), String>; -> Result<(), Error>;
fn set_speed(&self, input_volume: f64, option: NumberChangeOptions) -> Result<(), String>; fn set_speed(&self, input_volume: f64, option: NumberChangeOptions) -> Result<(), Error>;
fn set_volume(&self, input_volume: f64, option: NumberChangeOptions) -> Result<(), String>; fn set_volume(&self, input_volume: f64, option: NumberChangeOptions) -> Result<(), Error>;
fn stop(&self) -> Result<(), String>; fn stop(&self) -> Result<(), Error>;
fn toggle(&self) -> Result<(), String>; fn toggle(&self) -> Result<(), Error>;
} }
impl Commands for Mpv { impl Commands for Mpv {
fn get_metadata(&self) -> Result<HashMap<String, String>, String> { fn get_metadata(&self) -> Result<HashMap<String, String>, Error> {
match get_mpv_property(self, "metadata") { match get_mpv_property(self, "metadata") {
Ok(map) => Ok(map), Ok(map) => Ok(map),
Err(err) => Err(err), Err(err) => Err(err),
} }
} }
fn get_playlist(&self) -> Result<Playlist, String> { fn get_playlist(&self) -> Result<Playlist, Error> {
match get_mpv_property::<Vec<PlaylistEntry>>(self, "playlist") { match get_mpv_property::<Vec<PlaylistEntry>>(self, "playlist") {
Ok(entries) => Ok(Playlist(entries)), Ok(entries) => Ok(Playlist(entries)),
Err(msg) => Err(msg), Err(msg) => Err(msg),
} }
} }
fn get_property<T: GetPropertyTypeHandler>(&self, property: &str) -> Result<T, String> { fn get_property<T: GetPropertyTypeHandler>(&self, property: &str) -> Result<T, Error> {
T::get_property_generic(self, property) T::get_property_generic(self, property)
} }
fn get_property_string(&self, property: &str) -> Result<String, String> { fn get_property_string(&self, property: &str) -> Result<String, Error> {
get_mpv_property_string(self, property) get_mpv_property_string(self, property)
} }
fn kill(&self) -> Result<(), String> { fn kill(&self) -> Result<(), Error> {
run_mpv_command(self, "quit", &vec![]) run_mpv_command(self, "quit", &[])
} }
fn listen(&self, tx: &Sender<String>) { fn listen(&self, tx: &Sender<String>) {
listen(self, tx); listen(self, tx);
} }
fn next(&self) -> Result<(), String> { fn listen_raw(&self, tx: &Sender<String>) {
run_mpv_command(self, "playlist-next", &vec![]) listen_raw(self, tx);
} }
fn observe_property(&self, id: &usize, property: &str) -> Result<(), String> { fn next(&self) -> Result<(), Error> {
run_mpv_command(self, "playlist-next", &[])
}
fn observe_property(&self, id: &usize, property: &str) -> Result<(), Error> {
observe_mpv_property(self, id, property) observe_mpv_property(self, id, property)
} }
fn pause(&self) -> Result<(), String> { fn pause(&self) -> Result<(), Error> {
set_mpv_property(self, "pause", true) set_mpv_property(self, "pause", true)
} }
fn prev(&self) -> Result<(), String> { fn prev(&self) -> Result<(), Error> {
run_mpv_command(self, "playlist-prev", &vec![]) run_mpv_command(self, "playlist-prev", &[])
} }
fn restart(&self) -> Result<(), String> { fn restart(&self) -> Result<(), Error> {
run_mpv_command(self, "seek", &vec!["0", "absolute"]) run_mpv_command(self, "seek", &["0", "absolute"])
} }
fn run_command(&self, command: &str, args: &Vec<&str>) -> Result<(), String> { fn run_command(&self, command: &str, args: &[&str]) -> Result<(), Error> {
run_mpv_command(self, command, args) run_mpv_command(self, command, args)
} }
fn playlist_add(&self, file: &str, option: PlaylistAddOptions) -> Result<(), String> { fn playlist_add(&self, file: &str, option: PlaylistAddOptions) -> Result<(), Error> {
match option { match option {
PlaylistAddOptions::Replace => { PlaylistAddOptions::Replace => run_mpv_command(self, "loadfile", &[file, "replace"]),
run_mpv_command(self, "loadfile", &vec![file, "replace"]) PlaylistAddOptions::Append => run_mpv_command(self, "loadfile", &[file, "append"]),
}
PlaylistAddOptions::Append => run_mpv_command(self, "loadfile", &vec![file, "append"]),
PlaylistAddOptions::AppendPlay => { PlaylistAddOptions::AppendPlay => {
run_mpv_command(self, "loadfile", &vec![file, "append-play"]) run_mpv_command(self, "loadfile", &[file, "append-play"])
} }
} }
} }
fn playlist_clear(&self) -> Result<(), String> { fn playlist_clear(&self) -> Result<(), Error> {
run_mpv_command(self, "playlist-clear", &vec![]) run_mpv_command(self, "playlist-clear", &[])
} }
fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), String> { fn playlist_move_id(&self, from: usize, to: usize) -> Result<(), Error> {
run_mpv_command(self, run_mpv_command(self,
"playlist-remove", "playlist-remove",
&vec![&from.to_string(), &to.to_string()]) &[&from.to_string(), &to.to_string()])
} }
fn playlist_play_id(&self, id: usize) -> Result<(), String> { fn playlist_play_id(&self, id: usize) -> Result<(), Error> {
set_mpv_property(self, "playlist-pos", id) set_mpv_property(self, "playlist-pos", id)
} }
fn playlist_play_next(&self, id: usize) -> Result<(), String> { fn playlist_play_next(&self, id: usize) -> Result<(), Error> {
match get_mpv_property::<usize>(self, "playlist-pos") { match get_mpv_property::<usize>(self, "playlist-pos") {
Ok(current_id) => { Ok(current_id) => {
run_mpv_command(self, run_mpv_command(self,
"playlist-move", "playlist-move",
&vec![&id.to_string(), &(current_id + 1).to_string()]) &[&id.to_string(), &(current_id + 1).to_string()])
} }
Err(msg) => Err(msg), Err(msg) => Err(msg),
} }
} }
fn playlist_remove_id(&self, id: usize) -> Result<(), String> { fn playlist_remove_id(&self, id: usize) -> Result<(), Error> {
run_mpv_command(self, "playlist-remove", &vec![&id.to_string()]) run_mpv_command(self, "playlist-remove", &[&id.to_string()])
} }
fn playlist_shuffle(&self) -> Result<(), String> { fn playlist_shuffle(&self) -> Result<(), Error> {
run_mpv_command(self, "playlist-shuffle", &vec![]) run_mpv_command(self, "playlist-shuffle", &[])
} }
fn seek(&self, seconds: f64, option: SeekOptions) -> Result<(), String> { fn seek(&self, seconds: f64, option: SeekOptions) -> Result<(), Error> {
match option { match option {
SeekOptions::Absolute => { SeekOptions::Absolute => {
run_mpv_command(self, "seek", &vec![&seconds.to_string(), "absolute"]) run_mpv_command(self, "seek", &[&seconds.to_string(), "absolute"])
} }
SeekOptions::AbsolutePercent => { SeekOptions::AbsolutePercent => {
run_mpv_command(self, run_mpv_command(self, "seek", &[&seconds.to_string(), "absolute-percent"])
"seek",
&vec![&seconds.to_string(), "absolute-percent"])
} }
SeekOptions::Relative => { SeekOptions::Relative => {
run_mpv_command(self, "seek", &vec![&seconds.to_string(), "relative"]) run_mpv_command(self, "seek", &[&seconds.to_string(), "relative"])
} }
SeekOptions::RelativePercent => { SeekOptions::RelativePercent => {
run_mpv_command(self, run_mpv_command(self, "seek", &[&seconds.to_string(), "relative-percent"])
"seek",
&vec![&seconds.to_string(), "relative-percent"])
} }
} }
} }
fn set_loop_file(&self, option: Switch) -> Result<(), String> { fn set_loop_file(&self, option: Switch) -> Result<(), Error> {
let mut enabled = false; let mut enabled = false;
match option { match option {
Switch::On => enabled = true, Switch::On => enabled = true,
@ -376,7 +431,7 @@ impl Commands for Mpv {
set_mpv_property(self, "loop-file", enabled) set_mpv_property(self, "loop-file", enabled)
} }
fn set_loop_playlist(&self, option: Switch) -> Result<(), String> { fn set_loop_playlist(&self, option: Switch) -> Result<(), Error> {
let mut enabled = false; let mut enabled = false;
match option { match option {
Switch::On => enabled = true, Switch::On => enabled = true,
@ -400,7 +455,7 @@ impl Commands for Mpv {
set_mpv_property(self, "loop-playlist", enabled) set_mpv_property(self, "loop-playlist", enabled)
} }
fn set_mute(&self, option: Switch) -> Result<(), String> { fn set_mute(&self, option: Switch) -> Result<(), Error> {
let mut enabled = false; let mut enabled = false;
match option { match option {
Switch::On => enabled = true, Switch::On => enabled = true,
@ -420,11 +475,11 @@ impl Commands for Mpv {
fn set_property<T: SetPropertyTypeHandler<T>>(&self, fn set_property<T: SetPropertyTypeHandler<T>>(&self,
property: &str, property: &str,
value: T) value: T)
-> Result<(), String> { -> Result<(), Error> {
T::set_property_generic(self, property, value) T::set_property_generic(self, property, value)
} }
fn set_speed(&self, input_speed: f64, option: NumberChangeOptions) -> Result<(), String> { fn set_speed(&self, input_speed: f64, option: NumberChangeOptions) -> Result<(), Error> {
match get_mpv_property::<f64>(self, "speed") { match get_mpv_property::<f64>(self, "speed") {
Ok(speed) => { Ok(speed) => {
match option { match option {
@ -443,7 +498,7 @@ impl Commands for Mpv {
} }
} }
fn set_volume(&self, input_volume: f64, option: NumberChangeOptions) -> Result<(), String> { fn set_volume(&self, input_volume: f64, option: NumberChangeOptions) -> Result<(), Error> {
match get_mpv_property::<f64>(self, "volume") { match get_mpv_property::<f64>(self, "volume") {
Ok(volume) => { Ok(volume) => {
match option { match option {
@ -462,11 +517,11 @@ impl Commands for Mpv {
} }
} }
fn stop(&self) -> Result<(), String> { fn stop(&self) -> Result<(), Error> {
run_mpv_command(self, "stop", &vec![]) run_mpv_command(self, "stop", &[])
} }
fn toggle(&self) -> Result<(), String> { fn toggle(&self) -> Result<(), Error> {
match get_mpv_property::<bool>(self, "pause") { match get_mpv_property::<bool>(self, "pause") {
Ok(paused) => set_mpv_property(self, "pause", !paused), Ok(paused) => set_mpv_property(self, "pause", !paused),
Err(msg) => Err(msg), Err(msg) => Err(msg),