Error types consolidation
This commit is contained in:
parent
8f2566f574
commit
cd45836924
16 changed files with 185 additions and 350 deletions
102
src/app.rs
102
src/app.rs
|
@ -1,7 +1,7 @@
|
|||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::db::{self, DB};
|
||||
use crate::db::DB;
|
||||
use crate::paths::Paths;
|
||||
|
||||
pub mod config;
|
||||
|
@ -22,15 +22,105 @@ pub mod test;
|
|||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
Collection(#[from] index::Error),
|
||||
ThreadPoolBuilder(#[from] rayon::ThreadPoolBuildError),
|
||||
#[error(transparent)]
|
||||
Config(#[from] config::Error),
|
||||
#[error(transparent)]
|
||||
Database(#[from] db::Error),
|
||||
ThreadJoining(#[from] tokio::task::JoinError),
|
||||
|
||||
#[error("Filesystem error for `{0}`: `{1}`")]
|
||||
Io(PathBuf, std::io::Error),
|
||||
#[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)]
|
||||
|
|
|
@ -1,24 +1,7 @@
|
|||
use serde::Deserialize;
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{io::Read, path::Path};
|
||||
|
||||
use crate::app::{ddns, settings, user, vfs};
|
||||
|
||||
#[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),
|
||||
}
|
||||
use crate::app::{ddns, settings, user, vfs, Error};
|
||||
|
||||
#[derive(Default, Deserialize)]
|
||||
pub struct Config {
|
||||
|
|
|
@ -3,22 +3,11 @@ use log::{debug, error};
|
|||
use serde::{Deserialize, Serialize};
|
||||
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/";
|
||||
|
||||
#[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)]
|
||||
pub struct Config {
|
||||
pub ddns_host: String,
|
||||
|
|
|
@ -2,31 +2,12 @@ use id3::TagLike;
|
|||
use lewton::inside_ogg::OggStreamReader;
|
||||
use log::error;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::app::Error;
|
||||
use crate::utils;
|
||||
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)]
|
||||
pub struct SongMetadata {
|
||||
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> {
|
||||
let tag = id3::Tag::read_from_path(path).or_else(|error| {
|
||||
if let Some(tag) = error.partial_tag {
|
||||
Ok(tag)
|
||||
} else {
|
||||
Err(error)
|
||||
}
|
||||
})?;
|
||||
let tag = id3::Tag::read_from_path(&path)
|
||||
.or_else(|error| {
|
||||
if let Some(tag) = error.partial_tag {
|
||||
Ok(tag)
|
||||
} else {
|
||||
Err(error)
|
||||
}
|
||||
})
|
||||
.map_err(|e| Error::Id3(path.as_ref().to_owned(), e))?;
|
||||
|
||||
let artists = tag.get_text_values("TPE1");
|
||||
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> {
|
||||
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
|
||||
.vorbis_comments()
|
||||
.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> {
|
||||
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");
|
||||
|
||||
Ok(SongMetadata {
|
||||
|
|
|
@ -7,9 +7,8 @@ use log::{error, info};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use tokio::task::spawn_blocking;
|
||||
|
||||
use crate::app::scanner;
|
||||
use crate::app::vfs;
|
||||
use crate::db::{self, DB};
|
||||
use crate::app::{scanner, Error};
|
||||
use crate::db::DB;
|
||||
|
||||
mod browser;
|
||||
mod collection;
|
||||
|
@ -18,32 +17,6 @@ mod search;
|
|||
pub use browser::File;
|
||||
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)]
|
||||
pub struct Manager {
|
||||
db: DB,
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
use serde::{Deserialize, Serialize};
|
||||
use trie_rs::{Trie, TrieBuilder};
|
||||
|
||||
use crate::app::{index::Error, scanner};
|
||||
use crate::app::{scanner, Error};
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum File {
|
||||
|
|
|
@ -2,25 +2,11 @@ use rustfm_scrobble::{Scrobble, Scrobbler};
|
|||
use std::path::Path;
|
||||
use user::AuthToken;
|
||||
|
||||
use crate::app::{index, user};
|
||||
use crate::app::{index, user, Error};
|
||||
|
||||
const LASTFM_API_KEY: &str = "02b96c939a2b451c31dfd67add1f696e";
|
||||
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)]
|
||||
pub struct Manager {
|
||||
index_manager: index::Manager,
|
||||
|
|
|
@ -2,22 +2,8 @@ use core::clone::Clone;
|
|||
use sqlx::{Acquire, QueryBuilder, Sqlite};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::app::vfs;
|
||||
use crate::db::{self, 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),
|
||||
}
|
||||
use crate::app::{vfs, Error};
|
||||
use crate::db::DB;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Manager {
|
||||
|
@ -191,7 +177,7 @@ impl Manager {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::app::test;
|
||||
use crate::test_name;
|
||||
|
|
|
@ -11,7 +11,7 @@ use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
|
|||
use tokio::sync::Notify;
|
||||
use tokio::time::Instant;
|
||||
|
||||
use crate::app::{formats, index, settings, vfs};
|
||||
use crate::app::{formats, index, settings, vfs, Error};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Directory {
|
||||
|
@ -53,7 +53,7 @@ impl Scanner {
|
|||
index_manager: index::Manager,
|
||||
settings_manager: settings::Manager,
|
||||
vfs_manager: vfs::Manager,
|
||||
) -> Result<Self, index::Error> {
|
||||
) -> Result<Self, Error> {
|
||||
let scanner = Self {
|
||||
index_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();
|
||||
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 roots = vfs.mounts().clone();
|
||||
|
||||
|
|
|
@ -2,23 +2,8 @@ use regex::Regex;
|
|||
use serde::Deserialize;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::db::{self, 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),
|
||||
}
|
||||
use crate::app::Error;
|
||||
use crate::db::DB;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct AuthSecret {
|
||||
|
|
|
@ -6,26 +6,9 @@ use std::fs::{self, File};
|
|||
use std::hash::{Hash, Hasher};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::app::Error;
|
||||
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)]
|
||||
pub struct Options {
|
||||
pub max_dimension: Option<u32>,
|
||||
|
|
|
@ -5,35 +5,8 @@ use serde::{Deserialize, Serialize};
|
|||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use crate::app::settings::AuthSecret;
|
||||
use crate::db::{self, 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,
|
||||
}
|
||||
use crate::app::Error;
|
||||
use crate::db::DB;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct User {
|
||||
|
|
|
@ -4,17 +4,8 @@ use serde::{Deserialize, Serialize};
|
|||
use sqlx::{Acquire, QueryBuilder, Sqlite};
|
||||
use std::path::{self, Path, PathBuf};
|
||||
|
||||
use crate::db::{self, 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),
|
||||
}
|
||||
use crate::app::Error;
|
||||
use crate::db::DB;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
pub struct MountDir {
|
||||
|
|
16
src/db.rs
16
src/db.rs
|
@ -1,4 +1,4 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
|
||||
use sqlx::{
|
||||
migrate::Migrator,
|
||||
|
@ -7,19 +7,9 @@ use sqlx::{
|
|||
Sqlite,
|
||||
};
|
||||
|
||||
static MIGRATOR: Migrator = sqlx::migrate!("src/db");
|
||||
use crate::app::Error;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
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),
|
||||
}
|
||||
static MIGRATOR: Migrator = sqlx::migrate!("src/db");
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DB {
|
||||
|
|
|
@ -39,13 +39,11 @@ impl IntoResponse for APIError {
|
|||
APIError::OwnAdminPrivilegeRemoval => StatusCode::CONFLICT,
|
||||
APIError::PasswordHashing => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
APIError::PlaylistNotFound => StatusCode::NOT_FOUND,
|
||||
APIError::Settings(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
APIError::ThumbnailFlacDecoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
APIError::ThumbnailFileIOError => StatusCode::NOT_FOUND,
|
||||
APIError::ThumbnailId3Decoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
APIError::ThumbnailImageDecoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
APIError::ThumbnailMp4Decoding(_, _) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
APIError::TomlDeserialization(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
APIError::UnsupportedThumbnailFormat(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
APIError::UserNotFound => StatusCode::NOT_FOUND,
|
||||
APIError::VFSPathNotFound => StatusCode::NOT_FOUND,
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use std::path::PathBuf;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::app::{config, ddns, index, lastfm, playlist, settings, thumbnail, user, vfs};
|
||||
use crate::db;
|
||||
use crate::app;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum APIError {
|
||||
|
@ -66,8 +65,6 @@ pub enum APIError {
|
|||
PasswordHashing,
|
||||
#[error("Playlist not found")]
|
||||
PlaylistNotFound,
|
||||
#[error("Settings error:\n\n{0}")]
|
||||
Settings(settings::Error),
|
||||
#[error("Could not decode thumbnail from flac file `{0}`:\n\n{1}")]
|
||||
ThumbnailFlacDecoding(PathBuf, metaflac::Error),
|
||||
#[error("Thumbnail file could not be opened")]
|
||||
|
@ -78,8 +75,6 @@ pub enum APIError {
|
|||
ThumbnailImageDecoding(PathBuf, image::error::ImageError),
|
||||
#[error("Could not decode thumbnail from mp4 file `{0}`:\n\n{1}")]
|
||||
ThumbnailMp4Decoding(PathBuf, mp4ameta::Error),
|
||||
#[error("Toml deserialization error:\n\n{0}")]
|
||||
TomlDeserialization(toml::de::Error),
|
||||
#[error("Unsupported thumbnail format: `{0}`")]
|
||||
UnsupportedThumbnailFormat(&'static str),
|
||||
#[error("User not found")]
|
||||
|
@ -88,135 +83,63 @@ pub enum APIError {
|
|||
VFSPathNotFound,
|
||||
}
|
||||
|
||||
impl From<index::Error> for APIError {
|
||||
fn from(error: index::Error) -> APIError {
|
||||
impl From<app::Error> for APIError {
|
||||
fn from(error: app::Error) -> APIError {
|
||||
match error {
|
||||
index::Error::DirectoryNotFound(d) => APIError::DirectoryNotFound(d),
|
||||
index::Error::ArtistNotFound => APIError::ArtistNotFound,
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
app::Error::ThreadPoolBuilder(_) => APIError::Internal,
|
||||
app::Error::ThreadJoining(_) => APIError::Internal,
|
||||
|
||||
impl From<config::Error> for APIError {
|
||||
fn from(error: config::Error) -> APIError {
|
||||
match error {
|
||||
config::Error::Ddns(e) => e.into(),
|
||||
config::Error::Io(p, e) => APIError::Io(p, e),
|
||||
config::Error::Settings(e) => e.into(),
|
||||
config::Error::Toml(e) => APIError::TomlDeserialization(e),
|
||||
config::Error::User(e) => e.into(),
|
||||
config::Error::Vfs(e) => e.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
app::Error::Io(p, e) => APIError::Io(p, e),
|
||||
app::Error::Ape(_) => APIError::Internal,
|
||||
app::Error::Id3(p, e) => APIError::ThumbnailId3Decoding(p, e),
|
||||
app::Error::Metaflac(p, e) => APIError::ThumbnailFlacDecoding(p, e),
|
||||
app::Error::Mp4aMeta(p, e) => APIError::ThumbnailMp4Decoding(p, e),
|
||||
app::Error::Opus(_) => APIError::Internal,
|
||||
app::Error::Vorbis(_) => APIError::Internal,
|
||||
app::Error::VorbisCommentNotFoundInFlacFile => APIError::Internal,
|
||||
app::Error::Image(p, e) => APIError::ThumbnailImageDecoding(p, e),
|
||||
app::Error::UnsupportedFormat(f) => APIError::UnsupportedThumbnailFormat(f),
|
||||
|
||||
impl From<playlist::Error> for APIError {
|
||||
fn from(error: playlist::Error) -> APIError {
|
||||
match error {
|
||||
playlist::Error::Database(e) => APIError::Database(e),
|
||||
playlist::Error::DatabaseConnection(e) => e.into(),
|
||||
playlist::Error::PlaylistNotFound => APIError::PlaylistNotFound,
|
||||
playlist::Error::UserNotFound => APIError::UserNotFound,
|
||||
playlist::Error::Vfs(e) => e.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
app::Error::Database(e) => APIError::Database(e),
|
||||
app::Error::ConnectionPoolBuild => APIError::Internal,
|
||||
app::Error::ConnectionPool => APIError::Internal,
|
||||
app::Error::Migration(_) => APIError::Internal,
|
||||
|
||||
impl From<settings::Error> for APIError {
|
||||
fn from(error: settings::Error) -> APIError {
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
app::Error::UpdateQueryFailed(s) => APIError::DdnsUpdateQueryFailed(s),
|
||||
app::Error::UpdateQueryTransport => APIError::DdnsUpdateQueryFailed(0),
|
||||
|
||||
impl From<user::Error> for APIError {
|
||||
fn from(error: user::Error) -> APIError {
|
||||
match error {
|
||||
user::Error::AuthorizationTokenEncoding => APIError::AuthorizationTokenEncoding,
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
app::Error::AuthenticationSecretNotFound => APIError::Internal,
|
||||
app::Error::AuthenticationSecretInvalid => APIError::Internal,
|
||||
app::Error::MiscSettingsNotFound => APIError::Internal,
|
||||
app::Error::IndexAlbumArtPatternInvalid => APIError::Internal,
|
||||
|
||||
impl From<vfs::Error> for APIError {
|
||||
fn from(error: vfs::Error) -> APIError {
|
||||
match error {
|
||||
vfs::Error::CouldNotMapToRealPath(_) => APIError::VFSPathNotFound,
|
||||
vfs::Error::Database(e) => APIError::Database(e),
|
||||
vfs::Error::DatabaseConnection(e) => e.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
app::Error::Toml(_) => APIError::Internal,
|
||||
app::Error::IndexDeserializationError => APIError::Internal,
|
||||
app::Error::IndexSerializationError => APIError::Internal,
|
||||
|
||||
impl From<ddns::Error> for APIError {
|
||||
fn from(error: ddns::Error) -> APIError {
|
||||
match error {
|
||||
ddns::Error::Database(e) => APIError::Database(e),
|
||||
ddns::Error::DatabaseConnection(e) => e.into(),
|
||||
ddns::Error::UpdateQueryFailed(s) => APIError::DdnsUpdateQueryFailed(s),
|
||||
ddns::Error::UpdateQueryTransport => APIError::DdnsUpdateQueryFailed(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
app::Error::CouldNotMapToRealPath(_) => APIError::VFSPathNotFound,
|
||||
app::Error::UserNotFound => APIError::UserNotFound,
|
||||
app::Error::DirectoryNotFound(d) => APIError::DirectoryNotFound(d),
|
||||
app::Error::ArtistNotFound => APIError::ArtistNotFound,
|
||||
app::Error::AlbumNotFound => APIError::AlbumNotFound,
|
||||
app::Error::SongNotFound => APIError::SongNotFound,
|
||||
app::Error::PlaylistNotFound => APIError::PlaylistNotFound,
|
||||
app::Error::EmbeddedArtworkNotFound(_) => APIError::EmbeddedArtworkNotFound,
|
||||
|
||||
impl From<db::Error> for APIError {
|
||||
fn from(error: db::Error) -> APIError {
|
||||
match error {
|
||||
db::Error::ConnectionPoolBuild => APIError::Internal,
|
||||
db::Error::ConnectionPool => APIError::Internal,
|
||||
db::Error::Io(p, e) => APIError::Io(p, e),
|
||||
db::Error::Migration(_) => APIError::Internal,
|
||||
}
|
||||
}
|
||||
}
|
||||
app::Error::EmptyUsername => APIError::EmptyUsername,
|
||||
app::Error::EmptyPassword => APIError::EmptyPassword,
|
||||
app::Error::IncorrectUsername => APIError::IncorrectCredentials,
|
||||
app::Error::IncorrectPassword => APIError::IncorrectCredentials,
|
||||
app::Error::InvalidAuthToken => APIError::IncorrectCredentials,
|
||||
app::Error::IncorrectAuthorizationScope => APIError::IncorrectCredentials,
|
||||
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 {
|
||||
fn from(error: lastfm::Error) -> APIError {
|
||||
match error {
|
||||
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),
|
||||
app::Error::ScrobblerAuthentication(e) => APIError::LastFMScrobblerAuthentication(e),
|
||||
app::Error::Scrobble(e) => APIError::LastFMScrobble(e),
|
||||
app::Error::NowPlaying(e) => APIError::LastFMNowPlaying(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue