Error types consolidation

This commit is contained in:
Antoine Gersant 2024-08-01 00:09:21 -07:00
parent 8f2566f574
commit cd45836924
16 changed files with 185 additions and 350 deletions

View file

@ -1,7 +1,7 @@
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use crate::db::{self, DB}; use crate::db::DB;
use crate::paths::Paths; use crate::paths::Paths;
pub mod config; pub mod config;
@ -22,15 +22,105 @@ pub mod test;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub enum Error { pub enum Error {
#[error(transparent)] #[error(transparent)]
Collection(#[from] index::Error), ThreadPoolBuilder(#[from] rayon::ThreadPoolBuildError),
#[error(transparent)] #[error(transparent)]
Config(#[from] config::Error), ThreadJoining(#[from] tokio::task::JoinError),
#[error(transparent)]
Database(#[from] db::Error),
#[error("Filesystem error for `{0}`: `{1}`")] #[error("Filesystem error for `{0}`: `{1}`")]
Io(PathBuf, std::io::Error), Io(PathBuf, std::io::Error),
#[error(transparent)] #[error(transparent)]
Settings(#[from] settings::Error), Ape(#[from] ape::Error),
#[error("ID3 error in `{0}`: `{1}`")]
Id3(PathBuf, id3::Error),
#[error("Metaflac error in `{0}`: `{1}`")]
Metaflac(PathBuf, metaflac::Error),
#[error("Mp4aMeta error in `{0}`: `{1}`")]
Mp4aMeta(PathBuf, mp4ameta::Error),
#[error(transparent)]
Opus(#[from] opus_headers::ParseError),
#[error(transparent)]
Vorbis(#[from] lewton::VorbisError),
#[error("Could not find a Vorbis comment within flac file")]
VorbisCommentNotFoundInFlacFile,
#[error("Could not read thumbnail image in `{0}`:\n\n{1}")]
Image(PathBuf, image::error::ImageError),
#[error("This file format is not supported: {0}")]
UnsupportedFormat(&'static str),
#[error(transparent)]
Database(#[from] sqlx::Error),
#[error("Could not initialize database connection pool")]
ConnectionPoolBuild,
#[error("Could not acquire database connection from pool")]
ConnectionPool,
#[error("Could not apply database migrations: {0}")]
Migration(sqlx::migrate::MigrateError),
#[error("DDNS update query failed with HTTP status code `{0}`")]
UpdateQueryFailed(u16),
#[error("DDNS update query failed due to a transport error")]
UpdateQueryTransport,
#[error("Auth secret does not have the expected format")]
AuthenticationSecretInvalid,
#[error("Missing auth secret")]
AuthenticationSecretNotFound,
#[error("Missing settings")]
MiscSettingsNotFound,
#[error("Index album art pattern is not a valid regex")]
IndexAlbumArtPatternInvalid,
#[error(transparent)]
Toml(#[from] toml::de::Error),
#[error("Could not deserialize collection")]
IndexDeserializationError,
#[error("Could not serialize collection")]
IndexSerializationError,
#[error("The following virtual path could not be mapped to a real path: `{0}`")]
CouldNotMapToRealPath(PathBuf),
#[error("User not found")]
UserNotFound,
#[error("Directory not found: {0}")]
DirectoryNotFound(PathBuf),
#[error("Artist not found")]
ArtistNotFound,
#[error("Album not found")]
AlbumNotFound,
#[error("Song not found")]
SongNotFound,
#[error("Playlist not found")]
PlaylistNotFound,
#[error("No embedded artwork was found in `{0}`")]
EmbeddedArtworkNotFound(PathBuf),
#[error("Cannot use empty username")]
EmptyUsername,
#[error("Cannot use empty password")]
EmptyPassword,
#[error("Username does not exist")]
IncorrectUsername,
#[error("Password does not match username")]
IncorrectPassword,
#[error("Invalid auth token")]
InvalidAuthToken,
#[error("Incorrect authorization scope")]
IncorrectAuthorizationScope,
#[error("Last.fm session key is missing")]
MissingLastFMSessionKey,
#[error("Failed to hash password")]
PasswordHashing,
#[error("Failed to encode authorization token")]
AuthorizationTokenEncoding,
#[error("Failed to encode Branca token")]
BrancaTokenEncoding,
#[error("Failed to authenticate with last.fm")]
ScrobblerAuthentication(rustfm_scrobble::ScrobblerError),
#[error("Failed to emit last.fm scrobble")]
Scrobble(rustfm_scrobble::ScrobblerError),
#[error("Failed to emit last.fm now playing update")]
NowPlaying(rustfm_scrobble::ScrobblerError),
} }
#[derive(Clone)] #[derive(Clone)]

View file

@ -1,24 +1,7 @@
use serde::Deserialize; use serde::Deserialize;
use std::io::Read; use std::{io::Read, path::Path};
use std::path::{Path, PathBuf};
use crate::app::{ddns, settings, user, vfs}; use crate::app::{ddns, settings, user, vfs, Error};
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
Ddns(#[from] ddns::Error),
#[error("Filesystem error for `{0}`: `{1}`")]
Io(PathBuf, std::io::Error),
#[error(transparent)]
Settings(#[from] settings::Error),
#[error(transparent)]
Toml(#[from] toml::de::Error),
#[error(transparent)]
User(#[from] user::Error),
#[error(transparent)]
Vfs(#[from] vfs::Error),
}
#[derive(Default, Deserialize)] #[derive(Default, Deserialize)]
pub struct Config { pub struct Config {

View file

@ -3,22 +3,11 @@ use log::{debug, error};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
use crate::db::{self, DB}; use crate::app::Error;
use crate::db::DB;
const DDNS_UPDATE_URL: &str = "https://ydns.io/api/v1/update/"; const DDNS_UPDATE_URL: &str = "https://ydns.io/api/v1/update/";
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("DDNS update query failed with HTTP status code `{0}`")]
UpdateQueryFailed(u16),
#[error("DDNS update query failed due to a transport error")]
UpdateQueryTransport,
#[error(transparent)]
DatabaseConnection(#[from] db::Error),
#[error(transparent)]
Database(#[from] sqlx::Error),
}
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
pub struct Config { pub struct Config {
pub ddns_host: String, pub ddns_host: String,

View file

@ -2,31 +2,12 @@ use id3::TagLike;
use lewton::inside_ogg::OggStreamReader; use lewton::inside_ogg::OggStreamReader;
use log::error; use log::error;
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::Path;
use crate::app::Error;
use crate::utils; use crate::utils;
use crate::utils::AudioFormat; use crate::utils::AudioFormat;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
Ape(#[from] ape::Error),
#[error(transparent)]
Id3(#[from] id3::Error),
#[error("Filesystem error for `{0}`: `{1}`")]
Io(PathBuf, std::io::Error),
#[error(transparent)]
Metaflac(#[from] metaflac::Error),
#[error(transparent)]
Mp4aMeta(#[from] mp4ameta::Error),
#[error(transparent)]
Opus(#[from] opus_headers::ParseError),
#[error(transparent)]
Vorbis(#[from] lewton::VorbisError),
#[error("Could not find a Vorbis comment within flac file")]
VorbisCommentNotFoundInFlacFile,
}
#[derive(Debug, Default, Clone, PartialEq, Eq)] #[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct SongMetadata { pub struct SongMetadata {
pub disc_number: Option<u32>, pub disc_number: Option<u32>,
@ -83,13 +64,15 @@ impl ID3Ext for id3::Tag {
} }
fn read_id3<P: AsRef<Path>>(path: P) -> Result<SongMetadata, Error> { fn read_id3<P: AsRef<Path>>(path: P) -> Result<SongMetadata, Error> {
let tag = id3::Tag::read_from_path(path).or_else(|error| { let tag = id3::Tag::read_from_path(&path)
if let Some(tag) = error.partial_tag { .or_else(|error| {
Ok(tag) if let Some(tag) = error.partial_tag {
} else { Ok(tag)
Err(error) } else {
} Err(error)
})?; }
})
.map_err(|e| Error::Id3(path.as_ref().to_owned(), e))?;
let artists = tag.get_text_values("TPE1"); let artists = tag.get_text_values("TPE1");
let album_artists = tag.get_text_values("TPE2"); let album_artists = tag.get_text_values("TPE2");
@ -255,7 +238,8 @@ fn read_opus<P: AsRef<Path>>(path: P) -> Result<SongMetadata, Error> {
} }
fn read_flac<P: AsRef<Path>>(path: P) -> Result<SongMetadata, Error> { fn read_flac<P: AsRef<Path>>(path: P) -> Result<SongMetadata, Error> {
let tag = metaflac::Tag::read_from_path(path)?; let tag = metaflac::Tag::read_from_path(&path)
.map_err(|e| Error::Metaflac(path.as_ref().to_owned(), e))?;
let vorbis = tag let vorbis = tag
.vorbis_comments() .vorbis_comments()
.ok_or(Error::VorbisCommentNotFoundInFlacFile)?; .ok_or(Error::VorbisCommentNotFoundInFlacFile)?;
@ -290,7 +274,8 @@ fn read_flac<P: AsRef<Path>>(path: P) -> Result<SongMetadata, Error> {
} }
fn read_mp4<P: AsRef<Path>>(path: P) -> Result<SongMetadata, Error> { fn read_mp4<P: AsRef<Path>>(path: P) -> Result<SongMetadata, Error> {
let mut tag = mp4ameta::Tag::read_from_path(path)?; let mut tag = mp4ameta::Tag::read_from_path(&path)
.map_err(|e| Error::Mp4aMeta(path.as_ref().to_owned(), e))?;
let label_ident = mp4ameta::FreeformIdent::new("com.apple.iTunes", "Label"); let label_ident = mp4ameta::FreeformIdent::new("com.apple.iTunes", "Label");
Ok(SongMetadata { Ok(SongMetadata {

View file

@ -7,9 +7,8 @@ use log::{error, info};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::task::spawn_blocking; use tokio::task::spawn_blocking;
use crate::app::scanner; use crate::app::{scanner, Error};
use crate::app::vfs; use crate::db::DB;
use crate::db::{self, DB};
mod browser; mod browser;
mod collection; mod collection;
@ -18,32 +17,6 @@ mod search;
pub use browser::File; pub use browser::File;
pub use collection::{Album, AlbumKey, Artist, ArtistKey, Song, SongKey}; pub use collection::{Album, AlbumKey, Artist, ArtistKey, Song, SongKey};
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Directory not found: {0}")]
DirectoryNotFound(PathBuf),
#[error("Artist not found")]
ArtistNotFound,
#[error("Album not found")]
AlbumNotFound,
#[error("Song not found")]
SongNotFound,
#[error(transparent)]
Database(#[from] sqlx::Error),
#[error(transparent)]
DatabaseConnection(#[from] db::Error),
#[error(transparent)]
Vfs(#[from] vfs::Error),
#[error("Could not deserialize collection")]
IndexDeserializationError,
#[error("Could not serialize collection")]
IndexSerializationError,
#[error(transparent)]
ThreadPoolBuilder(#[from] rayon::ThreadPoolBuildError),
#[error(transparent)]
ThreadJoining(#[from] tokio::task::JoinError),
}
#[derive(Clone)] #[derive(Clone)]
pub struct Manager { pub struct Manager {
db: DB, db: DB,

View file

@ -7,7 +7,7 @@ use std::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use trie_rs::{Trie, TrieBuilder}; use trie_rs::{Trie, TrieBuilder};
use crate::app::{index::Error, scanner}; use crate::app::{scanner, Error};
#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub enum File { pub enum File {

View file

@ -2,25 +2,11 @@ use rustfm_scrobble::{Scrobble, Scrobbler};
use std::path::Path; use std::path::Path;
use user::AuthToken; use user::AuthToken;
use crate::app::{index, user}; use crate::app::{index, user, Error};
const LASTFM_API_KEY: &str = "02b96c939a2b451c31dfd67add1f696e"; const LASTFM_API_KEY: &str = "02b96c939a2b451c31dfd67add1f696e";
const LASTFM_API_SECRET: &str = "0f25a80ceef4b470b5cb97d99d4b3420"; const LASTFM_API_SECRET: &str = "0f25a80ceef4b470b5cb97d99d4b3420";
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Failed to authenticate with last.fm")]
ScrobblerAuthentication(rustfm_scrobble::ScrobblerError),
#[error("Failed to emit last.fm scrobble")]
Scrobble(rustfm_scrobble::ScrobblerError),
#[error("Failed to emit last.fm now playing update")]
NowPlaying(rustfm_scrobble::ScrobblerError),
#[error(transparent)]
Query(#[from] index::Error),
#[error(transparent)]
User(#[from] user::Error),
}
#[derive(Clone)] #[derive(Clone)]
pub struct Manager { pub struct Manager {
index_manager: index::Manager, index_manager: index::Manager,

View file

@ -2,22 +2,8 @@ use core::clone::Clone;
use sqlx::{Acquire, QueryBuilder, Sqlite}; use sqlx::{Acquire, QueryBuilder, Sqlite};
use std::path::PathBuf; use std::path::PathBuf;
use crate::app::vfs; use crate::app::{vfs, Error};
use crate::db::{self, DB}; use crate::db::DB;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
Database(#[from] sqlx::Error),
#[error(transparent)]
DatabaseConnection(#[from] db::Error),
#[error("User not found")]
UserNotFound,
#[error("Playlist not found")]
PlaylistNotFound,
#[error(transparent)]
Vfs(#[from] vfs::Error),
}
#[derive(Clone)] #[derive(Clone)]
pub struct Manager { pub struct Manager {
@ -191,7 +177,7 @@ impl Manager {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use std::path::{Path, PathBuf}; use std::path::PathBuf;
use crate::app::test; use crate::app::test;
use crate::test_name; use crate::test_name;

View file

@ -11,7 +11,7 @@ use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
use tokio::sync::Notify; use tokio::sync::Notify;
use tokio::time::Instant; use tokio::time::Instant;
use crate::app::{formats, index, settings, vfs}; use crate::app::{formats, index, settings, vfs, Error};
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub struct Directory { pub struct Directory {
@ -53,7 +53,7 @@ impl Scanner {
index_manager: index::Manager, index_manager: index::Manager,
settings_manager: settings::Manager, settings_manager: settings::Manager,
vfs_manager: vfs::Manager, vfs_manager: vfs::Manager,
) -> Result<Self, index::Error> { ) -> Result<Self, Error> {
let scanner = Self { let scanner = Self {
index_manager, index_manager,
vfs_manager, vfs_manager,
@ -100,7 +100,7 @@ impl Scanner {
}); });
} }
pub async fn update(&mut self) -> Result<(), index::Error> { pub async fn update(&mut self) -> Result<(), Error> {
let start = Instant::now(); let start = Instant::now();
info!("Beginning collection scan"); info!("Beginning collection scan");
@ -185,7 +185,7 @@ impl Scan {
} }
} }
pub async fn start(self) -> Result<(), index::Error> { pub async fn start(self) -> Result<(), Error> {
let vfs = self.vfs_manager.get_vfs().await?; let vfs = self.vfs_manager.get_vfs().await?;
let roots = vfs.mounts().clone(); let roots = vfs.mounts().clone();

View file

@ -2,23 +2,8 @@ use regex::Regex;
use serde::Deserialize; use serde::Deserialize;
use std::time::Duration; use std::time::Duration;
use crate::db::{self, DB}; use crate::app::Error;
use crate::db::DB;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Auth secret does not have the expected format")]
AuthenticationSecretInvalid,
#[error("Missing auth secret")]
AuthenticationSecretNotFound,
#[error(transparent)]
DatabaseConnection(#[from] db::Error),
#[error("Missing settings")]
MiscSettingsNotFound,
#[error("Index album art pattern is not a valid regex")]
IndexAlbumArtPatternInvalid,
#[error(transparent)]
Database(#[from] sqlx::Error),
}
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct AuthSecret { pub struct AuthSecret {

View file

@ -6,26 +6,9 @@ use std::fs::{self, File};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use crate::app::Error;
use crate::utils::{get_audio_format, AudioFormat}; use crate::utils::{get_audio_format, AudioFormat};
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("No embedded artwork was found in `{0}`")]
EmbeddedArtworkNotFound(PathBuf),
#[error("Could not read thumbnail from ID3 tag in `{0}`:\n\n{1}")]
Id3(PathBuf, id3::Error),
#[error("Could not read thumbnail image in `{0}`:\n\n{1}")]
Image(PathBuf, image::error::ImageError),
#[error("Filesystem error for `{0}`: `{1}`")]
Io(PathBuf, std::io::Error),
#[error("Could not read thumbnail from flac file in `{0}`:\n\n{1}")]
Metaflac(PathBuf, metaflac::Error),
#[error("Could not read thumbnail from mp4 file in `{0}`:\n\n{1}")]
Mp4aMeta(PathBuf, mp4ameta::Error),
#[error("This file format is not supported: {0}")]
UnsupportedFormat(&'static str),
}
#[derive(Debug, Hash)] #[derive(Debug, Hash)]
pub struct Options { pub struct Options {
pub max_dimension: Option<u32>, pub max_dimension: Option<u32>,

View file

@ -5,35 +5,8 @@ use serde::{Deserialize, Serialize};
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use crate::app::settings::AuthSecret; use crate::app::settings::AuthSecret;
use crate::db::{self, DB}; use crate::app::Error;
use crate::db::DB;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
Database(#[from] sqlx::Error),
#[error(transparent)]
DatabaseConnection(#[from] db::Error),
#[error("Cannot use empty username")]
EmptyUsername,
#[error("Cannot use empty password")]
EmptyPassword,
#[error("Username does not exist")]
IncorrectUsername,
#[error("Password does not match username")]
IncorrectPassword,
#[error("Invalid auth token")]
InvalidAuthToken,
#[error("Incorrect authorization scope")]
IncorrectAuthorizationScope,
#[error("Last.fm session key is missing")]
MissingLastFMSessionKey,
#[error("Failed to hash password")]
PasswordHashing,
#[error("Failed to encode authorization token")]
AuthorizationTokenEncoding,
#[error("Failed to encode Branca token")]
BrancaTokenEncoding,
}
#[derive(Debug)] #[derive(Debug)]
pub struct User { pub struct User {

View file

@ -4,17 +4,8 @@ use serde::{Deserialize, Serialize};
use sqlx::{Acquire, QueryBuilder, Sqlite}; use sqlx::{Acquire, QueryBuilder, Sqlite};
use std::path::{self, Path, PathBuf}; use std::path::{self, Path, PathBuf};
use crate::db::{self, DB}; use crate::app::Error;
use crate::db::DB;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("The following virtual path could not be mapped to a real path: `{0}`")]
CouldNotMapToRealPath(PathBuf),
#[error(transparent)]
DatabaseConnection(#[from] db::Error),
#[error(transparent)]
Database(#[from] sqlx::Error),
}
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
pub struct MountDir { pub struct MountDir {

View file

@ -1,4 +1,4 @@
use std::path::{Path, PathBuf}; use std::path::Path;
use sqlx::{ use sqlx::{
migrate::Migrator, migrate::Migrator,
@ -7,19 +7,9 @@ use sqlx::{
Sqlite, Sqlite,
}; };
static MIGRATOR: Migrator = sqlx::migrate!("src/db"); use crate::app::Error;
#[derive(thiserror::Error, Debug)] static MIGRATOR: Migrator = sqlx::migrate!("src/db");
pub enum Error {
#[error("Could not initialize database connection pool")]
ConnectionPoolBuild,
#[error("Could not acquire database connection from pool")]
ConnectionPool,
#[error("Filesystem error for `{0}`: `{1}`")]
Io(PathBuf, std::io::Error),
#[error("Could not apply database migrations: {0}")]
Migration(sqlx::migrate::MigrateError),
}
#[derive(Clone)] #[derive(Clone)]
pub struct DB { pub struct DB {

View file

@ -39,13 +39,11 @@ impl IntoResponse for APIError {
APIError::OwnAdminPrivilegeRemoval => StatusCode::CONFLICT, APIError::OwnAdminPrivilegeRemoval => StatusCode::CONFLICT,
APIError::PasswordHashing => StatusCode::INTERNAL_SERVER_ERROR, APIError::PasswordHashing => StatusCode::INTERNAL_SERVER_ERROR,
APIError::PlaylistNotFound => StatusCode::NOT_FOUND, APIError::PlaylistNotFound => StatusCode::NOT_FOUND,
APIError::Settings(_) => StatusCode::INTERNAL_SERVER_ERROR,
APIError::ThumbnailFlacDecoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR, APIError::ThumbnailFlacDecoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR,
APIError::ThumbnailFileIOError => StatusCode::NOT_FOUND, APIError::ThumbnailFileIOError => StatusCode::NOT_FOUND,
APIError::ThumbnailId3Decoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR, APIError::ThumbnailId3Decoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR,
APIError::ThumbnailImageDecoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR, APIError::ThumbnailImageDecoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR,
APIError::ThumbnailMp4Decoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR, APIError::ThumbnailMp4Decoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR,
APIError::TomlDeserialization(_) => StatusCode::INTERNAL_SERVER_ERROR,
APIError::UnsupportedThumbnailFormat(_) => StatusCode::INTERNAL_SERVER_ERROR, APIError::UnsupportedThumbnailFormat(_) => StatusCode::INTERNAL_SERVER_ERROR,
APIError::UserNotFound => StatusCode::NOT_FOUND, APIError::UserNotFound => StatusCode::NOT_FOUND,
APIError::VFSPathNotFound => StatusCode::NOT_FOUND, APIError::VFSPathNotFound => StatusCode::NOT_FOUND,

View file

@ -1,8 +1,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use thiserror::Error; use thiserror::Error;
use crate::app::{config, ddns, index, lastfm, playlist, settings, thumbnail, user, vfs}; use crate::app;
use crate::db;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum APIError { pub enum APIError {
@ -66,8 +65,6 @@ pub enum APIError {
PasswordHashing, PasswordHashing,
#[error("Playlist not found")] #[error("Playlist not found")]
PlaylistNotFound, PlaylistNotFound,
#[error("Settings error:\n\n{0}")]
Settings(settings::Error),
#[error("Could not decode thumbnail from flac file `{0}`:\n\n{1}")] #[error("Could not decode thumbnail from flac file `{0}`:\n\n{1}")]
ThumbnailFlacDecoding(PathBuf, metaflac::Error), ThumbnailFlacDecoding(PathBuf, metaflac::Error),
#[error("Thumbnail file could not be opened")] #[error("Thumbnail file could not be opened")]
@ -78,8 +75,6 @@ pub enum APIError {
ThumbnailImageDecoding(PathBuf, image::error::ImageError), ThumbnailImageDecoding(PathBuf, image::error::ImageError),
#[error("Could not decode thumbnail from mp4 file `{0}`:\n\n{1}")] #[error("Could not decode thumbnail from mp4 file `{0}`:\n\n{1}")]
ThumbnailMp4Decoding(PathBuf, mp4ameta::Error), ThumbnailMp4Decoding(PathBuf, mp4ameta::Error),
#[error("Toml deserialization error:\n\n{0}")]
TomlDeserialization(toml::de::Error),
#[error("Unsupported thumbnail format: `{0}`")] #[error("Unsupported thumbnail format: `{0}`")]
UnsupportedThumbnailFormat(&'static str), UnsupportedThumbnailFormat(&'static str),
#[error("User not found")] #[error("User not found")]
@ -88,135 +83,63 @@ pub enum APIError {
VFSPathNotFound, VFSPathNotFound,
} }
impl From<index::Error> for APIError { impl From<app::Error> for APIError {
fn from(error: index::Error) -> APIError { fn from(error: app::Error) -> APIError {
match error { match error {
index::Error::DirectoryNotFound(d) => APIError::DirectoryNotFound(d), app::Error::ThreadPoolBuilder(_) => APIError::Internal,
index::Error::ArtistNotFound => APIError::ArtistNotFound, app::Error::ThreadJoining(_) => APIError::Internal,
index::Error::AlbumNotFound => APIError::AlbumNotFound,
index::Error::SongNotFound => APIError::SongNotFound,
index::Error::Database(e) => APIError::Database(e),
index::Error::DatabaseConnection(e) => e.into(),
index::Error::Vfs(e) => e.into(),
index::Error::IndexDeserializationError => APIError::Internal,
index::Error::IndexSerializationError => APIError::Internal,
index::Error::ThreadPoolBuilder(_) => APIError::Internal,
index::Error::ThreadJoining(_) => APIError::Internal,
}
}
}
impl From<config::Error> for APIError { app::Error::Io(p, e) => APIError::Io(p, e),
fn from(error: config::Error) -> APIError { app::Error::Ape(_) => APIError::Internal,
match error { app::Error::Id3(p, e) => APIError::ThumbnailId3Decoding(p, e),
config::Error::Ddns(e) => e.into(), app::Error::Metaflac(p, e) => APIError::ThumbnailFlacDecoding(p, e),
config::Error::Io(p, e) => APIError::Io(p, e), app::Error::Mp4aMeta(p, e) => APIError::ThumbnailMp4Decoding(p, e),
config::Error::Settings(e) => e.into(), app::Error::Opus(_) => APIError::Internal,
config::Error::Toml(e) => APIError::TomlDeserialization(e), app::Error::Vorbis(_) => APIError::Internal,
config::Error::User(e) => e.into(), app::Error::VorbisCommentNotFoundInFlacFile => APIError::Internal,
config::Error::Vfs(e) => e.into(), app::Error::Image(p, e) => APIError::ThumbnailImageDecoding(p, e),
} app::Error::UnsupportedFormat(f) => APIError::UnsupportedThumbnailFormat(f),
}
}
impl From<playlist::Error> for APIError { app::Error::Database(e) => APIError::Database(e),
fn from(error: playlist::Error) -> APIError { app::Error::ConnectionPoolBuild => APIError::Internal,
match error { app::Error::ConnectionPool => APIError::Internal,
playlist::Error::Database(e) => APIError::Database(e), app::Error::Migration(_) => APIError::Internal,
playlist::Error::DatabaseConnection(e) => e.into(),
playlist::Error::PlaylistNotFound => APIError::PlaylistNotFound,
playlist::Error::UserNotFound => APIError::UserNotFound,
playlist::Error::Vfs(e) => e.into(),
}
}
}
impl From<settings::Error> for APIError { app::Error::UpdateQueryFailed(s) => APIError::DdnsUpdateQueryFailed(s),
fn from(error: settings::Error) -> APIError { app::Error::UpdateQueryTransport => APIError::DdnsUpdateQueryFailed(0),
match error {
settings::Error::AuthenticationSecretNotFound => APIError::Settings(error),
settings::Error::DatabaseConnection(e) => e.into(),
settings::Error::AuthenticationSecretInvalid => APIError::Settings(error),
settings::Error::MiscSettingsNotFound => APIError::Settings(error),
settings::Error::IndexAlbumArtPatternInvalid => APIError::Settings(error),
settings::Error::Database(e) => APIError::Database(e),
}
}
}
impl From<user::Error> for APIError { app::Error::AuthenticationSecretNotFound => APIError::Internal,
fn from(error: user::Error) -> APIError { app::Error::AuthenticationSecretInvalid => APIError::Internal,
match error { app::Error::MiscSettingsNotFound => APIError::Internal,
user::Error::AuthorizationTokenEncoding => APIError::AuthorizationTokenEncoding, app::Error::IndexAlbumArtPatternInvalid => APIError::Internal,
user::Error::BrancaTokenEncoding => APIError::BrancaTokenEncoding,
user::Error::Database(e) => APIError::Database(e),
user::Error::DatabaseConnection(e) => e.into(),
user::Error::EmptyPassword => APIError::EmptyPassword,
user::Error::EmptyUsername => APIError::EmptyUsername,
user::Error::IncorrectAuthorizationScope => APIError::IncorrectCredentials,
user::Error::IncorrectPassword => APIError::IncorrectCredentials,
user::Error::IncorrectUsername => APIError::IncorrectCredentials,
user::Error::InvalidAuthToken => APIError::IncorrectCredentials,
user::Error::MissingLastFMSessionKey => APIError::IncorrectCredentials,
user::Error::PasswordHashing => APIError::PasswordHashing,
}
}
}
impl From<vfs::Error> for APIError { app::Error::Toml(_) => APIError::Internal,
fn from(error: vfs::Error) -> APIError { app::Error::IndexDeserializationError => APIError::Internal,
match error { app::Error::IndexSerializationError => APIError::Internal,
vfs::Error::CouldNotMapToRealPath(_) => APIError::VFSPathNotFound,
vfs::Error::Database(e) => APIError::Database(e),
vfs::Error::DatabaseConnection(e) => e.into(),
}
}
}
impl From<ddns::Error> for APIError { app::Error::CouldNotMapToRealPath(_) => APIError::VFSPathNotFound,
fn from(error: ddns::Error) -> APIError { app::Error::UserNotFound => APIError::UserNotFound,
match error { app::Error::DirectoryNotFound(d) => APIError::DirectoryNotFound(d),
ddns::Error::Database(e) => APIError::Database(e), app::Error::ArtistNotFound => APIError::ArtistNotFound,
ddns::Error::DatabaseConnection(e) => e.into(), app::Error::AlbumNotFound => APIError::AlbumNotFound,
ddns::Error::UpdateQueryFailed(s) => APIError::DdnsUpdateQueryFailed(s), app::Error::SongNotFound => APIError::SongNotFound,
ddns::Error::UpdateQueryTransport => APIError::DdnsUpdateQueryFailed(0), app::Error::PlaylistNotFound => APIError::PlaylistNotFound,
} app::Error::EmbeddedArtworkNotFound(_) => APIError::EmbeddedArtworkNotFound,
}
}
impl From<db::Error> for APIError { app::Error::EmptyUsername => APIError::EmptyUsername,
fn from(error: db::Error) -> APIError { app::Error::EmptyPassword => APIError::EmptyPassword,
match error { app::Error::IncorrectUsername => APIError::IncorrectCredentials,
db::Error::ConnectionPoolBuild => APIError::Internal, app::Error::IncorrectPassword => APIError::IncorrectCredentials,
db::Error::ConnectionPool => APIError::Internal, app::Error::InvalidAuthToken => APIError::IncorrectCredentials,
db::Error::Io(p, e) => APIError::Io(p, e), app::Error::IncorrectAuthorizationScope => APIError::IncorrectCredentials,
db::Error::Migration(_) => APIError::Internal, app::Error::MissingLastFMSessionKey => APIError::IncorrectCredentials,
} app::Error::PasswordHashing => APIError::PasswordHashing,
} app::Error::AuthorizationTokenEncoding => APIError::AuthorizationTokenEncoding,
} app::Error::BrancaTokenEncoding => APIError::BrancaTokenEncoding,
impl From<lastfm::Error> for APIError { app::Error::ScrobblerAuthentication(e) => APIError::LastFMScrobblerAuthentication(e),
fn from(error: lastfm::Error) -> APIError { app::Error::Scrobble(e) => APIError::LastFMScrobble(e),
match error { app::Error::NowPlaying(e) => APIError::LastFMNowPlaying(e),
lastfm::Error::ScrobblerAuthentication(e) => APIError::LastFMScrobblerAuthentication(e),
lastfm::Error::Scrobble(e) => APIError::LastFMScrobble(e),
lastfm::Error::NowPlaying(e) => APIError::LastFMNowPlaying(e),
lastfm::Error::Query(e) => e.into(),
lastfm::Error::User(e) => e.into(),
}
}
}
impl From<thumbnail::Error> for APIError {
fn from(error: thumbnail::Error) -> APIError {
match error {
thumbnail::Error::EmbeddedArtworkNotFound(_) => APIError::EmbeddedArtworkNotFound,
thumbnail::Error::Id3(p, e) => APIError::ThumbnailId3Decoding(p, e),
thumbnail::Error::Image(p, e) => APIError::ThumbnailImageDecoding(p, e),
thumbnail::Error::Io(p, e) => APIError::Io(p, e),
thumbnail::Error::Metaflac(p, e) => APIError::ThumbnailFlacDecoding(p, e),
thumbnail::Error::Mp4aMeta(p, e) => APIError::ThumbnailMp4Decoding(p, e),
thumbnail::Error::UnsupportedFormat(f) => APIError::UnsupportedThumbnailFormat(f),
} }
} }
} }