aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pkgs/by-name/mp/mpdpopm/Cargo.lock91
-rw-r--r--pkgs/by-name/mp/mpdpopm/Cargo.toml3
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs211
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/bin/mpdpopmd.rs117
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/clients.rs309
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/config.rs34
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/filters_ast.rs227
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/lib.rs116
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/messages.rs165
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/playcounts.rs86
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/storage/mod.rs103
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/vars.rs1
12 files changed, 215 insertions, 1248 deletions
diff --git a/pkgs/by-name/mp/mpdpopm/Cargo.lock b/pkgs/by-name/mp/mpdpopm/Cargo.lock
index fbedffd4..96909646 100644
--- a/pkgs/by-name/mp/mpdpopm/Cargo.lock
+++ b/pkgs/by-name/mp/mpdpopm/Cargo.lock
@@ -3,21 +3,6 @@
version = 4
[[package]]
-name = "addr2line"
-version = "0.25.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
-dependencies = [
- "gimli",
-]
-
-[[package]]
-name = "adler2"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
-
-[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -86,6 +71,12 @@ dependencies = [
]
[[package]]
+name = "anyhow"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
+
+[[package]]
name = "ascii-canvas"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -112,21 +103,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
-name = "backtrace"
-version = "0.3.76"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
-dependencies = [
- "addr2line",
- "cfg-if",
- "libc",
- "miniz_oxide",
- "object",
- "rustc-demangle",
- "windows-link",
-]
-
-[[package]]
name = "bit-set"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -427,12 +403,6 @@ dependencies = [
]
[[package]]
-name = "gimli"
-version = "0.32.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
-
-[[package]]
name = "hashbrown"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -593,15 +563,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
-name = "miniz_oxide"
-version = "0.8.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
-dependencies = [
- "adler2",
-]
-
-[[package]]
name = "mio"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -616,8 +577,8 @@ dependencies = [
name = "mpdpopm"
version = "0.1.0"
dependencies = [
+ "anyhow",
"async-trait",
- "backtrace",
"boolinator",
"chrono",
"clap",
@@ -631,7 +592,6 @@ dependencies = [
"regex",
"serde",
"serde_json",
- "snafu",
"tokio",
"toml",
"tracing",
@@ -663,15 +623,6 @@ dependencies = [
]
[[package]]
-name = "object"
-version = "0.37.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
-dependencies = [
- "memchr",
-]
-
-[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -835,12 +786,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]]
-name = "rustc-demangle"
-version = "0.1.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
-
-[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -967,28 +912,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
-name = "snafu"
-version = "0.8.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2"
-dependencies = [
- "backtrace",
- "snafu-derive",
-]
-
-[[package]]
-name = "snafu-derive"
-version = "0.8.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "socket2"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/pkgs/by-name/mp/mpdpopm/Cargo.toml b/pkgs/by-name/mp/mpdpopm/Cargo.toml
index ccadfabb..c82537e6 100644
--- a/pkgs/by-name/mp/mpdpopm/Cargo.toml
+++ b/pkgs/by-name/mp/mpdpopm/Cargo.toml
@@ -25,7 +25,6 @@ lalrpop = { version = "0.22", features = ["lexer"] }
[dependencies]
async-trait = "0.1"
-backtrace = "0.3"
boolinator = "2.4"
chrono = "0.4"
clap = {version = "4.5", features = ["derive"]}
@@ -38,8 +37,8 @@ pin-project = "1.1"
regex = "1.12"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.149"
-snafu = { version = "0.8.9", features = ["backtrace"] }
toml = "0.9"
tokio = { version = "1.49", features = ["io-util", "macros", "net", "process", "rt-multi-thread", "signal", "sync", "time"] }
tracing = "0.1.44"
tracing-subscriber = { version = "0.3.22", features = ["env-filter"]}
+anyhow = "1.0.100"
diff --git a/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs b/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs
index 82a354d6..d9d607d5 100644
--- a/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs
+++ b/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs
@@ -32,82 +32,12 @@ use mpdpopm::{
storage::{last_played, play_count, rating_count},
};
-use backtrace::Backtrace;
+use anyhow::{Context, Result, anyhow, bail};
use clap::{Parser, Subcommand};
use tracing::{debug, info, level_filters::LevelFilter, trace};
use tracing_subscriber::{EnvFilter, Registry, layer::SubscriberExt};
-use std::{fmt, path::PathBuf};
-
-#[non_exhaustive]
-pub enum Error {
- NoSubCommand,
- NoConfigArg,
- NoRating,
- NoPlayCount,
- NoLastPlayed,
- NoConfig {
- config: std::path::PathBuf,
- cause: std::io::Error,
- },
- PlayerStopped,
- BadPath {
- path: PathBuf,
- back: Backtrace,
- },
- NoPlaylist,
- Client {
- source: mpdpopm::clients::Error,
- back: Backtrace,
- },
- Ratings {
- source: Box<mpdpopm::storage::Error>,
- back: Backtrace,
- },
- Playcounts {
- source: Box<mpdpopm::storage::Error>,
- back: Backtrace,
- },
- ExpectedInt {
- source: std::num::ParseIntError,
- back: Backtrace,
- },
- Config {
- source: crate::config::Error,
- back: Backtrace,
- },
-}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Error::NoSubCommand => write!(f, "No sub-command given"),
- Error::NoConfigArg => write!(f, "No argument given for the configuration option"),
- Error::NoRating => write!(f, "No rating supplied"),
- Error::NoPlayCount => write!(f, "No play count supplied"),
- Error::NoLastPlayed => write!(f, "No last played timestamp given"),
- Error::NoConfig { config, cause } => write!(f, "Bad config ({:?}): {}", config, cause),
- Error::PlayerStopped => write!(f, "The player is stopped"),
- Error::BadPath { path, back: _ } => write!(f, "Bad path: {:?}", path),
- Error::NoPlaylist => write!(f, "No playlist given"),
- Error::Client { source, back: _ } => write!(f, "Client error: {}", source),
- Error::Ratings { source, back: _ } => write!(f, "Rating error: {}", source),
- Error::Playcounts { source, back: _ } => write!(f, "Playcount error: {}", source),
- Error::ExpectedInt { source, back: _ } => write!(f, "Expected integer: {}", source),
- Error::Config { source, back: _ } => {
- write!(f, "Error reading configuration: {}", source)
- }
- }
- }
-}
-
-impl fmt::Debug for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self)
- }
-}
-
-type Result<T> = std::result::Result<T, Error>;
+use std::path::PathBuf;
/// Map `tracks' argument(s) to a Vec of String containing one or more mpd URIs
///
@@ -132,20 +62,18 @@ async fn provide_file(client: &mut Client, maybe_file: Option<String>) -> Result
let file = match maybe_file {
Some(file) => file,
None => {
- match client.status().await.map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })? {
+ match client
+ .status()
+ .await
+ .context("Failed to get status of client")?
+ {
PlayerStatus::Play(curr) | PlayerStatus::Pause(curr) => curr
.file
.to_str()
- .ok_or_else(|| Error::BadPath {
- path: curr.file.clone(),
- back: Backtrace::new(),
- })?
+ .ok_or_else(|| anyhow!("Path is not utf8: `{}`", curr.file.display()))?
.to_string(),
PlayerStatus::Stopped => {
- return Err(Error::PlayerStopped);
+ bail!("Player is stopped");
}
}
}
@@ -163,12 +91,7 @@ async fn get_ratings(
let mut ratings: Vec<(String, i8)> = Vec::new();
for file in map_tracks(client, tracks).await? {
- let rating = rating_count::get(client, &file)
- .await
- .map_err(|err| Error::Ratings {
- source: Box::new(err),
- back: Backtrace::new(),
- })?;
+ let rating = rating_count::get(client, &file).await?;
ratings.push((file, rating.unwrap_or_default()));
}
@@ -189,12 +112,7 @@ async fn set_rating(client: &mut Client, rating: i8, arg: Option<String>) -> Res
let is_current = arg.is_none();
let file = provide_file(client, arg).await?;
- rating_count::set(client, &file, rating)
- .await
- .map_err(|err| Error::Ratings {
- source: Box::new(err),
- back: Backtrace::new(),
- })?;
+ rating_count::set(client, &file, rating).await?;
match is_current {
false => info!("Set the rating for \"{}\" to \"{}\".", file, rating),
@@ -209,19 +127,9 @@ async fn inc_rating(client: &mut Client, arg: Option<String>) -> Result<()> {
let is_current = arg.is_none();
let file = provide_file(client, arg).await?;
- let now = rating_count::get(client, &file)
- .await
- .map_err(|err| Error::Ratings {
- source: Box::new(err),
- back: Backtrace::new(),
- })?;
+ let now = rating_count::get(client, &file).await?;
- rating_count::set(client, &file, now.unwrap_or_default().saturating_add(1))
- .await
- .map_err(|err| Error::Ratings {
- source: Box::new(err),
- back: Backtrace::new(),
- })?;
+ rating_count::set(client, &file, now.unwrap_or_default().saturating_add(1)).await?;
match is_current {
false => info!("Incremented the rating for \"{}\".", file),
@@ -236,19 +144,9 @@ async fn decr_rating(client: &mut Client, arg: Option<String>) -> Result<()> {
let is_current = arg.is_none();
let file = provide_file(client, arg).await?;
- let now = rating_count::get(client, &file)
- .await
- .map_err(|err| Error::Ratings {
- source: Box::new(err),
- back: Backtrace::new(),
- })?;
+ let now = rating_count::get(client, &file).await?;
- rating_count::set(client, &file, now.unwrap_or_default().saturating_sub(1))
- .await
- .map_err(|err| Error::Ratings {
- source: Box::new(err),
- back: Backtrace::new(),
- })?;
+ rating_count::set(client, &file, now.unwrap_or_default().saturating_sub(1)).await?;
match is_current {
false => info!("Decremented the rating for \"{}\".", file),
@@ -266,13 +164,7 @@ async fn get_play_counts(
) -> Result<()> {
let mut playcounts: Vec<(String, usize)> = Vec::new();
for file in map_tracks(client, tracks).await? {
- let playcount = play_count::get(client, &file)
- .await
- .map_err(|err| Error::Playcounts {
- source: Box::new(err),
- back: Backtrace::new(),
- })?
- .unwrap_or_default();
+ let playcount = play_count::get(client, &file).await?.unwrap_or_default();
playcounts.push((file, playcount));
}
@@ -292,12 +184,7 @@ async fn set_play_counts(client: &mut Client, playcount: usize, arg: Option<Stri
let is_current = arg.is_none();
let file = provide_file(client, arg).await?;
- play_count::set(client, &file, playcount)
- .await
- .map_err(|err| Error::Playcounts {
- source: Box::new(err),
- back: Backtrace::new(),
- })?;
+ play_count::set(client, &file, playcount).await?;
match is_current {
false => info!("Set the playcount for \"{}\" to \"{}\".", file, playcount),
@@ -318,13 +205,7 @@ async fn get_last_playeds(
) -> Result<()> {
let mut lastplayeds: Vec<(String, Option<u64>)> = Vec::new();
for file in map_tracks(client, tracks).await? {
- let lastplayed =
- last_played::get(client, &file)
- .await
- .map_err(|err| Error::Playcounts {
- source: Box::new(err),
- back: Backtrace::new(),
- })?;
+ let lastplayed = last_played::get(client, &file).await?;
lastplayeds.push((file, lastplayed));
}
@@ -357,12 +238,7 @@ async fn set_last_playeds(client: &mut Client, lastplayed: u64, arg: Option<Stri
let is_current = arg.is_none();
let file = provide_file(client, arg).await?;
- last_played::set(client, &file, lastplayed)
- .await
- .map_err(|err| Error::Playcounts {
- source: Box::new(err),
- back: Backtrace::new(),
- })?;
+ last_played::set(client, &file, lastplayed).await?;
match is_current {
false => info!("Set last played for \"{}\" to \"{}\".", file, lastplayed),
@@ -377,13 +253,7 @@ async fn set_last_playeds(client: &mut Client, lastplayed: u64, arg: Option<Stri
/// Retrieve the list of stored playlists
async fn get_playlists(client: &mut Client) -> Result<()> {
- let mut pls = client
- .get_stored_playlists()
- .await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?;
+ let mut pls = client.get_stored_playlists().await?;
pls.sort();
println!("Stored playlists:");
for pl in pls {
@@ -397,13 +267,7 @@ async fn findadd(client: &mut Client, chan: &str, filter: &str, case: bool) -> R
let qfilter = quote(filter);
debug!("findadd: got ``{}'', quoted to ``{}''.", filter, qfilter);
let cmd = format!("{} {}", if case { "findadd" } else { "searchadd" }, qfilter);
- client
- .send_message(chan, &cmd)
- .await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?;
+ client.send_message(chan, &cmd).await?;
Ok(())
}
@@ -419,11 +283,7 @@ async fn send_command(client: &mut Client, chan: &str, args: Vec<String>) -> Res
.join(" ")
.as_str(),
)
- .await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?;
+ .await?;
Ok(())
}
@@ -647,18 +507,17 @@ async fn main() -> Result<()> {
let config = if let Some(configpath) = &args.config {
match std::fs::read_to_string(configpath) {
- Ok(text) => config::from_str(&text).map_err(|err| Error::Config {
- source: err,
- back: Backtrace::new(),
+ Ok(text) => config::from_str(&text).with_context(|| {
+ format!("Failed to parse config file at: `{}`", configpath.display())
})?,
Err(err) => {
// Either they did _not_, in which case they probably want to know that the config
// file they explicitly asked for does not exist, or there was some other problem,
// in which case we're out of options, anyway. Either way:
- return Err(Error::NoConfig {
- config: PathBuf::from(configpath),
- cause: err,
- });
+ bail!(
+ "Failed to read config file at: `{}`, because: {err}",
+ configpath.display()
+ )
}
}
} else {
@@ -691,18 +550,10 @@ async fn main() -> Result<()> {
trace!("logging configured.");
let mut client = match config.conn {
- config::Connection::Local { path } => {
- Client::open(path).await.map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?
+ config::Connection::Local { path } => Client::open(path).await?,
+ config::Connection::TCP { host, port } => {
+ Client::connect(format!("{}:{}", host, port)).await?
}
- config::Connection::TCP { host, port } => Client::connect(format!("{}:{}", host, port))
- .await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?,
};
match args.command {
diff --git a/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopmd.rs b/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopmd.rs
index e903774c..643611d6 100644
--- a/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopmd.rs
+++ b/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopmd.rs
@@ -25,94 +25,17 @@
//! the sticker database, by invoking external commands to keep your tags up-to-date (something
//! along the lines of [mpdcron](https://alip.github.io/mpdcron)).
-use mpdpopm::config;
-use mpdpopm::config::Config;
-use mpdpopm::mpdpopm;
+use mpdpopm::{
+ config::{self, Config},
+ mpdpopm,
+};
-use backtrace::Backtrace;
+use anyhow::{Context, Result, bail};
use clap::Parser;
use tracing::{info, level_filters::LevelFilter};
use tracing_subscriber::{EnvFilter, Layer, Registry, layer::SubscriberExt};
-use std::{fmt, io, path::PathBuf, sync::MutexGuard};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// mppopmd application Error type //
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-#[non_exhaustive]
-pub enum Error {
- NoConfigArg,
- NoConfig {
- config: std::path::PathBuf,
- cause: std::io::Error,
- },
- Filter {
- source: tracing_subscriber::filter::FromEnvError,
- back: Backtrace,
- },
- Fork {
- errno: errno::Errno,
- back: Backtrace,
- },
- PathContainsNull {
- back: Backtrace,
- },
- OpenLockFile {
- errno: errno::Errno,
- back: Backtrace,
- },
- LockFile {
- errno: errno::Errno,
- back: Backtrace,
- },
- WritePid {
- errno: errno::Errno,
- back: Backtrace,
- },
- Config {
- source: crate::config::Error,
- back: Backtrace,
- },
- MpdPopm {
- source: Box<mpdpopm::Error>,
- back: Backtrace,
- },
-}
-
-impl std::fmt::Display for Error {
- #[allow(unreachable_patterns)] // the _ arm is *currently* unreachable
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Error::NoConfigArg => write!(f, "No configuration file given"),
- Error::NoConfig { config, cause } => {
- write!(f, "Configuration error ({:?}): {}", config, cause)
- }
- Error::Fork { errno, back: _ } => write!(f, "When forking, got errno {}", errno),
- Error::PathContainsNull { back: _ } => write!(f, "Path contains a null character"),
- Error::OpenLockFile { errno, back: _ } => {
- write!(f, "While opening lock file, got errno {}", errno)
- }
- Error::LockFile { errno, back: _ } => {
- write!(f, "While locking the lock file, got errno {}", errno)
- }
- Error::WritePid { errno, back: _ } => {
- write!(f, "While writing pid file, got errno {}", errno)
- }
- Error::Config { source, back: _ } => write!(f, "Configuration error: {}", source),
- Error::MpdPopm { source, back: _ } => write!(f, "mpdpopm error: {}", source),
- _ => write!(f, "Unknown mppopmd error"),
- }
- }
-}
-
-impl fmt::Debug for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self)
- }
-}
-
-type Result = std::result::Result<(), Error>;
+use std::{io, path::PathBuf, sync::MutexGuard};
pub struct MyMutexGuardWriter<'a>(MutexGuard<'a, std::fs::File>);
@@ -164,22 +87,21 @@ struct Args {
debug: bool,
}
-/// Entry point for `mppopmd'.
+/// Entry point for `mpdopmd'.
///
/// Do *not* use the #[tokio::main] attribute here! If this program is asked to daemonize (the usual
/// case), we will fork after tokio has started its thread pool, with disastrous consequences.
/// Instead, stay synchronous until we've daemonized (or figured out that we don't need to), and
/// only then fire-up the tokio runtime.
-fn main() -> Result {
+fn main() -> Result<()> {
use mpdpopm::vars::VERSION;
let args = Args::parse();
let config = if let Some(cfgpath) = &args.config {
match std::fs::read_to_string(cfgpath) {
- Ok(text) => config::from_str(&text).map_err(|err| Error::Config {
- source: err,
- back: Backtrace::new(),
+ Ok(text) => config::from_str(&text).with_context(|| {
+ format!("Failed to parse config file at: `{}`", cfgpath.display())
})?,
// The config file (defaulted or not) either didn't exist, or we were unable to read its
// contents...
@@ -187,10 +109,10 @@ fn main() -> Result {
// Either they did _not_, in which case they probably want to know that the config
// file they explicitly asked for does not exist, or there was some other problem,
// in which case we're out of options, anyway. Either way:
- return Err(Error::NoConfig {
- config: PathBuf::from(cfgpath),
- cause: err,
- });
+ bail!(
+ "No config file could be read at: `{}`, because: {err}",
+ cfgpath.display()
+ )
}
}
} else {
@@ -208,10 +130,7 @@ fn main() -> Result {
let filter = EnvFilter::builder()
.with_default_directive(lf.into())
.from_env()
- .map_err(|err| Error::Filter {
- source: err,
- back: Backtrace::new(),
- })?;
+ .context("Failed to construct env filter")?;
let formatter: Box<dyn Layer<Registry> + Send + Sync> = {
Box::new(
@@ -226,8 +145,6 @@ fn main() -> Result {
info!("mppopmd {VERSION} logging at level {lf:#?}.");
let rt = tokio::runtime::Runtime::new().unwrap();
- rt.block_on(mpdpopm(config)).map_err(|err| Error::MpdPopm {
- source: Box::new(err),
- back: Backtrace::new(),
- })
+
+ rt.block_on(mpdpopm(config)).context("Main mpdpopm failed")
}
diff --git a/pkgs/by-name/mp/mpdpopm/src/clients.rs b/pkgs/by-name/mp/mpdpopm/src/clients.rs
index 587063b2..b88e4041 100644
--- a/pkgs/by-name/mp/mpdpopm/src/clients.rs
+++ b/pkgs/by-name/mp/mpdpopm/src/clients.rs
@@ -31,9 +31,9 @@
//! re-issue the "idle" command. This crate however takes the approach of two channels (like
//! [mpdfav](https://github.com/vincent-petithory/mpdfav)).
+use anyhow::{Context, Error, Result, anyhow, bail, ensure};
use async_trait::async_trait;
use regex::Regex;
-use snafu::{Backtrace, IntoError, OptionExt, ResultExt, prelude::*};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::net::{TcpStream, ToSocketAddrs, UnixStream};
use tracing::{debug, info};
@@ -49,92 +49,9 @@ use std::{
str::FromStr,
};
-// The Protocol error, below, gets used a *lot*; anywhere we receive a message from the MPD server
-// that "should" never happen. To help give a bit of context beyond a stack trace, I use this
-// enumeration of "operations"
-/// Enumerated list of MPD operations; used in Error::Protocol to distinguish which operation it was
-/// that elicited the protocol error.
-#[derive(Debug)]
-#[non_exhaustive]
-pub enum Operation {
- Connect,
- Status,
- GetSticker,
- SetSticker,
- SendToPlaylist,
- SendMessage,
- Update,
- GetStoredPlaylists,
- RspToUris,
- GetStickers,
- GetAllSongs,
- Add,
- Idle,
- GetMessages,
-}
-
-impl std::fmt::Display for Operation {
- #[allow(unreachable_patterns)] // the _ arm is *currently* unreachable
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Operation::Connect => write!(f, "Connect"),
- Operation::Status => write!(f, "Status"),
- Operation::GetSticker => write!(f, "GetSticker"),
- Operation::SetSticker => write!(f, "SetSticker"),
- Operation::SendToPlaylist => write!(f, "SendToPlaylist"),
- Operation::SendMessage => write!(f, "SendMessage"),
- Operation::Update => write!(f, "Update"),
- Operation::GetStoredPlaylists => write!(f, "GetStoredPlaylists"),
- Operation::RspToUris => write!(f, "RspToUris"),
- Operation::GetStickers => write!(f, "GetStickers"),
- Operation::GetAllSongs => write!(f, "GetAllSongs"),
- Operation::Add => write!(f, "Add"),
- Operation::Idle => write!(f, "Idle"),
- Operation::GetMessages => write!(f, "GetMessages"),
- _ => write!(f, "Unknown client operation"),
- }
- }
-}
-
-/// An MPD client error
-#[derive(Debug, Snafu)]
-#[non_exhaustive]
-pub enum Error {
- #[snafu(display("Protocol error ({}): {}", op, msg))]
- Protocol {
- op: Operation,
- msg: String,
- backtrace: Backtrace,
- },
- #[snafu(display("Protocol errror ({}): {}", op, source))]
- ProtocolConv {
- op: Operation,
- source: Box<dyn std::error::Error>,
- backtrace: Backtrace,
- },
- #[snafu(display("I/O error: {}", source))]
- Io {
- source: std::io::Error,
- backtrace: Backtrace,
- },
- #[snafu(display("Encoding error: {}", source))]
- Encoding {
- source: std::string::FromUtf8Error,
- backtrace: Backtrace,
- },
- #[snafu(display("While converting sticker ``{}'': {}", sticker, source))]
- StickerConversion {
- sticker: String,
- source: Box<dyn std::error::Error>,
- backtrace: Backtrace,
- },
- #[snafu(display("``{}'' is not a recognized Idle subsystem", text))]
- IdleSubSystem { text: String, backtrace: Backtrace },
-}
-
-pub type Result<T> = std::result::Result<T, Error>;
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
+// Some default error context messages
+const ENCODING_SNAFU: &str = "Failed to interpete text as utf8";
+const IO_SNAFU: &str = "Failed read from mpd socket";
/// A description of the current track, suitable for our purposes (as in, it only tracks the
/// attributes needed for this module's functionality).
@@ -187,10 +104,6 @@ impl PlayerStatus {
}
}
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Connection //
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
/// A trait representing a simple, textual request/response protocol like that
/// [employed](https://www.musicpd.org/doc/html/protocol.html) by [MPD](https://www.musicpd.org/):
/// the caller sends a textual command & the server responds with a (perhaps multi-line) textual
@@ -310,7 +223,7 @@ where
self.sock
.write_all(format!("{}\n", msg).as_bytes())
.await
- .context(IoSnafu)?;
+ .context(IO_SNAFU)?;
let mut buf = Vec::with_capacity(hint);
// Given the request/response nature of the MPD protocol, our callers expect a complete
@@ -319,7 +232,7 @@ where
let mut cb = 0; // # bytes read so far
let mut more = true; // true as long as there is more to read
while more {
- cb += self.sock.read_buf(&mut buf).await.context(IoSnafu)?;
+ cb += self.sock.read_buf(&mut buf).await.context(IO_SNAFU)?;
// The shortest complete response has three bytes. If the final byte in `buf' is not a
// newline, then don't bother looking further.
@@ -347,7 +260,7 @@ where
}
// Only doing this to trouble-shoot issue 11
- String::from_utf8(buf.clone()).context(EncodingSnafu)
+ String::from_utf8(buf.clone()).context(ENCODING_SNAFU)
}
}
@@ -357,15 +270,15 @@ where
T: AsyncReadExt + AsyncWriteExt + Send + Unpin,
{
let mut buf = Vec::with_capacity(32);
- let _cb = sock.read_buf(&mut buf).await.context(IoSnafu)?;
+ let _cb = sock.read_buf(&mut buf).await.context(IO_SNAFU)?;
+
// Only doing this to trouble-shoot issue 11
- let text = String::from_utf8(buf.clone()).context(EncodingSnafu)?;
+ let text = String::from_utf8(buf.clone()).context(ENCODING_SNAFU)?;
+
ensure!(
text.starts_with("OK MPD "),
- ProtocolSnafu {
- op: Operation::Connect,
- msg: text.trim()
- }
+ "failed to connect: {}",
+ text.trim()
);
info!("Connected {}.", text[7..].trim());
Ok(text[7..].trim().to_string())
@@ -373,7 +286,7 @@ where
impl MpdConnection<TcpStream> {
pub async fn connect<A: ToSocketAddrs>(addr: A) -> Result<Box<dyn RequestResponse>> {
- let mut sock = TcpStream::connect(addr).await.context(IoSnafu)?;
+ let mut sock = TcpStream::connect(addr).await.context(IO_SNAFU)?;
let proto_ver = parse_connect_rsp(&mut sock).await?;
Ok(Box::new(MpdConnection::<TcpStream> {
sock,
@@ -385,7 +298,7 @@ impl MpdConnection<TcpStream> {
impl MpdConnection<UnixStream> {
// NTS: we have to box the return value because a `dyn RequestResponse` isn't Sized.
pub async fn connect<P: AsRef<Path>>(pth: P) -> Result<Box<dyn RequestResponse>> {
- let mut sock = UnixStream::connect(pth).await.context(IoSnafu)?;
+ let mut sock = UnixStream::connect(pth).await.context(IO_SNAFU)?;
let proto_ver = parse_connect_rsp(&mut sock).await?;
Ok(Box::new(MpdConnection::<UnixStream> {
sock,
@@ -478,13 +391,7 @@ impl Client {
// also don't want to depend on the order.
let text = self.stream.req("status").await?;
- let proto = || -> Error {
- ProtocolSnafu {
- op: Operation::Status,
- msg: text.to_owned(),
- }
- .build()
- };
+ let proto = || -> Error { anyhow!("Failed to parse mpd status output (with regexes)") };
// I first thought to avoid the use (and cost) of regular expressions by just doing
// sub-string searching on "state: ", but when I realized I needed to only match at the
@@ -507,12 +414,7 @@ impl Client {
.ok_or_else(proto)?
.as_str()
.parse::<u64>()
- .map_err(|err| {
- ProtocolConvSnafu {
- op: Operation::Status,
- }
- .into_error(Box::new(err))
- })?;
+ .context("Failed to parse songid as u64")?;
let elapsed = RE_ELAPSED
.captures(&text)
@@ -521,12 +423,7 @@ impl Client {
.ok_or_else(proto)?
.as_str()
.parse::<f64>()
- .map_err(|err| {
- ProtocolConvSnafu {
- op: Operation::Status,
- }
- .into_error(Box::new(err))
- })?;
+ .context("failed to parse `elapsed` as f64")?;
// navigate from `songid'-- don't send a "currentsong" message-- the current song
// could have changed
@@ -545,12 +442,7 @@ impl Client {
.ok_or_else(proto)?
.as_str()
.parse::<f64>()
- .map_err(|err| {
- ProtocolConvSnafu {
- op: Operation::Status,
- }
- .into_error(Box::new(err))
- })?;
+ .context("Failed to parse `duration` as f64")?;
let curr = CurrentSong::new(songid, PathBuf::from(file), elapsed, duration);
@@ -560,11 +452,7 @@ impl Client {
Ok(PlayerStatus::Pause(curr))
}
}
- _ => ProtocolSnafu {
- op: Operation::Status,
- msg: state.to_owned(),
- }
- .fail(),
+ _ => bail!("Encountered unknow state `{}`", state),
}
}
@@ -586,24 +474,18 @@ impl Client {
let s = text[prefix.len()..]
.split('\n')
.next()
- .context(ProtocolSnafu {
- op: Operation::GetSticker,
- msg,
- })?;
- Ok(Some(T::from_str(s).map_err(|err| {
- StickerConversionSnafu {
- sticker: sticker_name.to_owned(),
- }
- .into_error(Box::new(err))
+ .with_context(|| format!("Failed to parse `{}` as get_sticker response", text))?;
+ Ok(Some(T::from_str(s).with_context(|| {
+ format!(
+ "Failed to parse sticker value as correct type: `{}`",
+ sticker_name
+ )
})?))
} else {
// ACK_ERROR_NO_EXIST = 50 (Ack.hxx:17)
ensure!(
text.starts_with("ACK [50@0]"),
- ProtocolSnafu {
- op: Operation::GetSticker,
- msg,
- }
+ "Missing no sticker response"
);
Ok(None)
}
@@ -626,13 +508,7 @@ impl Client {
let text = self.stream.req(&msg).await?;
debug!("Sent `{}'; got `{}'", &msg, &text);
- ensure!(
- text.starts_with("OK"),
- ProtocolSnafu {
- op: Operation::SetSticker,
- msg
- }
- );
+ ensure!(text.starts_with("OK"), "Set sticker, not acknowledged");
Ok(())
}
@@ -641,13 +517,7 @@ impl Client {
let msg = format!("playlistadd {} {}", quote(pl), quote(file));
let text = self.stream.req(&msg).await?;
debug!("Sent `{}'; got `{}'.", &msg, &text);
- ensure!(
- text.starts_with("OK"),
- ProtocolSnafu {
- op: Operation::SendToPlaylist,
- msg
- }
- );
+ ensure!(text.starts_with("OK"), "send_to_playlist not acknowledged");
Ok(())
}
@@ -657,13 +527,7 @@ impl Client {
let text = self.stream.req(&msg).await?;
debug!("Sent `{}'; got `{}'.", &msg, &text);
- ensure!(
- text.starts_with("OK"),
- ProtocolSnafu {
- op: Operation::SendMessage,
- msg: text
- }
- );
+ ensure!(text.starts_with("OK"), "Send_message not acknowledged");
Ok(())
}
@@ -683,20 +547,12 @@ impl Client {
let prefix = "updating_db: ";
ensure!(
text.starts_with(prefix),
- ProtocolSnafu {
- op: Operation::Update,
- msg: &text
- }
+ "update response doesn't start with correct prefix"
);
text[prefix.len()..].split('\n').collect::<Vec<&str>>()[0]
.to_string()
.parse::<u64>()
- .map_err(|err| {
- ProtocolConvSnafu {
- op: Operation::Update,
- }
- .into_error(Box::new(err))
- })
+ .context("Failed to treat update job id as u64")
}
/// Get the list of stored playlists
@@ -717,10 +573,7 @@ impl Client {
// ACK...
ensure!(
!text.starts_with("ACK"),
- ProtocolSnafu {
- op: Operation::GetStoredPlaylists,
- msg: text
- }
+ "get_stored_playlists response not acknowledged"
);
Ok(text
.lines()
@@ -742,13 +595,7 @@ impl Client {
// or
//
// ACK...
- ensure!(
- !text.starts_with("ACK"),
- ProtocolSnafu {
- op: Operation::RspToUris,
- msg: text.to_owned()
- }
- );
+ ensure!(!text.starts_with("ACK"), "rsp_to_uris not acknowledged");
Ok(text
.lines()
.filter_map(|x| x.strip_prefix("file: ").map(String::from))
@@ -814,27 +661,15 @@ impl Client {
// or
//
// ACK ...
- ensure!(
- !text.starts_with("ACK"),
- ProtocolSnafu {
- op: Operation::GetStickers,
- msg: text,
- }
- );
+ ensure!(!text.starts_with("ACK"), "get_stickers not ACKed");
let mut m = HashMap::new();
let mut lines = text.lines();
loop {
- let file = lines.next().context(ProtocolSnafu {
- op: Operation::GetStickers,
- msg: text.to_owned(),
- })?;
+ let file = lines.next().context("get_stickers no new line")?;
if "OK" == file {
break;
}
- let val = lines.next().context(ProtocolSnafu {
- op: Operation::GetStickers,
- msg: text.to_owned(),
- })?;
+ let val = lines.next().context("get_stickers no val")?;
m.insert(
String::from(&file[6..]),
@@ -863,13 +698,7 @@ impl Client {
// OK
//
// or "ACK..."
- ensure!(
- !text.starts_with("ACK"),
- ProtocolSnafu {
- op: Operation::GetAllSongs,
- msg: text,
- }
- );
+ ensure!(!text.starts_with("ACK"), "get_all_songs not ACKed");
Ok(text
.lines()
.filter_map(|x| x.strip_prefix("file: ").map(String::from))
@@ -881,13 +710,7 @@ impl Client {
let text = self.stream.req(&msg).await?;
debug!("Sent `{}'; got `{}'.", &msg, &text);
- ensure!(
- text.starts_with("OK"),
- ProtocolSnafu {
- op: Operation::Add,
- msg: &text
- }
- );
+ ensure!(text.starts_with("OK"), "add not Oked");
Ok(())
}
}
@@ -1161,10 +984,7 @@ impl TryFrom<&str> for IdleSubSystem {
} else if x == "message" {
Ok(IdleSubSystem::Message)
} else {
- Err(IdleSubSystemSnafu {
- text: String::from(text),
- }
- .build())
+ bail!("{}", text)
}
}
}
@@ -1227,13 +1047,7 @@ impl IdleClient {
pub async fn subscribe(&mut self, chan: &str) -> Result<()> {
let text = self.conn.req(&format!("subscribe {}", chan)).await?;
debug!("Sent subscribe message for {}; got `{}'.", chan, text);
- ensure!(
- text.starts_with("OK"),
- ProtocolSnafu {
- op: Operation::Connect,
- msg: &text
- }
- );
+ ensure!(text.starts_with("OK"), "subscribe not Ok: `{}`", text);
debug!("Subscribed to {}.", chan);
Ok(())
}
@@ -1255,27 +1069,12 @@ impl IdleClient {
//
// We remain subscribed, but we need to send a new idle message.
- ensure!(
- text.starts_with("changed: "),
- ProtocolSnafu {
- op: Operation::Idle,
- msg: &text
- }
- );
- let idx = text.find('\n').context(ProtocolSnafu {
- op: Operation::Idle,
- msg: text.to_owned(),
- })?;
+ ensure!(text.starts_with("changed: "), "idle not OK: `{}`", text);
+ let idx = text.find('\n').context("idle has no newline")?;
let result = IdleSubSystem::try_from(&text[9..idx])?;
let text = text[idx + 1..].to_string();
- ensure!(
- text.starts_with("OK"),
- ProtocolSnafu {
- op: Operation::Idle,
- msg: &text
- }
- );
+ ensure!(text.starts_with("OK"), "idle not OKed");
Ok(result)
}
@@ -1308,13 +1107,7 @@ impl IdleClient {
for line in text.lines() {
match state {
State::Init => {
- ensure!(
- line.starts_with("channel: "),
- ProtocolSnafu {
- op: Operation::GetMessages,
- msg: line.to_owned()
- }
- );
+ ensure!(line.starts_with("channel: "), "no `channel: ` given");
chan = String::from(&line[9..]);
state = State::Running;
}
@@ -1339,20 +1132,12 @@ impl IdleClient {
}
state = State::Finished;
} else {
- return Err(ProtocolSnafu {
- op: Operation::GetMessages,
- msg: text,
- }
- .build());
+ bail!("Failed to get messages: `{}`", text)
}
}
State::Finished => {
// Should never be here!
- return Err(ProtocolSnafu {
- op: Operation::GetMessages,
- msg: String::from(line),
- }
- .build());
+ bail!("Failed to get messages: `{}`", text)
}
}
}
diff --git a/pkgs/by-name/mp/mpdpopm/src/config.rs b/pkgs/by-name/mp/mpdpopm/src/config.rs
index 08509e47..e6c01599 100644
--- a/pkgs/by-name/mp/mpdpopm/src/config.rs
+++ b/pkgs/by-name/mp/mpdpopm/src/config.rs
@@ -40,9 +40,10 @@
//! bundle-up all the errors, report 'em & urge the user to use the most recent version
use crate::vars::{LOCALSTATEDIR, PREFIX};
+use anyhow::{Result, bail};
use serde::{Deserialize, Serialize};
-use std::path::PathBuf;
+use std::{env, path::PathBuf};
/// [mpdpopm](crate) can communicate with MPD over either a local Unix socket, or over regular TCP
#[derive(Debug, Deserialize, PartialEq, Serialize)]
@@ -85,15 +86,6 @@ mod test_connection {
}
}
-impl std::default::Default for Connection {
- fn default() -> Self {
- Connection::TCP {
- host: String::from("localhost"),
- port: 6600,
- }
- }
-}
-
/// This is the most recent `mppopmd` configuration struct.
#[derive(Deserialize, Debug, Serialize)]
#[serde(default)]
@@ -139,31 +131,11 @@ impl Default for Config {
}
}
-#[derive(Debug)]
-pub enum Error {
- /// Failure to parse
- ParseFail { err: Box<dyn std::error::Error> },
-}
-
-impl std::fmt::Display for Error {
- #[allow(unreachable_patterns)] // the _ arm is *currently* unreachable
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Error::ParseFail { err } => write!(f, "Parse failure: {}", err),
- _ => write!(f, "Unknown configuration error"),
- }
- }
-}
-
-pub type Result<T> = std::result::Result<T, Error>;
-
pub fn from_str(text: &str) -> Result<Config> {
let cfg: Config = match serde_json::from_str(text) {
Ok(cfg) => cfg,
Err(err_outer) => {
- return Err(Error::ParseFail {
- err: Box::new(err_outer),
- });
+ bail!("Failed to parse config: `{}`", err_outer)
}
};
Ok(cfg)
diff --git a/pkgs/by-name/mp/mpdpopm/src/filters_ast.rs b/pkgs/by-name/mp/mpdpopm/src/filters_ast.rs
index 7d30739d..bd1a67d6 100644
--- a/pkgs/by-name/mp/mpdpopm/src/filters_ast.rs
+++ b/pkgs/by-name/mp/mpdpopm/src/filters_ast.rs
@@ -20,7 +20,7 @@
use crate::clients::Client;
use crate::storage::{last_played, play_count, rating_count};
-use backtrace::Backtrace;
+use anyhow::{Context, Error, Result, anyhow, bail};
use boolinator::Boolinator;
use chrono::prelude::*;
use tracing::debug;
@@ -197,7 +197,6 @@ pub enum Expression {
#[cfg(test)]
mod smoke_tests {
-
use super::*;
use crate::filters::*;
@@ -315,10 +314,6 @@ mod smoke_tests {
}
}
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// evaluation logic //
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum EvalOp {
And,
@@ -336,92 +331,6 @@ impl std::fmt::Display for EvalOp {
}
}
-#[derive(Debug)]
-pub enum Error {
- BadISO8601String {
- text: Vec<u8>,
- back: Backtrace,
- },
- ExpectQuoted {
- text: String,
- back: Backtrace,
- },
- FilterTypeErr {
- text: String,
- back: Backtrace,
- },
- InvalidOperand {
- op: OpCode,
- back: Backtrace,
- },
- OperatorOnStack {
- op: EvalOp,
- back: Backtrace,
- },
- RatingOverflow {
- rating: usize,
- back: Backtrace,
- },
- TooManyOperands {
- num_ops: usize,
- back: Backtrace,
- },
- NumericParse {
- sticker: String,
- source: std::num::ParseIntError,
- back: Backtrace,
- },
- Client {
- source: crate::clients::Error,
- back: Backtrace,
- },
-}
-
-impl std::fmt::Display for Error {
- #[allow(unreachable_patterns)] // the _ arm is *currently* unreachable
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Error::BadISO8601String { text, back: _ } => {
- write!(f, "Bad ISO8601 timestamp: ``{:?}''", text)
- }
- Error::ExpectQuoted { text, back: _ } => write!(f, "Expected quote: ``{}''", text),
- Error::FilterTypeErr { text, back: _ } => {
- write!(f, "Un-expected type in filter ``{}''", text)
- }
- Error::InvalidOperand { op, back: _ } => write!(f, "Invalid operand {}", op),
- Error::OperatorOnStack { op, back: _ } => {
- write!(f, "Operator {} left on parse stack", op)
- }
- Error::RatingOverflow { rating, back: _ } => write!(f, "Rating {} overflows", rating),
- Error::TooManyOperands { num_ops, back: _ } => {
- write!(f, "Too many operands ({})", num_ops)
- }
- Error::NumericParse {
- sticker,
- source,
- back: _,
- } => write!(f, "While parsing sticker {}, got {}", sticker, source),
- Error::Client { source, back: _ } => write!(f, "Client error: {}", source),
- }
- }
-}
-
-impl std::error::Error for Error {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- match &self {
- Error::NumericParse {
- sticker: _,
- source,
- back: _,
- } => Some(source),
- Error::Client { source, back: _ } => Some(source),
- _ => None,
- }
- }
-}
-
-pub type Result<T> = std::result::Result<T, Error>;
-
fn peek(buf: &[u8]) -> Option<char> {
match buf.len() {
0 => None,
@@ -433,10 +342,7 @@ fn peek(buf: &[u8]) -> Option<char> {
/// Pop a single byte off of `buf`
fn take1(buf: &mut &[u8], i: usize) -> Result<()> {
if i > buf.len() {
- return Err(Error::BadISO8601String {
- text: buf.to_vec(),
- back: Backtrace::new(),
- });
+ bail!("Bad iso-8601 string: `{:#?}`", buf);
}
let (_first, second) = buf.split_at(i);
*buf = second;
@@ -447,26 +353,20 @@ fn take1(buf: &mut &[u8], i: usize) -> Result<()> {
fn take2<T>(buf: &mut &[u8], i: usize) -> Result<T>
where
T: FromStr,
+ <T as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static,
{
// 1. check len
if i > buf.len() {
- return Err(Error::BadISO8601String {
- text: buf.to_vec(),
- back: Backtrace::new(),
- });
+ bail!("Bad iso-8601 string: `{:#?}`", buf);
}
+
let (first, second) = buf.split_at(i);
*buf = second;
// 2. convert to a string
- let s = std::str::from_utf8(first).map_err(|_| Error::BadISO8601String {
- text: buf.to_vec(),
- back: Backtrace::new(),
- })?;
+ let s = std::str::from_utf8(first).context("Bad iso-8601 string")?;
// 3. parse as a T
- s.parse::<T>().map_err(|_err| Error::BadISO8601String {
- text: buf.to_vec(),
- back: Backtrace::new(),
- }) // Parse*Error => Error
+ s.parse::<T>()
+ .context("Failed to parse iso-8601 string as T")
}
/// Parse a timestamp in ISO 8601 format to a chrono DateTime instance
@@ -545,18 +445,12 @@ pub fn parse_iso_8601(buf: &mut &[u8]) -> Result<i64> {
return Ok(Utc
.with_ymd_and_hms(year, month, day, hour, minute, second)
.single()
- .ok_or(Error::BadISO8601String {
- text: buf.to_vec(),
- back: Backtrace::new(),
- })?
+ .ok_or(anyhow!("bad iso-8601 string"))?
.timestamp());
} else {
let next = peek(buf);
if next != Some('-') && next != Some('+') {
- return Err(Error::BadISO8601String {
- text: buf.to_vec(),
- back: Backtrace::new(),
- });
+ bail!("bad iso-8601 string")
}
let west = next == Some('-');
take1(buf, 1)?;
@@ -573,29 +467,17 @@ pub fn parse_iso_8601(buf: &mut &[u8]) -> Result<i64> {
if west {
return Ok(FixedOffset::west_opt(hours * 3600 + minutes * 60)
- .ok_or(Error::BadISO8601String {
- text: buf.to_vec(),
- back: Backtrace::new(),
- })?
+ .ok_or(anyhow!("Bad iso-8601 string"))?
.with_ymd_and_hms(year, month, day, hour, minute, second)
.single()
- .ok_or(Error::BadISO8601String {
- text: buf.to_vec(),
- back: Backtrace::new(),
- })?
+ .ok_or(anyhow!("Bad iso-8601 string"))?
.timestamp());
} else {
return Ok(FixedOffset::east_opt(hours * 3600 + minutes * 60)
- .ok_or(Error::BadISO8601String {
- text: buf.to_vec(),
- back: Backtrace::new(),
- })?
+ .ok_or(anyhow!("Bad iso-8601 string"))?
.with_ymd_and_hms(year, month, day, hour, minute, second)
.single()
- .ok_or(Error::BadISO8601String {
- text: buf.to_vec(),
- back: Backtrace::new(),
- })?
+ .ok_or(anyhow!("Bad iso-8601 string"))?
.timestamp());
}
}
@@ -604,10 +486,7 @@ pub fn parse_iso_8601(buf: &mut &[u8]) -> Result<i64> {
Ok(Local
.with_ymd_and_hms(year, month, day, hour, minute, second)
.single()
- .ok_or(Error::BadISO8601String {
- text: buf.to_vec(),
- back: Backtrace::new(),
- })?
+ .ok_or(anyhow!("Bad iso-8601 string"))?
.timestamp())
}
@@ -658,10 +537,7 @@ pub fn expect_quoted(qtext: &str) -> Result<String> {
}
if quote != Some('\'') && quote != Some('"') {
- return Err(Error::ExpectQuoted {
- text: String::from(qtext),
- back: Backtrace::new(),
- });
+ bail!("Expected text to be quoted: `{}`", qtext);
}
let mut ret = String::new();
@@ -676,10 +552,7 @@ pub fn expect_quoted(qtext: &str) -> Result<String> {
match this {
Some(c) => ret.push(c),
None => {
- return Err(Error::ExpectQuoted {
- text: String::from(qtext),
- back: Backtrace::new(),
- });
+ bail!("Expected text to be quoted: `{}`", qtext);
}
}
this = iter.next();
@@ -727,10 +600,7 @@ fn make_numeric_closure<'a, T: 'a + PartialEq + PartialOrd + Copy>(
OpCode::LessThan => Ok(Box::new(move |x: T| x < val) as Box<dyn Fn(T) -> bool>),
OpCode::GreaterThanEqual => Ok(Box::new(move |x: T| x >= val) as Box<dyn Fn(T) -> bool>),
OpCode::LessThanEqual => Ok(Box::new(move |x: T| x <= val) as Box<dyn Fn(T) -> bool>),
- _ => Err(Error::InvalidOperand {
- op,
- back: Backtrace::new(),
- }),
+ _ => bail!("Invalid operant: `{op}`"),
}
}
@@ -767,18 +637,11 @@ async fn eval_numeric_sticker_term<
let mut m = client
.get_stickers(sticker)
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?
+ .context("Failed to get stickers from client")?
.drain()
.map(|(k, v)| v.parse::<T>().map(|x| (k, x)))
.collect::<std::result::Result<HashMap<String, T>, _>>()
- .map_err(|err| Error::NumericParse {
- sticker: String::from(sticker),
- source: err,
- back: Backtrace::new(),
- })?;
+ .context("Failed to parse sticker as T")?;
// `m' is now a map of song URI to rating/playcount/wathever (expressed as a T)... for all songs
// that have the salient sticker.
//
@@ -787,10 +650,7 @@ async fn eval_numeric_sticker_term<
client
.get_all_songs()
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?
+ .context("Failed to get all songs from client")?
.drain(..)
.for_each(|song| {
m.entry(song).or_insert(default_val);
@@ -846,10 +706,7 @@ async fn eval_term<'a>(
Term::UnaryCondition(op, val) => Ok(client
.find1(&format!("{}", op), &quote_value(val), case)
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?
+ .context("Failed to find1 on client")?
.drain(..)
.collect()),
Term::BinaryCondition(attr, op, val) => {
@@ -857,20 +714,14 @@ async fn eval_term<'a>(
match val {
Value::Uint(n) => {
if *n > 255 {
- return Err(Error::RatingOverflow {
- rating: *n,
- back: Backtrace::new(),
- });
+ bail!("Rating of `{}` is greater than allowed!", n)
}
Ok(
eval_numeric_sticker_term(stickers.rating, client, *op, *n as u8, 0)
.await?,
)
}
- _ => Err(Error::FilterTypeErr {
- text: format!("filter ratings expect an unsigned int; got {:#?}", val),
- back: Backtrace::new(),
- }),
+ _ => bail!("filter ratings expect an unsigned int; got {:#?}", val),
}
} else if *attr == Selector::PlayCount {
match val {
@@ -880,10 +731,7 @@ async fn eval_term<'a>(
.await?,
)
}
- _ => Err(Error::FilterTypeErr {
- text: format!("filter ratings expect an unsigned int; got {:#?}", val),
- back: Backtrace::new(),
- }),
+ _ => bail!("filter ratings expect an unsigned int; got {:#?}", val),
}
} else if *attr == Selector::LastPlayed {
match val {
@@ -893,10 +741,7 @@ async fn eval_term<'a>(
.await?,
)
}
- _ => Err(Error::FilterTypeErr {
- text: format!("filter ratings expect an unsigned int; got {:#?}", val),
- back: Backtrace::new(),
- }),
+ _ => bail!("filter ratings expect an unsigned int; got {:#?}", val),
}
} else {
Ok(client
@@ -907,10 +752,7 @@ async fn eval_term<'a>(
case,
)
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?
+ .context("Failed to `find2` on client")?
.drain(..)
.collect())
}
@@ -932,10 +774,7 @@ async fn negate_result(
Ok(client
.get_all_songs()
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?
+ .context("Failed to get all songs from client")?
.drain(..)
.filter_map(|song| {
// Some(thing) adds thing, None elides it
@@ -1117,10 +956,7 @@ pub async fn evaluate<'a>(
se.iter()
.enumerate()
.for_each(|(i, x)| debug!(" {}: {:#?}", i, x));
- return Err(Error::TooManyOperands {
- num_ops: se.len(),
- back: Backtrace::new(),
- });
+ bail!("The number of operants is too big `{}`", se.len());
}
let ret = se.pop().unwrap();
@@ -1128,10 +964,7 @@ pub async fn evaluate<'a>(
EvalStackNode::Result(result) => Ok(result),
EvalStackNode::Op(op) => {
debug!("Operator left on stack (!?): {:#?}", op);
- Err(Error::OperatorOnStack {
- op,
- back: Backtrace::new(),
- })
+ bail!("Operator left on stack: {op}")
}
}
}
diff --git a/pkgs/by-name/mp/mpdpopm/src/lib.rs b/pkgs/by-name/mp/mpdpopm/src/lib.rs
index e4579db2..4fe523ea 100644
--- a/pkgs/by-name/mp/mpdpopm/src/lib.rs
+++ b/pkgs/by-name/mp/mpdpopm/src/lib.rs
@@ -49,14 +49,15 @@ pub mod filters {
include!(concat!(env!("OUT_DIR"), "/src/filters.rs"));
}
-use clients::{Client, IdleClient, IdleSubSystem};
-use config::Config;
-use config::Connection;
-use filters_ast::FilterStickerNames;
-use messages::MessageProcessor;
-use playcounts::PlayState;
+use crate::{
+ clients::{Client, IdleClient, IdleSubSystem},
+ config::{Config, Connection},
+ filters_ast::FilterStickerNames,
+ messages::MessageProcessor,
+ playcounts::PlayState,
+};
-use backtrace::Backtrace;
+use anyhow::{Context, Error};
use futures::{future::FutureExt, pin_mut, select};
use tokio::{
signal,
@@ -65,100 +66,39 @@ use tokio::{
};
use tracing::{debug, error, info};
-use std::path::PathBuf;
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-#[derive(Debug)]
-#[non_exhaustive]
-pub enum Error {
- BadPath {
- pth: PathBuf,
- },
- Client {
- source: crate::clients::Error,
- back: Backtrace,
- },
- Playcounts {
- source: crate::playcounts::Error,
- back: Backtrace,
- },
-}
-
-impl std::fmt::Display for Error {
- #[allow(unreachable_patterns)] // the _ arm is *currently* unreachable
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Error::BadPath { pth } => write!(f, "Bad path: {:?}", pth),
- Error::Client { source, back: _ } => write!(f, "Client error: {}", source),
- Error::Playcounts { source, back: _ } => write!(f, "Playcount error: {}", source),
- }
- }
-}
-
-impl std::error::Error for Error {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- match &self {
- Error::Client { source, back: _ } => Some(source),
- _ => None,
- }
- }
-}
-
-pub type Result<T> = std::result::Result<T, Error>;
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
/// Core `mppopmd' logic
pub async fn mpdpopm(cfg: Config) -> std::result::Result<(), Error> {
info!("mpdpopm {} beginning.", vars::VERSION);
let filter_stickers = FilterStickerNames::new();
- let mut client = match cfg.conn {
- Connection::Local { ref path } => {
- Client::open(path).await.map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?
- }
- Connection::TCP { ref host, port } => Client::connect(format!("{}:{}", host, port))
- .await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?,
- };
+ let mut client =
+ match cfg.conn {
+ Connection::Local { ref path } => Client::open(path)
+ .await
+ .with_context(|| format!("Failed to open socket at `{}`", path.display()))?,
+ Connection::TCP { ref host, port } => Client::connect(format!("{}:{}", host, port))
+ .await
+ .with_context(|| format!("Failed to connect to client at `{}:{}`", host, port))?,
+ };
let mut state = PlayState::new(&mut client, cfg.played_thresh)
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?;
+ .context("Failed to construct PlayState")?;
let mut idle_client = match cfg.conn {
- Connection::Local { ref path } => {
- IdleClient::open(path).await.map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?
- }
+ Connection::Local { ref path } => IdleClient::open(path)
+ .await
+ .context("Failed to open idle client")?,
Connection::TCP { ref host, port } => IdleClient::connect(format!("{}:{}", host, port))
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?,
+ .context("Failed to connect to TCP idle client")?,
};
idle_client
.subscribe(&cfg.commands_chan)
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?;
+ .context("Failed to subscribe to idle_client")?;
let mut hup = signal(SignalKind::hangup()).unwrap();
let mut kill = signal(SignalKind::terminate()).unwrap();
@@ -200,10 +140,7 @@ pub async fn mpdpopm(cfg: Config) -> std::result::Result<(), Error> {
tick.set(sleep(Duration::from_millis(cfg.poll_interval_ms)).fuse());
state.update(&mut client)
.await
- .map_err(|err| Error::Playcounts {
- source: err,
- back: Backtrace::new()
- })?
+ .context("PlayState update failed")?
},
// next = cmds.next() => match next {
// Some(out) => {
@@ -229,10 +166,7 @@ pub async fn mpdpopm(cfg: Config) -> std::result::Result<(), Error> {
if subsys == IdleSubSystem::Player {
state.update(&mut client)
.await
- .map_err(|err| Error::Playcounts {
- source: err,
- back: Backtrace::new()
- })?
+ .context("PlayState update failed")?
} else if subsys == IdleSubSystem::Message {
msg_check_needed = true;
}
diff --git a/pkgs/by-name/mp/mpdpopm/src/messages.rs b/pkgs/by-name/mp/mpdpopm/src/messages.rs
index c7c295c8..171a246a 100644
--- a/pkgs/by-name/mp/mpdpopm/src/messages.rs
+++ b/pkgs/by-name/mp/mpdpopm/src/messages.rs
@@ -54,110 +54,11 @@ use crate::{
filters_ast::{FilterStickerNames, evaluate},
};
-use backtrace::Backtrace;
+use anyhow::{Context, Error, Result, anyhow, bail};
use boolinator::Boolinator;
use tracing::debug;
use std::collections::VecDeque;
-use std::path::PathBuf;
-
-#[derive(Debug)]
-pub enum Error {
- BadPath {
- pth: PathBuf,
- },
- FilterParseError {
- msg: String,
- },
- InvalidChar {
- c: u8,
- },
- NoClosingQuotes,
- NoCommand,
- NotImplemented {
- feature: String,
- },
- PlayerStopped,
- TrailingBackslash,
- UnknownChannel {
- chan: String,
- back: Backtrace,
- },
- UnknownCommand {
- name: String,
- back: Backtrace,
- },
- Client {
- source: crate::clients::Error,
- back: Backtrace,
- },
- Ratings {
- source: crate::storage::Error,
- back: Backtrace,
- },
- Playcount {
- source: crate::storage::Error,
- back: Backtrace,
- },
- Filter {
- source: crate::filters_ast::Error,
- back: Backtrace,
- },
- Utf8 {
- source: std::str::Utf8Error,
- buf: Vec<u8>,
- back: Backtrace,
- },
- ExpectedInt {
- source: std::num::ParseIntError,
- text: String,
- back: Backtrace,
- },
-}
-
-impl std::fmt::Display for Error {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Error::BadPath { pth } => write!(f, "Bad path: {:?}", pth),
- Error::FilterParseError { msg } => write!(f, "Parse error: ``{}''", msg),
- Error::InvalidChar { c } => write!(f, "Invalid unquoted character {}", c),
- Error::NoClosingQuotes => write!(f, "Missing closing quotes"),
- Error::NoCommand => write!(f, "No command specified"),
- Error::NotImplemented { feature } => write!(f, "`{}' not implemented, yet", feature),
- Error::PlayerStopped => write!(
- f,
- "Can't operate on the current track when the player is stopped"
- ),
- Error::TrailingBackslash => write!(f, "Trailing backslash"),
- Error::UnknownChannel { chan, back: _ } => write!(
- f,
- "We received messages for an unknown channel `{}'; this is likely a bug; please consider filing a report to sp1ff@pobox.com",
- chan
- ),
- Error::UnknownCommand { name, back: _ } => {
- write!(f, "We received an unknown message ``{}''", name)
- }
- Error::Client { source, back: _ } => write!(f, "Client error: {}", source),
- Error::Ratings { source, back: _ } => write!(f, "Ratings eror: {}", source),
- Error::Playcount { source, back: _ } => write!(f, "Playcount error: {}", source),
- Error::Filter { source, back: _ } => write!(f, "Filter error: {}", source),
- Error::Utf8 {
- source,
- buf,
- back: _,
- } => write!(f, "UTF8 error {} ({:#?})", source, buf),
- Error::ExpectedInt {
- source,
- text,
- back: _,
- } => write!(f, "``{}''L {}", source, text),
- }
- }
-}
-
-pub type Result<T> = std::result::Result<T, Error>;
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
/// Break `buf` up into individual tokens while removing MPD-style quoting.
///
@@ -243,14 +144,14 @@ impl<'a> Iterator for TokenIterator<'a> {
if '\\' == self.slice[inp] as char {
inp += 1;
if inp == nslice {
- return Some(Err(Error::TrailingBackslash));
+ return Some(Err(anyhow!("Trailing backslash")));
}
}
self.slice[out] = self.slice[inp];
out += 1;
inp += 1;
if inp == nslice {
- return Some(Err(Error::NoClosingQuotes));
+ return Some(Err(anyhow!("No closing quote")));
}
}
// The next token is in self.slice[self.input..out] and self.slice[inp] is "
@@ -273,7 +174,7 @@ impl<'a> Iterator for TokenIterator<'a> {
break;
}
if self.slice[i] as char == '"' || self.slice[i] as char == '\'' {
- return Some(Err(Error::InvalidChar { c: self.slice[i] }));
+ return Some(Err(anyhow!("Invalid char: `{}`", self.slice[i])));
}
i += 1;
}
@@ -316,17 +217,11 @@ impl MessageProcessor {
let m = idle_client
.get_messages()
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?;
+ .context("Failed to `get_messages` from client")?;
for (chan, msgs) in m {
// Only supporting a single channel, ATM
- (chan == command_chan).ok_or_else(|| Error::UnknownChannel {
- chan,
- back: Backtrace::new(),
- })?;
+ (chan == command_chan).ok_or_else(|| anyhow!("Unknown chanell: `{}`", chan))?;
for msg in msgs {
self.process(msg, client, &state, stickers).await?;
}
@@ -365,11 +260,8 @@ impl MessageProcessor {
let mut buf = msg.into_bytes();
let args: VecDeque<&str> = tokenize(&mut buf)
.map(|r| match r {
- Ok(buf) => Ok(std::str::from_utf8(buf).map_err(|err| Error::Utf8 {
- source: err,
- buf: buf.to_vec(),
- back: Backtrace::new(),
- })?),
+ Ok(buf) => Ok(std::str::from_utf8(buf)
+ .context("Failed to interpete `findadd` string as utf8")?),
Err(err) => Err(err),
})
.collect::<Result<VecDeque<&str>>>()?;
@@ -385,9 +277,7 @@ impl MessageProcessor {
let ast = match ExpressionParser::new().parse(args[0]) {
Ok(ast) => ast,
Err(err) => {
- return Err(Error::FilterParseError {
- msg: format!("{}", err),
- });
+ bail!("Failed to parse filter: `{}`", err)
}
};
@@ -396,22 +286,16 @@ impl MessageProcessor {
let mut results = Vec::new();
for song in evaluate(&ast, true, client, stickers)
.await
- .map_err(|err| Error::Filter {
- source: err,
- back: Backtrace::new(),
- })?
+ .context("Failed to evaluate filter")?
{
results.push(client.add(&song).await);
}
match results
.into_iter()
- .collect::<std::result::Result<Vec<()>, crate::clients::Error>>()
+ .collect::<std::result::Result<Vec<()>, Error>>()
{
Ok(_) => Ok(()),
- Err(err) => Err(Error::Client {
- source: err,
- back: Backtrace::new(),
- }),
+ Err(err) => Err(err),
}
}
@@ -427,14 +311,11 @@ impl MessageProcessor {
let mut buf = msg.into_bytes();
let args: VecDeque<&str> = tokenize(&mut buf)
.map(|r| match r {
- Ok(buf) => Ok(std::str::from_utf8(buf).map_err(|err| Error::Utf8 {
- source: err,
- buf: buf.to_vec(),
- back: Backtrace::new(),
- })?),
+ Ok(buf) => Ok(std::str::from_utf8(buf)
+ .context("Failed to interpete `searchadd` string as utf8")?),
Err(err) => Err(err),
})
- .collect::<Result<VecDeque<&str>>>()?;
+ .collect::<Result<VecDeque<_>>>()?;
debug!("searchadd arguments: {:#?}", args);
@@ -447,9 +328,7 @@ impl MessageProcessor {
let ast = match ExpressionParser::new().parse(args[0]) {
Ok(ast) => ast,
Err(err) => {
- return Err(Error::FilterParseError {
- msg: format!("{}", err),
- });
+ bail!("Failed to parse filter: `{err}`")
}
};
@@ -458,22 +337,16 @@ impl MessageProcessor {
let mut results = Vec::new();
for song in evaluate(&ast, false, client, stickers)
.await
- .map_err(|err| Error::Filter {
- source: err,
- back: Backtrace::new(),
- })?
+ .context("Failed to evaluate ast")?
{
results.push(client.add(&song).await);
}
match results
.into_iter()
- .collect::<std::result::Result<Vec<()>, crate::clients::Error>>()
+ .collect::<std::result::Result<Vec<()>, Error>>()
{
Ok(_) => Ok(()),
- Err(err) => Err(Error::Client {
- source: err,
- back: Backtrace::new(),
- }),
+ Err(err) => Err(err),
}
}
}
diff --git a/pkgs/by-name/mp/mpdpopm/src/playcounts.rs b/pkgs/by-name/mp/mpdpopm/src/playcounts.rs
index 6ae8f903..7d646b4c 100644
--- a/pkgs/by-name/mp/mpdpopm/src/playcounts.rs
+++ b/pkgs/by-name/mp/mpdpopm/src/playcounts.rs
@@ -26,67 +26,13 @@
//!
use crate::clients::{Client, PlayerStatus};
-use crate::storage::{self, last_played, play_count, skipped};
+use crate::storage::{last_played, play_count, skipped};
-use backtrace::Backtrace;
+use anyhow::{Context, Error, Result, anyhow};
use tracing::{debug, info};
-use std::path::PathBuf;
use std::time::SystemTime;
-#[derive(Debug)]
-pub enum Error {
- PlayerStopped,
- BadPath {
- pth: PathBuf,
- },
- SystemTime {
- source: std::time::SystemTimeError,
- back: Backtrace,
- },
- Client {
- source: crate::clients::Error,
- back: Backtrace,
- },
-}
-
-impl std::fmt::Display for Error {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Error::PlayerStopped => write!(f, "The MPD player is stopped"),
- Error::BadPath { pth } => write!(f, "Bad path: {:?}", pth),
- Error::SystemTime { source, back: _ } => {
- write!(f, "Couldn't get system time: {}", source)
- }
- Error::Client { source, back: _ } => write!(f, "Client error: {}", source),
- }
- }
-}
-
-impl std::error::Error for Error {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- match &self {
- Error::SystemTime { source, back: _ } => Some(source),
- Error::Client { source, back: _ } => Some(source),
- _ => None,
- }
- }
-}
-
-impl From<storage::Error> for Error {
- fn from(value: storage::Error) -> Self {
- match value {
- storage::Error::PlayerStopped => Self::PlayerStopped,
- storage::Error::BadPath { pth } => Self::BadPath { pth },
- storage::Error::SystemTime { source, back } => Self::SystemTime { source, back },
- storage::Error::Client { source, back } => Self::Client { source, back },
- _ => unreachable!(),
- }
- }
-}
-
-type Result<T> = std::result::Result<T, Error>;
-
/// Current server state in terms of the play status (stopped/paused/playing, current track, elapsed
/// time in current track, &c)
#[derive(Debug)]
@@ -109,7 +55,7 @@ impl PlayState {
pub async fn new(
client: &mut Client,
played_thresh: f64,
- ) -> std::result::Result<PlayState, crate::clients::Error> {
+ ) -> std::result::Result<PlayState, Error> {
Ok(PlayState {
last_server_stat: client.status().await?,
have_incr_play_count: false,
@@ -126,10 +72,10 @@ impl PlayState {
/// Poll the server-- update our status; maybe increment the current track's play count; the
/// caller must arrange to have this method invoked periodically to keep our state fresh
pub async fn update(&mut self, client: &mut Client) -> Result<()> {
- let new_stat = client.status().await.map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?;
+ let new_stat = client
+ .status()
+ .await
+ .context("Failed to get client status")?;
match (&self.last_server_stat, &new_stat) {
(PlayerStatus::Play(last), PlayerStatus::Play(curr))
@@ -176,8 +122,8 @@ impl PlayState {
curr.elapsed / curr.duration
);
- let file = curr.file.to_str().ok_or_else(|| Error::BadPath {
- pth: curr.file.clone(),
+ let file = curr.file.to_str().ok_or_else(|| {
+ anyhow!("Failed to parse path as utf8: `{}`", curr.file.display())
})?;
let curr_pc = play_count::get(client, file).await?.unwrap_or_default();
@@ -189,10 +135,7 @@ impl PlayState {
file,
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
- .map_err(|err| Error::SystemTime {
- source: err,
- back: Backtrace::new(),
- })?
+ .context("Failed to get system time")?
.as_secs(),
)
.await?;
@@ -213,8 +156,8 @@ impl PlayState {
last.elapsed / last.duration
);
- let file = last.file.to_str().ok_or_else(|| Error::BadPath {
- pth: last.file.clone(),
+ let file = last.file.to_str().ok_or_else(|| {
+ anyhow!("Failed to parse path as utf8: `{}`", last.file.display())
})?;
let skip_count = skipped::get(client, file).await?.unwrap_or_default();
@@ -350,7 +293,10 @@ OK
),
"OK\n",
),
- ("sticker set song \"E/Enya - Wild Child.mp3\" unwoundstack.com:playcount 12", "OK\n"),
+ (
+ "sticker set song \"E/Enya - Wild Child.mp3\" unwoundstack.com:playcount 12",
+ "OK\n",
+ ),
]));
let mut cli = Client::new(mock).unwrap();
diff --git a/pkgs/by-name/mp/mpdpopm/src/storage/mod.rs b/pkgs/by-name/mp/mpdpopm/src/storage/mod.rs
index d64f17c1..24d8dcb5 100644
--- a/pkgs/by-name/mp/mpdpopm/src/storage/mod.rs
+++ b/pkgs/by-name/mp/mpdpopm/src/storage/mod.rs
@@ -1,54 +1,11 @@
-use std::path::PathBuf;
-
-use backtrace::Backtrace;
-
-#[derive(Debug)]
-pub enum Error {
- PlayerStopped,
- BadPath {
- pth: PathBuf,
- },
- SystemTime {
- source: std::time::SystemTimeError,
- back: Backtrace,
- },
- Client {
- source: crate::clients::Error,
- back: Backtrace,
- },
-}
-
-impl std::fmt::Display for Error {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- match self {
- Error::PlayerStopped => write!(f, "The MPD player is stopped"),
- Error::BadPath { pth } => write!(f, "Bad path: {:?}", pth),
- Error::SystemTime { source, back: _ } => {
- write!(f, "Couldn't get system time: {}", source)
- }
- Error::Client { source, back: _ } => write!(f, "Client error: {}", source),
- }
- }
-}
-
-impl std::error::Error for Error {
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- match &self {
- Error::SystemTime { source, back: _ } => Some(source),
- Error::Client { source, back: _ } => Some(source),
- _ => None,
- }
- }
-}
-
-type Result<T> = std::result::Result<T, Error>;
+use anyhow::{Error, Result};
pub mod play_count {
- use backtrace::Backtrace;
+ use anyhow::Context;
use crate::clients::Client;
- use super::{Error, Result};
+ use super::Result;
pub const STICKER: &str = "unwoundstack.com:playcount";
@@ -57,10 +14,8 @@ pub mod play_count {
match client
.get_sticker::<usize>(file, STICKER)
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })? {
+ .context("Failed to get sticker from client")?
+ {
Some(n) => Ok(Some(n)),
None => Ok(None),
}
@@ -71,10 +26,7 @@ pub mod play_count {
client
.set_sticker(file, STICKER, &format!("{}", play_count))
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?;
+ .context("Failed to set_sticker on client")?;
Ok(())
}
@@ -109,11 +61,11 @@ pub mod play_count {
}
pub mod skipped {
- use backtrace::Backtrace;
+ use anyhow::Context;
use crate::clients::Client;
- use super::{Error, Result};
+ use super::Result;
const STICKER: &str = "unwoundstack.com:skipped_count";
@@ -122,10 +74,8 @@ pub mod skipped {
match client
.get_sticker::<usize>(file, STICKER)
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })? {
+ .context("Failed to get_sticker on client")?
+ {
Some(n) => Ok(Some(n)),
None => Ok(None),
}
@@ -136,19 +86,16 @@ pub mod skipped {
client
.set_sticker(file, STICKER, &format!("{}", skip_count))
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })
+ .context("Failed to set_sticker on client")
}
}
pub mod last_played {
- use backtrace::Backtrace;
+ use anyhow::Context;
use crate::clients::Client;
- use super::{Error, Result};
+ use super::Result;
pub const STICKER: &str = "unwoundstack.com:lastplayed";
@@ -157,10 +104,7 @@ pub mod last_played {
client
.get_sticker::<u64>(file, STICKER)
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })
+ .context("Falied to get_sticker on client")
}
/// Set the last played for a track
@@ -168,20 +112,17 @@ pub mod last_played {
client
.set_sticker(file, STICKER, &format!("{}", last_played))
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?;
+ .context("Failed to set_sticker on client")?;
Ok(())
}
}
pub mod rating_count {
- use backtrace::Backtrace;
+ use anyhow::Context;
use crate::clients::Client;
- use super::{Error, Result};
+ use super::Result;
pub const STICKER: &str = "unwoundstack.com:ratings_count";
@@ -190,10 +131,7 @@ pub mod rating_count {
client
.get_sticker::<i8>(file, STICKER)
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })
+ .context("Failed to get_sticker on client")
}
/// Set the rating count for a track
@@ -201,10 +139,7 @@ pub mod rating_count {
client
.set_sticker(file, STICKER, &format!("{}", rating_count))
.await
- .map_err(|err| Error::Client {
- source: err,
- back: Backtrace::new(),
- })?;
+ .context("Failed to set_sticker on client")?;
Ok(())
}
}
diff --git a/pkgs/by-name/mp/mpdpopm/src/vars.rs b/pkgs/by-name/mp/mpdpopm/src/vars.rs
index 29b9610d..7cacec66 100644
--- a/pkgs/by-name/mp/mpdpopm/src/vars.rs
+++ b/pkgs/by-name/mp/mpdpopm/src/vars.rs
@@ -2,4 +2,3 @@ pub static VERSION: &str = env!("CARGO_PKG_VERSION");
pub static AUTHOR: &str = env!("CARGO_PKG_AUTHORS");
pub static LOCALSTATEDIR: &str = "/home/soispha/.local/state";
pub static PREFIX: &str = "/home/soispha/.local/share/mpdpopm";
-