Create the query executor
This commit is contained in:
parent
9c92f690fc
commit
0832665fb2
1 changed files with 81 additions and 11 deletions
|
@ -1,4 +1,5 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Display;
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use typed_builder::TypedBuilder;
|
use typed_builder::TypedBuilder;
|
||||||
|
@ -24,21 +25,46 @@ pub struct Track {
|
||||||
pub position: u32,
|
pub position: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum CmusError {
|
||||||
|
CmusRunningError(String),
|
||||||
|
UnknownStatus,
|
||||||
|
NoStatus,
|
||||||
|
EmptyPath,
|
||||||
|
DurationError(String),
|
||||||
|
PositionError(String),
|
||||||
|
UnknownError(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for CmusError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
CmusError::CmusRunningError(s) => write!(f, "Cmus running error: {}", s),
|
||||||
|
CmusError::UnknownStatus => write!(f, "Unknown status"),
|
||||||
|
CmusError::NoStatus => write!(f, "No status"),
|
||||||
|
CmusError::EmptyPath => write!(f, "Empty path"),
|
||||||
|
CmusError::DurationError(s) => write!(f, "Duration error: {}", s),
|
||||||
|
CmusError::PositionError(s) => write!(f, "Position error: {}", s),
|
||||||
|
CmusError::UnknownError(s) => write!(f, "Unknown error: {}", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FromStr for TrackStatus {
|
impl FromStr for TrackStatus {
|
||||||
type Err = String;
|
type Err = CmusError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s {
|
match s {
|
||||||
"playing" => Ok(TrackStatus::Playing),
|
"playing" => Ok(TrackStatus::Playing),
|
||||||
"paused" => Ok(TrackStatus::Paused),
|
"paused" => Ok(TrackStatus::Paused),
|
||||||
"stopped" => Ok(TrackStatus::Stopped),
|
"stopped" => Ok(TrackStatus::Stopped),
|
||||||
_ => Err(format!("Unknown status: {}", s)),
|
_ => Err(CmusError::UnknownStatus),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Track {
|
impl FromStr for Track {
|
||||||
type Err = String;
|
type Err = CmusError;
|
||||||
|
|
||||||
/// Creates a `Track` from the output of `cmus-remote -Q`.
|
/// Creates a `Track` from the output of `cmus-remote -Q`.
|
||||||
///
|
///
|
||||||
|
@ -49,18 +75,20 @@ impl FromStr for Track {
|
||||||
let mut lines = s.lines();
|
let mut lines = s.lines();
|
||||||
|
|
||||||
Ok(Track::builder().status(
|
Ok(Track::builder().status(
|
||||||
TrackStatus::from_str(lines.next().ok_or("Missing status")?.split_once(' ')
|
TrackStatus::from_str(lines.next().ok_or(CmusError::NoStatus)?.split_once(' ')
|
||||||
.ok_or("Unknown status")?.1)?
|
.ok_or(CmusError::NoStatus)?.1)?
|
||||||
)
|
)
|
||||||
.path(lines.next().ok_or("Missing path")?.split_once(' ')
|
.path(lines.next().ok_or(CmusError::EmptyPath)?.split_once(' ')
|
||||||
.ok_or("Empty path")?.1.to_string())
|
.ok_or(CmusError::EmptyPath)?.1.to_string())
|
||||||
.duration(
|
.duration(
|
||||||
lines.next().ok_or("Missing duration")?.split_once(' ')
|
lines.next().ok_or(CmusError::DurationError("Missing duration".to_string()))?.split_once(' ')
|
||||||
.ok_or("Empty duration")?.1.parse().map_err(|e: ParseIntError| e.to_string())?
|
.ok_or(CmusError::DurationError("Empty duration".to_string()))?.1.parse()
|
||||||
|
.map_err(|e: ParseIntError| CmusError::DurationError(e.to_string()))?
|
||||||
)
|
)
|
||||||
.position(
|
.position(
|
||||||
lines.next().ok_or("Missing position")?.split_once(' ')
|
lines.next().ok_or(CmusError::PositionError("Missing position".to_string()))?.split_once(' ')
|
||||||
.ok_or("Empty position")?.1.parse().map_err(|e: ParseIntError| e.to_string())?
|
.ok_or(CmusError::PositionError("Empty position".to_string()))?.1.parse()
|
||||||
|
.map_err(|e: ParseIntError| CmusError::PositionError(e.to_string()))?
|
||||||
)
|
)
|
||||||
.metadata(TrackMetadata::parse(lines))
|
.metadata(TrackMetadata::parse(lines))
|
||||||
.build())
|
.build())
|
||||||
|
@ -105,6 +133,38 @@ impl Track {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Make a status request to cmus.
|
||||||
|
/// And collect the output, and parse it into a `Track`.
|
||||||
|
/// If the cmus is not running, or the socket is not available, this function will return an error.
|
||||||
|
pub fn get_track(cmus_remote_bin: &[&str], socket_addr: Option<&str>, socket_pass: Option<&str>) -> Result<Track, CmusError> {
|
||||||
|
let mut command = std::process::Command::new(cmus_remote_bin[0]);
|
||||||
|
|
||||||
|
for arg in cmus_remote_bin.iter().skip(1) {
|
||||||
|
command.arg(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(socket_addr) = socket_addr {
|
||||||
|
command.arg("--server").arg(socket_addr); // Use the socket instead of the default socket.
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(socket_pass) = socket_pass {
|
||||||
|
command.arg("--passwd").arg(socket_pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
command.arg("-Q");
|
||||||
|
|
||||||
|
let output = command.output().map_err(|e| CmusError::CmusRunningError(e.to_string()))?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
return Err(CmusError::CmusRunningError(String::from_utf8(output.stderr)
|
||||||
|
.map_err(|e| CmusError::UnknownError(e.to_string()))?));
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = String::from_utf8(output.stdout).map_err(|e| CmusError::UnknownError(e.to_string()))?;
|
||||||
|
|
||||||
|
Track::from_str(&output).map_err(|e| CmusError::UnknownError(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -174,4 +234,14 @@ mod tests {
|
||||||
assert_eq!(metadata.tags.get("publisher"), Some(&"mudhutdigital.com".to_string()));
|
assert_eq!(metadata.tags.get("publisher"), Some(&"mudhutdigital.com".to_string()));
|
||||||
assert_eq!(metadata.tags.get("bpm"), Some(&"146".to_string()));
|
assert_eq!(metadata.tags.get("bpm"), Some(&"146".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_get_track() {
|
||||||
|
let track = get_track(&["cmus-remote"], None, None);
|
||||||
|
|
||||||
|
assert_matches!(track, Ok(_));
|
||||||
|
|
||||||
|
println!("{:?}", track);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue