Modernized error handling
- Use error-chain instead of writing tons of boilerplate - Switched try!() macros to '?'
This commit is contained in:
parent
15505f8991
commit
ec8a8da81e
14 changed files with 249 additions and 317 deletions
57
Cargo.lock
generated
57
Cargo.lock
generated
|
@ -4,6 +4,7 @@ version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ape 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ape 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"app_dirs 1.1.1 (git+https://github.com/agersant/app-dirs-rs)",
|
"app_dirs 1.1.1 (git+https://github.com/agersant/app-dirs-rs)",
|
||||||
|
"error-chain 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"id3 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"id3 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -56,6 +57,29 @@ dependencies = [
|
||||||
"xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-demangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace-sys"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -88,6 +112,11 @@ name = "byteorder"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -112,6 +141,15 @@ dependencies = [
|
||||||
"url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dbghelp-sys"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deque"
|
name = "deque"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
|
@ -199,6 +237,14 @@ dependencies = [
|
||||||
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "error-chain"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -788,6 +834,11 @@ dependencies = [
|
||||||
"url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-serialize"
|
name = "rustc-serialize"
|
||||||
version = "0.3.21"
|
version = "0.3.21"
|
||||||
|
@ -1050,14 +1101,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
|
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
|
||||||
"checksum ape 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b419c2e36e91776200588f91e24c970d16d34236369136ca819f12dd903c5691"
|
"checksum ape 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b419c2e36e91776200588f91e24c970d16d34236369136ca819f12dd903c5691"
|
||||||
"checksum app_dirs 1.1.1 (git+https://github.com/agersant/app-dirs-rs)" = "<none>"
|
"checksum app_dirs 1.1.1 (git+https://github.com/agersant/app-dirs-rs)" = "<none>"
|
||||||
|
"checksum backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f551bc2ddd53aea015d453ef0b635af89444afa5ed2405dd0b2062ad5d600d80"
|
||||||
|
"checksum backtrace-sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3602e8d8c43336088a8505fa55cae2b3884a9be29440863a11528a42f46f6bb7"
|
||||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||||
"checksum bodyparser 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07b171b407e583dc8f01011a713f20575a81ac60acecf3b8153012709aeb1fd6"
|
"checksum bodyparser 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "07b171b407e583dc8f01011a713f20575a81ac60acecf3b8153012709aeb1fd6"
|
||||||
"checksum buf_redux 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "861b9d19b9f5cb40647242d10d0cb0a13de0a96d5ff8c8a01ea324fa3956eb7d"
|
"checksum buf_redux 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "861b9d19b9f5cb40647242d10d0cb0a13de0a96d5ff8c8a01ea324fa3956eb7d"
|
||||||
"checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304"
|
"checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304"
|
||||||
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
|
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
|
||||||
|
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
||||||
"checksum color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a475fc4af42d83d28adf72968d9bcfaf035a1a9381642d8e85d8a04957767b0d"
|
"checksum color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a475fc4af42d83d28adf72968d9bcfaf035a1a9381642d8e85d8a04957767b0d"
|
||||||
"checksum conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca30253581af809925ef68c2641cc140d6183f43e12e0af4992d53768bd7b8"
|
"checksum conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95ca30253581af809925ef68c2641cc140d6183f43e12e0af4992d53768bd7b8"
|
||||||
"checksum cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e3d6405328b6edb412158b3b7710e2634e23f3614b9bb1c412df7952489a626"
|
"checksum cookie 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e3d6405328b6edb412158b3b7710e2634e23f3614b9bb1c412df7952489a626"
|
||||||
|
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
|
||||||
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
|
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
|
||||||
"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d"
|
"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d"
|
||||||
"checksum encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
|
"checksum encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
|
||||||
|
@ -1069,6 +1124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
|
"checksum encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
|
||||||
"checksum enum_primitive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f79eff5be92a4d7d5bddf7daa7d650717ea71628634efe6ca7bcda85b2183c23"
|
"checksum enum_primitive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f79eff5be92a4d7d5bddf7daa7d650717ea71628634efe6ca7bcda85b2183c23"
|
||||||
"checksum error 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "a6e606f14042bb87cc02ef6a14db6c90ab92ed6f62d87e69377bc759fd7987cc"
|
"checksum error 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "a6e606f14042bb87cc02ef6a14db6c90ab92ed6f62d87e69377bc759fd7987cc"
|
||||||
|
"checksum error-chain 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1cd681735364a04cd5d69f01a4f6768e70473941f8d86d8c224faf6955a75799"
|
||||||
"checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb"
|
"checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb"
|
||||||
"checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
|
"checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
|
||||||
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
|
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
|
||||||
|
@ -1136,6 +1192,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
||||||
"checksum route-recognizer 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4f0a750d020adb1978f5964ea7bca830585899b09da7cbb3f04961fc2400122d"
|
"checksum route-recognizer 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4f0a750d020adb1978f5964ea7bca830585899b09da7cbb3f04961fc2400122d"
|
||||||
"checksum router 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b94397bfa5b772b4375be4da12560a7c1c1e74b2e35c46ed312958aad56df726"
|
"checksum router 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b94397bfa5b772b4375be4da12560a7c1c1e74b2e35c46ed312958aad56df726"
|
||||||
|
"checksum rustc-demangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1430d286cadb237c17c885e25447c982c97113926bb579f4379c0eca8d9586dc"
|
||||||
"checksum rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818"
|
"checksum rustc-serialize 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "bff9fc1c79f2dec76b253273d07682e94a978bd8f132ded071188122b2af9818"
|
||||||
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
|
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
|
||||||
"checksum scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef399c8893e8cb7aa9696e895427fab3a6bf265977bb96e126f24ddd2cda85a"
|
"checksum scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef399c8893e8cb7aa9696e895427fab3a6bf265977bb96e126f24ddd2cda85a"
|
||||||
|
|
|
@ -9,6 +9,7 @@ ui = []
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ape = "0.1.2"
|
ape = "0.1.2"
|
||||||
app_dirs = { git = "https://github.com/agersant/app-dirs-rs" }
|
app_dirs = { git = "https://github.com/agersant/app-dirs-rs" }
|
||||||
|
error-chain = "0.7.1"
|
||||||
getopts = "0.2.14"
|
getopts = "0.2.14"
|
||||||
hyper = "0.9.10"
|
hyper = "0.9.10"
|
||||||
id3 = "0.1.11"
|
id3 = "0.1.11"
|
||||||
|
|
58
src/api.rs
58
src/api.rs
|
@ -1,4 +1,3 @@
|
||||||
use core::str::Utf8Error;
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::*;
|
use std::path::*;
|
||||||
|
@ -15,7 +14,7 @@ use rustc_serialize::json;
|
||||||
use url::percent_encoding::percent_decode;
|
use url::percent_encoding::percent_decode;
|
||||||
|
|
||||||
use collection::*;
|
use collection::*;
|
||||||
use error::*;
|
use errors::*;
|
||||||
use thumbnails::*;
|
use thumbnails::*;
|
||||||
use utils::*;
|
use utils::*;
|
||||||
|
|
||||||
|
@ -37,27 +36,6 @@ impl Version {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PError> for IronError {
|
|
||||||
fn from(err: PError) -> IronError {
|
|
||||||
match err {
|
|
||||||
PError::Io(e) => IronError::new(e, status::NotFound),
|
|
||||||
PError::CannotClearExistingIndex => IronError::new(err, status::InternalServerError),
|
|
||||||
PError::PathDecoding => IronError::new(err, status::InternalServerError),
|
|
||||||
PError::ConfigDirectoryError => IronError::new(err, status::InternalServerError),
|
|
||||||
PError::CacheDirectoryError => IronError::new(err, status::InternalServerError),
|
|
||||||
PError::PathNotInVfs => IronError::new(err, status::NotFound),
|
|
||||||
PError::CannotServeDirectory => IronError::new(err, status::BadRequest),
|
|
||||||
PError::UnsupportedFileType => IronError::new(err, status::BadRequest),
|
|
||||||
PError::AlbumArtSearchError => IronError::new(err, status::InternalServerError),
|
|
||||||
PError::ImageProcessingError => IronError::new(err, status::InternalServerError),
|
|
||||||
PError::UnsupportedMetadataFormat => IronError::new(err, status::InternalServerError),
|
|
||||||
PError::MetadataDecodingError => IronError::new(err, status::InternalServerError),
|
|
||||||
PError::Unauthorized => IronError::new(err, status::Unauthorized),
|
|
||||||
PError::IncorrectCredentials => IronError::new(err, status::BadRequest),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_api_handler(collection: Arc<Collection>) -> Mount {
|
pub fn get_api_handler(collection: Arc<Collection>) -> Mount {
|
||||||
let mut api_handler = Mount::new();
|
let mut api_handler = Mount::new();
|
||||||
|
|
||||||
|
@ -97,20 +75,18 @@ pub fn get_api_handler(collection: Arc<Collection>) -> Mount {
|
||||||
api_handler
|
api_handler
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_from_request(request: &Request) -> Result<PathBuf, Utf8Error> {
|
fn path_from_request(request: &Request) -> Result<PathBuf> {
|
||||||
let path_string = request.url.path().join("\\");
|
let path_string = request.url.path().join("\\");
|
||||||
let decoded_path = try!(percent_decode(path_string.as_bytes()).decode_utf8());
|
let decoded_path = percent_decode(path_string.as_bytes()).decode_utf8()?;
|
||||||
Ok(PathBuf::from(decoded_path.deref()))
|
Ok(PathBuf::from(decoded_path.deref()))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AuthRequirement;
|
struct AuthRequirement;
|
||||||
impl BeforeMiddleware for AuthRequirement {
|
impl BeforeMiddleware for AuthRequirement {
|
||||||
fn before(&self, req: &mut Request) -> IronResult<()> {
|
fn before(&self, req: &mut Request) -> IronResult<()> {
|
||||||
let auth_cookie = req.get_cookie("username");
|
match req.get_cookie("username") {
|
||||||
if auth_cookie.is_some() {
|
Some(_) => Ok(()),
|
||||||
Ok(())
|
None => Err(Error::from(ErrorKind::AuthenticationRequired).into()),
|
||||||
} else {
|
|
||||||
Err(IronError::new(PError::Unauthorized, status::Unauthorized))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,13 +101,13 @@ fn version(_: &mut Request) -> IronResult<Response> {
|
||||||
|
|
||||||
fn auth(request: &mut Request, collection: &Collection) -> IronResult<Response> {
|
fn auth(request: &mut Request, collection: &Collection) -> IronResult<Response> {
|
||||||
let input = request.get_ref::<params::Params>().unwrap();
|
let input = request.get_ref::<params::Params>().unwrap();
|
||||||
let username = match input.find(&["username"]) {
|
let username = match input.find(&["username"]) {
|
||||||
Some(¶ms::Value::String(ref username)) => username,
|
Some(¶ms::Value::String(ref username)) => username,
|
||||||
_ => return Err(IronError::from(PError::IncorrectCredentials)),
|
_ => return Err(Error::from(ErrorKind::MissingUsername).into()),
|
||||||
};
|
};
|
||||||
let password = match input.find(&["password"]) {
|
let password = match input.find(&["password"]) {
|
||||||
Some(¶ms::Value::String(ref password)) => password,
|
Some(¶ms::Value::String(ref password)) => password,
|
||||||
_ => return Err(IronError::from(PError::IncorrectCredentials)),
|
_ => return Err(Error::from(ErrorKind::MissingPassword).into()),
|
||||||
};
|
};
|
||||||
if collection.auth(username.as_str(), password.as_str()) {
|
if collection.auth(username.as_str(), password.as_str()) {
|
||||||
let mut response = Response::with((status::Ok, ""));
|
let mut response = Response::with((status::Ok, ""));
|
||||||
|
@ -140,7 +116,7 @@ fn auth(request: &mut Request, collection: &Collection) -> IronResult<Response>
|
||||||
response.set_cookie(username_cookie);
|
response.set_cookie(username_cookie);
|
||||||
Ok(response)
|
Ok(response)
|
||||||
} else {
|
} else {
|
||||||
Err(IronError::from(PError::IncorrectCredentials))
|
Err(Error::from(ErrorKind::IncorrectCredentials).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +126,7 @@ fn browse(request: &mut Request, collection: &Collection) -> IronResult<Response
|
||||||
Err(e) => return Err(IronError::new(e, status::BadRequest)),
|
Err(e) => return Err(IronError::new(e, status::BadRequest)),
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
};
|
};
|
||||||
let browse_result = try!(collection.browse(&path));
|
let browse_result = collection.browse(&path)?;
|
||||||
|
|
||||||
let result_json = json::encode(&browse_result);
|
let result_json = json::encode(&browse_result);
|
||||||
let result_json = match result_json {
|
let result_json = match result_json {
|
||||||
|
@ -167,7 +143,7 @@ fn flatten(request: &mut Request, collection: &Collection) -> IronResult<Respons
|
||||||
Err(e) => return Err(IronError::new(e, status::BadRequest)),
|
Err(e) => return Err(IronError::new(e, status::BadRequest)),
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
};
|
};
|
||||||
let flatten_result = try!(collection.flatten(&path));
|
let flatten_result = collection.flatten(&path)?;
|
||||||
|
|
||||||
let result_json = json::encode(&flatten_result);
|
let result_json = json::encode(&flatten_result);
|
||||||
let result_json = match result_json {
|
let result_json = match result_json {
|
||||||
|
@ -204,7 +180,7 @@ fn serve(request: &mut Request, collection: &Collection) -> IronResult<Response>
|
||||||
};
|
};
|
||||||
|
|
||||||
if !metadata.is_file() {
|
if !metadata.is_file() {
|
||||||
return Err(IronError::from(PError::CannotServeDirectory));
|
return Err(Error::from(ErrorKind::CannotServeDirectory).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_song(real_path.as_path()) {
|
if is_song(real_path.as_path()) {
|
||||||
|
@ -215,7 +191,7 @@ fn serve(request: &mut Request, collection: &Collection) -> IronResult<Response>
|
||||||
return art(request, real_path.as_path());
|
return art(request, real_path.as_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(IronError::from(PError::UnsupportedFileType))
|
Err(Error::from(ErrorKind::UnsupportedFileType).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn art(_: &mut Request, real_path: &Path) -> IronResult<Response> {
|
fn art(_: &mut Request, real_path: &Path) -> IronResult<Response> {
|
||||||
|
|
|
@ -4,9 +4,9 @@ use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
|
use errors::*;
|
||||||
use index::*;
|
use index::*;
|
||||||
use vfs::*;
|
use vfs::*;
|
||||||
use error::*;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -39,7 +39,7 @@ impl Collection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_config(&mut self, config: &Config) -> Result<(), PError> {
|
pub fn load_config(&mut self, config: &Config) -> Result<()> {
|
||||||
self.users = config.users.to_vec();
|
self.users = config.users.to_vec();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -48,15 +48,15 @@ impl Collection {
|
||||||
self.users.iter().any(|u| u.name == username && u.password == password)
|
self.users.iter().any(|u| u.name == username && u.password == password)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn browse(&self, virtual_path: &Path) -> Result<Vec<CollectionFile>, PError> {
|
pub fn browse(&self, virtual_path: &Path) -> Result<Vec<CollectionFile>> {
|
||||||
self.index.deref().browse(virtual_path)
|
self.index.deref().browse(virtual_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flatten(&self, virtual_path: &Path) -> Result<Vec<Song>, PError> {
|
pub fn flatten(&self, virtual_path: &Path) -> Result<Vec<Song>> {
|
||||||
self.index.deref().flatten(virtual_path)
|
self.index.deref().flatten(virtual_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn locate(&self, virtual_path: &Path) -> Result<PathBuf, PError> {
|
pub fn locate(&self, virtual_path: &Path) -> Result<PathBuf> {
|
||||||
self.vfs.virtual_to_real(virtual_path)
|
self.vfs.virtual_to_real(virtual_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
160
src/config.rs
160
src/config.rs
|
@ -1,12 +1,12 @@
|
||||||
use regex;
|
use regex;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path;
|
use std::path;
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
use collection::User;
|
use collection::User;
|
||||||
use ddns::DDNSConfig;
|
use ddns::DDNSConfig;
|
||||||
|
use errors::*;
|
||||||
use index::IndexConfig;
|
use index::IndexConfig;
|
||||||
use utils;
|
use utils;
|
||||||
use vfs::VfsConfig;
|
use vfs::VfsConfig;
|
||||||
|
@ -27,34 +27,6 @@ const CONFIG_DDNS_HOST: &'static str = "host";
|
||||||
const CONFIG_DDNS_USERNAME: &'static str = "username";
|
const CONFIG_DDNS_USERNAME: &'static str = "username";
|
||||||
const CONFIG_DDNS_PASSWORD: &'static str = "password";
|
const CONFIG_DDNS_PASSWORD: &'static str = "password";
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ConfigError {
|
|
||||||
IoError(io::Error),
|
|
||||||
CacheDirectoryError,
|
|
||||||
ConfigDirectoryError,
|
|
||||||
TOMLParseError,
|
|
||||||
RegexError(regex::Error),
|
|
||||||
SecretParseError,
|
|
||||||
SleepDurationParseError,
|
|
||||||
AlbumArtPatternParseError,
|
|
||||||
UsersParseError,
|
|
||||||
MountDirsParseError,
|
|
||||||
DDNSParseError,
|
|
||||||
ConflictingMounts,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<io::Error> for ConfigError {
|
|
||||||
fn from(err: io::Error) -> ConfigError {
|
|
||||||
ConfigError::IoError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<regex::Error> for ConfigError {
|
|
||||||
fn from(err: regex::Error) -> ConfigError {
|
|
||||||
ConfigError::RegexError(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub secret: String,
|
pub secret: String,
|
||||||
pub vfs: VfsConfig,
|
pub vfs: VfsConfig,
|
||||||
|
@ -64,26 +36,23 @@ pub struct Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn parse(custom_path: Option<path::PathBuf>) -> Result<Config, ConfigError> {
|
pub fn parse(custom_path: Option<path::PathBuf>) -> Result<Config> {
|
||||||
|
|
||||||
let config_path = match custom_path {
|
let config_path = match custom_path {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => {
|
None => {
|
||||||
let mut root = match utils::get_config_root() {
|
let mut root = utils::get_config_root()?;
|
||||||
Ok(r) => r,
|
|
||||||
Err(_) => return Err(ConfigError::ConfigDirectoryError),
|
|
||||||
};
|
|
||||||
root.push(DEFAULT_CONFIG_FILE_NAME);
|
root.push(DEFAULT_CONFIG_FILE_NAME);
|
||||||
root
|
root
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
println!("Loading config from: {}", config_path.to_string_lossy());
|
println!("Loading config from: {}", config_path.to_string_lossy());
|
||||||
|
|
||||||
let mut config_file = try!(fs::File::open(config_path));
|
let mut config_file = fs::File::open(config_path)?;
|
||||||
let mut config_file_content = String::new();
|
let mut config_file_content = String::new();
|
||||||
try!(config_file.read_to_string(&mut config_file_content));
|
config_file.read_to_string(&mut config_file_content)?;
|
||||||
let parsed_config = toml::Parser::new(config_file_content.as_str()).parse();
|
let parsed_config = toml::Parser::new(config_file_content.as_str()).parse();
|
||||||
let parsed_config = try!(parsed_config.ok_or(ConfigError::TOMLParseError));
|
let parsed_config = parsed_config.ok_or("Could not parse config as valid TOML")?;
|
||||||
|
|
||||||
let mut config = Config {
|
let mut config = Config {
|
||||||
secret: String::new(),
|
secret: String::new(),
|
||||||
|
@ -93,57 +62,55 @@ impl Config {
|
||||||
ddns: None,
|
ddns: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
try!(config.parse_secret(&parsed_config));
|
config.parse_secret(&parsed_config)?;
|
||||||
try!(config.parse_index_sleep_duration(&parsed_config));
|
config.parse_index_sleep_duration(&parsed_config)?;
|
||||||
try!(config.parse_mount_points(&parsed_config));
|
config.parse_mount_points(&parsed_config)?;
|
||||||
try!(config.parse_users(&parsed_config));
|
config.parse_users(&parsed_config)?;
|
||||||
try!(config.parse_album_art_pattern(&parsed_config));
|
config.parse_album_art_pattern(&parsed_config)?;
|
||||||
try!(config.parse_ddns(&parsed_config));
|
config.parse_ddns(&parsed_config)?;
|
||||||
|
|
||||||
let mut index_path = match utils::get_cache_root() {
|
let mut index_path = utils::get_cache_root()?;
|
||||||
Err(_) => return Err(ConfigError::CacheDirectoryError),
|
|
||||||
Ok(p) => p,
|
|
||||||
};
|
|
||||||
index_path.push(INDEX_FILE_NAME);
|
index_path.push(INDEX_FILE_NAME);
|
||||||
config.index.path = index_path;
|
config.index.path = index_path;
|
||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_secret(&mut self, source: &toml::Table) -> Result<(), ConfigError> {
|
fn parse_secret(&mut self, source: &toml::Table) -> Result<()> {
|
||||||
let secret = try!(source.get(CONFIG_SECRET).ok_or(ConfigError::SecretParseError));
|
self.secret = source.get(CONFIG_SECRET)
|
||||||
let secret = try!(secret.as_str().ok_or(ConfigError::SecretParseError));
|
.and_then(|s| s.as_str())
|
||||||
self.secret = secret.to_owned();
|
.map(|s| s.to_owned())
|
||||||
|
.ok_or("Could not parse config secret")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_index_sleep_duration(&mut self, source: &toml::Table) -> Result<(), ConfigError> {
|
fn parse_index_sleep_duration(&mut self, source: &toml::Table) -> Result<()> {
|
||||||
let sleep_duration = match source.get(CONFIG_INDEX_SLEEP_DURATION) {
|
let sleep_duration = match source.get(CONFIG_INDEX_SLEEP_DURATION) {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
let sleep_duration = match sleep_duration {
|
let sleep_duration = match sleep_duration {
|
||||||
&toml::Value::Integer(s) => s as u64,
|
&toml::Value::Integer(s) => s as u64,
|
||||||
_ => return Err(ConfigError::SleepDurationParseError),
|
_ => bail!("Could not parse index sleep duration"),
|
||||||
};
|
};
|
||||||
self.index.sleep_duration = sleep_duration;
|
self.index.sleep_duration = sleep_duration;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_album_art_pattern(&mut self, source: &toml::Table) -> Result<(), ConfigError> {
|
fn parse_album_art_pattern(&mut self, source: &toml::Table) -> Result<()> {
|
||||||
let pattern = match source.get(CONFIG_ALBUM_ART_PATTERN) {
|
let pattern = match source.get(CONFIG_ALBUM_ART_PATTERN) {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
let pattern = match pattern {
|
let pattern = match pattern {
|
||||||
&toml::Value::String(ref s) => s,
|
&toml::Value::String(ref s) => s,
|
||||||
_ => return Err(ConfigError::AlbumArtPatternParseError),
|
_ => bail!("Could not parse album art pattern"),
|
||||||
};
|
};
|
||||||
self.index.album_art_pattern = Some(try!(regex::Regex::new(pattern)));
|
self.index.album_art_pattern = Some(regex::Regex::new(pattern)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_users(&mut self, source: &toml::Table) -> Result<(), ConfigError> {
|
fn parse_users(&mut self, source: &toml::Table) -> Result<()> {
|
||||||
let users = match source.get(CONFIG_USERS) {
|
let users = match source.get(CONFIG_USERS) {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
|
@ -151,28 +118,16 @@ impl Config {
|
||||||
|
|
||||||
let users = match users {
|
let users = match users {
|
||||||
&toml::Value::Array(ref a) => a,
|
&toml::Value::Array(ref a) => a,
|
||||||
_ => return Err(ConfigError::UsersParseError),
|
_ => bail!("Could not parse users array"),
|
||||||
};
|
};
|
||||||
|
|
||||||
for user in users {
|
for user in users {
|
||||||
let name = match user.lookup(CONFIG_USER_NAME) {
|
let name = user.lookup(CONFIG_USER_NAME)
|
||||||
None => return Err(ConfigError::UsersParseError),
|
.and_then(|n| n.as_str())
|
||||||
Some(n) => n,
|
.ok_or("Could not parse username")?;
|
||||||
};
|
let password = user.lookup(CONFIG_USER_PASSWORD)
|
||||||
let name = match name.as_str() {
|
.and_then(|n| n.as_str())
|
||||||
None => return Err(ConfigError::UsersParseError),
|
.ok_or("Could not parse user password")?;
|
||||||
Some(n) => n,
|
|
||||||
};
|
|
||||||
|
|
||||||
let password = match user.lookup(CONFIG_USER_PASSWORD) {
|
|
||||||
None => return Err(ConfigError::UsersParseError),
|
|
||||||
Some(n) => n,
|
|
||||||
};
|
|
||||||
let password = match password.as_str() {
|
|
||||||
None => return Err(ConfigError::UsersParseError),
|
|
||||||
Some(n) => n,
|
|
||||||
};
|
|
||||||
|
|
||||||
let user = User::new(name.to_owned(), password.to_owned());
|
let user = User::new(name.to_owned(), password.to_owned());
|
||||||
self.users.push(user);
|
self.users.push(user);
|
||||||
}
|
}
|
||||||
|
@ -180,7 +135,7 @@ impl Config {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_mount_points(&mut self, source: &toml::Table) -> Result<(), ConfigError> {
|
fn parse_mount_points(&mut self, source: &toml::Table) -> Result<()> {
|
||||||
let mount_dirs = match source.get(CONFIG_MOUNT_DIRS) {
|
let mount_dirs = match source.get(CONFIG_MOUNT_DIRS) {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
|
@ -188,31 +143,19 @@ impl Config {
|
||||||
|
|
||||||
let mount_dirs = match mount_dirs {
|
let mount_dirs = match mount_dirs {
|
||||||
&toml::Value::Array(ref a) => a,
|
&toml::Value::Array(ref a) => a,
|
||||||
_ => return Err(ConfigError::MountDirsParseError),
|
_ => bail!("Could not parse mount directories array"),
|
||||||
};
|
};
|
||||||
|
|
||||||
for dir in mount_dirs {
|
for dir in mount_dirs {
|
||||||
let name = match dir.lookup(CONFIG_MOUNT_DIR_NAME) {
|
let name = dir.lookup(CONFIG_MOUNT_DIR_NAME)
|
||||||
None => return Err(ConfigError::MountDirsParseError),
|
.and_then(|n| n.as_str())
|
||||||
Some(n) => n,
|
.ok_or("Could not parse mount directory name")?;
|
||||||
};
|
let source = dir.lookup(CONFIG_MOUNT_DIR_SOURCE)
|
||||||
let name = match name.as_str() {
|
.and_then(|n| n.as_str())
|
||||||
None => return Err(ConfigError::MountDirsParseError),
|
.ok_or("Could not parse mount directory source")?;
|
||||||
Some(n) => n,
|
|
||||||
};
|
|
||||||
|
|
||||||
let source = match dir.lookup(CONFIG_MOUNT_DIR_SOURCE) {
|
|
||||||
None => return Err(ConfigError::MountDirsParseError),
|
|
||||||
Some(n) => n,
|
|
||||||
};
|
|
||||||
let source = match source.as_str() {
|
|
||||||
None => return Err(ConfigError::MountDirsParseError),
|
|
||||||
Some(n) => n,
|
|
||||||
};
|
|
||||||
let source = clean_path_string(source);
|
let source = clean_path_string(source);
|
||||||
|
|
||||||
if self.vfs.mount_points.contains_key(name) {
|
if self.vfs.mount_points.contains_key(name) {
|
||||||
return Err(ConfigError::ConflictingMounts);
|
bail!("Conflicting mount directories");
|
||||||
}
|
}
|
||||||
self.vfs.mount_points.insert(name.to_owned(), source);
|
self.vfs.mount_points.insert(name.to_owned(), source);
|
||||||
}
|
}
|
||||||
|
@ -220,25 +163,24 @@ impl Config {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ddns(&mut self, source: &toml::Table) -> Result<(), ConfigError> {
|
fn parse_ddns(&mut self, source: &toml::Table) -> Result<()> {
|
||||||
let ddns = match source.get(CONFIG_DDNS) {
|
let ddns = match source.get(CONFIG_DDNS) {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
let ddns = match ddns {
|
let ddns = match ddns {
|
||||||
&toml::Value::Table(ref a) => a,
|
&toml::Value::Table(ref a) => a,
|
||||||
_ => return Err(ConfigError::DDNSParseError),
|
_ => bail!("Could not parse DDNS settings table"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let host = try!(ddns.get(CONFIG_DDNS_HOST).ok_or(ConfigError::DDNSParseError)).as_str();
|
let host =
|
||||||
let username = try!(ddns.get(CONFIG_DDNS_USERNAME).ok_or(ConfigError::DDNSParseError))
|
ddns.get(CONFIG_DDNS_HOST).and_then(|n| n.as_str()).ok_or("Could not parse DDNS host")?;
|
||||||
.as_str();
|
let username = ddns.get(CONFIG_DDNS_USERNAME)
|
||||||
let password = try!(ddns.get(CONFIG_DDNS_PASSWORD).ok_or(ConfigError::DDNSParseError))
|
.and_then(|n| n.as_str())
|
||||||
.as_str();
|
.ok_or("Could not parse DDNS username")?;
|
||||||
|
let password = ddns.get(CONFIG_DDNS_PASSWORD)
|
||||||
let host = try!(host.ok_or(ConfigError::DDNSParseError));
|
.and_then(|n| n.as_str())
|
||||||
let username = try!(username.ok_or(ConfigError::DDNSParseError));
|
.ok_or("Could not parse DDNS password")?;
|
||||||
let password = try!(password.ok_or(ConfigError::DDNSParseError));
|
|
||||||
|
|
||||||
self.ddns = Some(DDNSConfig {
|
self.ddns = Some(DDNSConfig {
|
||||||
host: host.to_owned(),
|
host: host.to_owned(),
|
||||||
|
|
|
@ -37,9 +37,9 @@ const DDNS_UPDATE_URL: &'static str = "http://ydns.io/api/v1/update/";
|
||||||
|
|
||||||
fn get_my_ip() -> Result<String, DDNSError> {
|
fn get_my_ip() -> Result<String, DDNSError> {
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
let mut res = try!(client.get(MY_IP_API_URL).send());
|
let mut res = client.get(MY_IP_API_URL).send()?;
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
try!(res.read_to_string(&mut buf));
|
res.read_to_string(&mut buf)?;
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ fn update_my_ip(ip: &String, config: &DDNSConfig) -> Result<(), DDNSError> {
|
||||||
password: Some(config.password.to_owned()),
|
password: Some(config.password.to_owned()),
|
||||||
});
|
});
|
||||||
|
|
||||||
let res = try!(client.get(full_url.as_str()).header(auth_header).send());
|
let res = client.get(full_url.as_str()).header(auth_header).send()?;
|
||||||
match res.status {
|
match res.status {
|
||||||
hyper::status::StatusCode::Ok => Ok(()),
|
hyper::status::StatusCode::Ok => Ok(()),
|
||||||
s => Err(DDNSError::UpdateError(s)),
|
s => Err(DDNSError::UpdateError(s)),
|
||||||
|
|
111
src/error.rs
111
src/error.rs
|
@ -1,111 +0,0 @@
|
||||||
use ape;
|
|
||||||
use std::error;
|
|
||||||
use std::fmt;
|
|
||||||
use std::io;
|
|
||||||
use id3;
|
|
||||||
use image;
|
|
||||||
use lewton;
|
|
||||||
use metaflac;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum PError {
|
|
||||||
CannotClearExistingIndex,
|
|
||||||
PathDecoding,
|
|
||||||
Io(io::Error),
|
|
||||||
CacheDirectoryError,
|
|
||||||
ConfigDirectoryError,
|
|
||||||
PathNotInVfs,
|
|
||||||
CannotServeDirectory,
|
|
||||||
UnsupportedFileType,
|
|
||||||
AlbumArtSearchError,
|
|
||||||
ImageProcessingError,
|
|
||||||
UnsupportedMetadataFormat,
|
|
||||||
MetadataDecodingError,
|
|
||||||
Unauthorized,
|
|
||||||
IncorrectCredentials,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ape::Error> for PError {
|
|
||||||
fn from(_: ape::Error) -> PError {
|
|
||||||
PError::MetadataDecodingError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<io::Error> for PError {
|
|
||||||
fn from(err: io::Error) -> PError {
|
|
||||||
PError::Io(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<id3::Error> for PError {
|
|
||||||
fn from(_: id3::Error) -> PError {
|
|
||||||
PError::MetadataDecodingError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<image::ImageError> for PError {
|
|
||||||
fn from(_: image::ImageError) -> PError {
|
|
||||||
PError::ImageProcessingError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<lewton::VorbisError> for PError {
|
|
||||||
fn from(_: lewton::VorbisError) -> PError {
|
|
||||||
PError::MetadataDecodingError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<metaflac::Error> for PError {
|
|
||||||
fn from(_: metaflac::Error) -> PError {
|
|
||||||
PError::MetadataDecodingError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for PError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
PError::Io(ref err) => err.description(),
|
|
||||||
PError::CannotClearExistingIndex => "Error while removing existing index",
|
|
||||||
PError::PathDecoding => "Error while decoding a Path as a UTF-8 string",
|
|
||||||
PError::CacheDirectoryError => "Could not access the cache directory",
|
|
||||||
PError::ConfigDirectoryError => "Could not access the config directory",
|
|
||||||
PError::PathNotInVfs => "Requested path does not index a mount point",
|
|
||||||
PError::CannotServeDirectory => "Only individual files can be served",
|
|
||||||
PError::UnsupportedFileType => "Unrecognized extension",
|
|
||||||
PError::AlbumArtSearchError => "Error while looking for album art",
|
|
||||||
PError::ImageProcessingError => "Error while processing image",
|
|
||||||
PError::UnsupportedMetadataFormat => "Unsupported metadata format",
|
|
||||||
PError::MetadataDecodingError => "Error while reading song metadata",
|
|
||||||
PError::Unauthorized => "Authentication required",
|
|
||||||
PError::IncorrectCredentials => "Incorrect username/password combination",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cause(&self) -> Option<&error::Error> {
|
|
||||||
match *self {
|
|
||||||
PError::Io(ref err) => Some(err),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for PError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
PError::Io(ref err) => write!(f, "IO error: {}", err),
|
|
||||||
PError::CannotClearExistingIndex => write!(f, "Error while removing existing index"),
|
|
||||||
PError::PathDecoding => write!(f, "Path decoding error"),
|
|
||||||
PError::CacheDirectoryError => write!(f, "Could not access the cache directory"),
|
|
||||||
PError::ConfigDirectoryError => write!(f, "Could not access the config directory"),
|
|
||||||
PError::PathNotInVfs => write!(f, "Requested path does not index a mount point"),
|
|
||||||
PError::CannotServeDirectory => write!(f, "Only individual files can be served"),
|
|
||||||
PError::UnsupportedFileType => write!(f, "Unrecognized extension"),
|
|
||||||
PError::AlbumArtSearchError => write!(f, "Error while looking for album art"),
|
|
||||||
PError::ImageProcessingError => write!(f, "Error while processing image"),
|
|
||||||
PError::UnsupportedMetadataFormat => write!(f, "Unsupported metadata format"),
|
|
||||||
PError::MetadataDecodingError => write!(f, "Error while reading song metadata"),
|
|
||||||
PError::Unauthorized => write!(f, "Authentication required"),
|
|
||||||
PError::IncorrectCredentials => write!(f, "Incorrect username/password combination"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
50
src/errors.rs
Normal file
50
src/errors.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use ape;
|
||||||
|
use core;
|
||||||
|
use id3;
|
||||||
|
use image;
|
||||||
|
use hyper;
|
||||||
|
use iron::IronError;
|
||||||
|
use iron::status::Status;
|
||||||
|
use lewton;
|
||||||
|
use metaflac;
|
||||||
|
use regex;
|
||||||
|
use std;
|
||||||
|
|
||||||
|
error_chain! {
|
||||||
|
foreign_links {
|
||||||
|
Ape(ape::Error);
|
||||||
|
Encoding(core::str::Utf8Error);
|
||||||
|
Flac(metaflac::Error);
|
||||||
|
Hyper(hyper::Error);
|
||||||
|
Id3(id3::Error);
|
||||||
|
Image(image::ImageError);
|
||||||
|
Io(std::io::Error);
|
||||||
|
Regex(regex::Error);
|
||||||
|
Vorbis(lewton::VorbisError);
|
||||||
|
}
|
||||||
|
|
||||||
|
errors {
|
||||||
|
AuthenticationRequired {}
|
||||||
|
MissingUsername {}
|
||||||
|
MissingPassword {}
|
||||||
|
IncorrectCredentials {}
|
||||||
|
CannotServeDirectory {}
|
||||||
|
UnsupportedFileType {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Error> for IronError {
|
||||||
|
fn from(err: Error) -> IronError {
|
||||||
|
match err {
|
||||||
|
e @ Error(ErrorKind::AuthenticationRequired, _) => {
|
||||||
|
IronError::new(e, Status::Unauthorized)
|
||||||
|
}
|
||||||
|
e @ Error(ErrorKind::MissingUsername, _) => IronError::new(e, Status::BadRequest),
|
||||||
|
e @ Error(ErrorKind::MissingPassword, _) => IronError::new(e, Status::BadRequest),
|
||||||
|
e @ Error(ErrorKind::IncorrectCredentials, _) => IronError::new(e, Status::BadRequest),
|
||||||
|
e @ Error(ErrorKind::CannotServeDirectory, _) => IronError::new(e, Status::BadRequest),
|
||||||
|
e @ Error(ErrorKind::UnsupportedFileType, _) => IronError::new(e, Status::BadRequest),
|
||||||
|
e => IronError::new(e, Status::InternalServerError),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/index.rs
14
src/index.rs
|
@ -8,7 +8,7 @@ use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
use error::*;
|
use errors::*;
|
||||||
use metadata;
|
use metadata;
|
||||||
use vfs::Vfs;
|
use vfs::Vfs;
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ impl<'db> Drop for IndexBuilder<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index {
|
impl Index {
|
||||||
pub fn new(vfs: Arc<Vfs>, config: &IndexConfig) -> Result<Index, PError> {
|
pub fn new(vfs: Arc<Vfs>, config: &IndexConfig) -> Result<Index> {
|
||||||
|
|
||||||
let path = &config.path;
|
let path = &config.path;
|
||||||
|
|
||||||
|
@ -536,7 +536,7 @@ impl Index {
|
||||||
self.select_songs(&mut select).into_iter().map(|s| CollectionFile::Song(s)).collect()
|
self.select_songs(&mut select).into_iter().map(|s| CollectionFile::Song(s)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn browse(&self, virtual_path: &Path) -> Result<Vec<CollectionFile>, PError> {
|
pub fn browse(&self, virtual_path: &Path) -> Result<Vec<CollectionFile>> {
|
||||||
|
|
||||||
let mut output = Vec::new();
|
let mut output = Vec::new();
|
||||||
|
|
||||||
|
@ -553,9 +553,9 @@ impl Index {
|
||||||
output.push(CollectionFile::Directory(directory));
|
output.push(CollectionFile::Directory(directory));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Browse sub-directory
|
// Browse sub-directory
|
||||||
} else {
|
} else {
|
||||||
let real_path = try!(self.vfs.virtual_to_real(virtual_path));
|
let real_path = self.vfs.virtual_to_real(virtual_path)?;
|
||||||
let directories = self.browse_directories(real_path.as_path());
|
let directories = self.browse_directories(real_path.as_path());
|
||||||
let songs = self.browse_songs(real_path.as_path());
|
let songs = self.browse_songs(real_path.as_path());
|
||||||
output.extend(directories);
|
output.extend(directories);
|
||||||
|
@ -565,9 +565,9 @@ impl Index {
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flatten(&self, virtual_path: &Path) -> Result<Vec<Song>, PError> {
|
pub fn flatten(&self, virtual_path: &Path) -> Result<Vec<Song>> {
|
||||||
let db = self.connect();
|
let db = self.connect();
|
||||||
let real_path = try!(self.vfs.virtual_to_real(virtual_path));
|
let real_path = self.vfs.virtual_to_real(virtual_path)?;
|
||||||
let path_string = real_path.to_string_lossy().into_owned() + "%";
|
let path_string = real_path.to_string_lossy().into_owned() + "%";
|
||||||
let mut select =
|
let mut select =
|
||||||
db.prepare("SELECT path, disc_number, track_number, title, year, album_artist, \
|
db.prepare("SELECT path, disc_number, track_number, title, year, album_artist, \
|
||||||
|
|
27
src/main.rs
27
src/main.rs
|
@ -1,6 +1,10 @@
|
||||||
|
#![recursion_limit = "128"]
|
||||||
|
|
||||||
extern crate ape;
|
extern crate ape;
|
||||||
extern crate app_dirs;
|
extern crate app_dirs;
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate error_chain;
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
extern crate id3;
|
extern crate id3;
|
||||||
|
@ -30,6 +34,7 @@ extern crate shell32;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
extern crate user32;
|
extern crate user32;
|
||||||
|
|
||||||
|
use errors::*;
|
||||||
use getopts::Options;
|
use getopts::Options;
|
||||||
use iron::prelude::*;
|
use iron::prelude::*;
|
||||||
use mount::Mount;
|
use mount::Mount;
|
||||||
|
@ -41,7 +46,7 @@ mod api;
|
||||||
mod collection;
|
mod collection;
|
||||||
mod config;
|
mod config;
|
||||||
mod ddns;
|
mod ddns;
|
||||||
mod error;
|
mod errors;
|
||||||
mod index;
|
mod index;
|
||||||
mod metadata;
|
mod metadata;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
@ -50,6 +55,20 @@ mod thumbnails;
|
||||||
mod vfs;
|
mod vfs;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
if let Err(ref e) = run() {
|
||||||
|
println!("Error: {}", e);
|
||||||
|
|
||||||
|
for e in e.iter().skip(1) {
|
||||||
|
println!("caused by: {}", e);
|
||||||
|
}
|
||||||
|
if let Some(backtrace) = e.backtrace() {
|
||||||
|
println!("backtrace: {:?}", backtrace);
|
||||||
|
}
|
||||||
|
::std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run() -> Result<()> {
|
||||||
|
|
||||||
// Parse CLI options
|
// Parse CLI options
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
@ -63,7 +82,7 @@ fn main() {
|
||||||
let config_file_path = config_file_name.map(|n| Path::new(n.as_str()).to_path_buf());
|
let config_file_path = config_file_name.map(|n| Path::new(n.as_str()).to_path_buf());
|
||||||
|
|
||||||
// Parse config
|
// Parse config
|
||||||
let config = config::Config::parse(config_file_path).unwrap();
|
let config = config::Config::parse(config_file_path)?;
|
||||||
|
|
||||||
// Init VFS
|
// Init VFS
|
||||||
let vfs = Arc::new(vfs::Vfs::new(config.vfs.clone()));
|
let vfs = Arc::new(vfs::Vfs::new(config.vfs.clone()));
|
||||||
|
@ -95,7 +114,7 @@ fn main() {
|
||||||
let mut mount = Mount::new();
|
let mut mount = Mount::new();
|
||||||
mount.mount("/api/", api_chain);
|
mount.mount("/api/", api_chain);
|
||||||
mount.mount("/", Static::new(Path::new("web")));
|
mount.mount("/", Static::new(Path::new("web")));
|
||||||
let mut server = Iron::new(mount).http(("0.0.0.0", 5050)).unwrap();
|
let mut server = Iron::new(mount).http(("0.0.0.0", 5050))?;
|
||||||
|
|
||||||
// Start DDNS updates
|
// Start DDNS updates
|
||||||
match config.ddns {
|
match config.ddns {
|
||||||
|
@ -113,4 +132,6 @@ fn main() {
|
||||||
|
|
||||||
println!("Shutting down server");
|
println!("Shutting down server");
|
||||||
server.close().unwrap();
|
server.close().unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use regex::Regex;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use error::PError;
|
use errors::*;
|
||||||
use utils;
|
use utils;
|
||||||
use utils::AudioFormat;
|
use utils::AudioFormat;
|
||||||
|
|
||||||
|
@ -22,18 +22,18 @@ pub struct SongTags {
|
||||||
pub year: Option<i32>,
|
pub year: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(path: &Path) -> Result<SongTags, PError> {
|
pub fn read(path: &Path) -> Result<SongTags> {
|
||||||
match utils::get_audio_format(path) {
|
match utils::get_audio_format(path) {
|
||||||
Some(AudioFormat::FLAC) => read_flac(path),
|
Some(AudioFormat::FLAC) => read_flac(path),
|
||||||
Some(AudioFormat::MP3) => read_id3(path),
|
Some(AudioFormat::MP3) => read_id3(path),
|
||||||
Some(AudioFormat::MPC) => read_ape(path),
|
Some(AudioFormat::MPC) => read_ape(path),
|
||||||
Some(AudioFormat::OGG) => read_vorbis(path),
|
Some(AudioFormat::OGG) => read_vorbis(path),
|
||||||
_ => Err(PError::UnsupportedMetadataFormat),
|
_ => bail!("Unsupported file format for reading metadata"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_id3(path: &Path) -> Result<SongTags, PError> {
|
fn read_id3(path: &Path) -> Result<SongTags> {
|
||||||
let tag = try!(id3::Tag::read_from_path(path));
|
let tag = id3::Tag::read_from_path(path)?;
|
||||||
|
|
||||||
let artist = tag.artist().map(|s| s.to_string());
|
let artist = tag.artist().map(|s| s.to_string());
|
||||||
let album_artist = tag.album_artist().map(|s| s.to_string());
|
let album_artist = tag.album_artist().map(|s| s.to_string());
|
||||||
|
@ -85,8 +85,8 @@ fn read_ape_x_of_y(item: &ape::Item) -> Option<u32> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_ape(path: &Path) -> Result<SongTags, PError> {
|
fn read_ape(path: &Path) -> Result<SongTags> {
|
||||||
let tag = try!(ape::read(path));
|
let tag = ape::read(path)?;
|
||||||
let artist = tag.item("Artist").and_then(read_ape_string);
|
let artist = tag.item("Artist").and_then(read_ape_string);
|
||||||
let album = tag.item("Album").and_then(read_ape_string);
|
let album = tag.item("Album").and_then(read_ape_string);
|
||||||
let album_artist = tag.item("Album artist").and_then(read_ape_string);
|
let album_artist = tag.item("Album artist").and_then(read_ape_string);
|
||||||
|
@ -105,10 +105,10 @@ fn read_ape(path: &Path) -> Result<SongTags, PError> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_vorbis(path: &Path) -> Result<SongTags, PError> {
|
fn read_vorbis(path: &Path) -> Result<SongTags> {
|
||||||
|
|
||||||
let file = try!(fs::File::open(path));
|
let file = fs::File::open(path)?;
|
||||||
let source = try!(OggStreamReader::new(PacketReader::new(file)));
|
let source = OggStreamReader::new(PacketReader::new(file))?;
|
||||||
|
|
||||||
let mut tags = SongTags {
|
let mut tags = SongTags {
|
||||||
artist: None,
|
artist: None,
|
||||||
|
@ -136,9 +136,9 @@ fn read_vorbis(path: &Path) -> Result<SongTags, PError> {
|
||||||
Ok(tags)
|
Ok(tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_flac(path: &Path) -> Result<SongTags, PError> {
|
fn read_flac(path: &Path) -> Result<SongTags> {
|
||||||
let tag = try!(metaflac::Tag::read_from_path(path));
|
let tag = metaflac::Tag::read_from_path(path)?;
|
||||||
let vorbis = try!(tag.vorbis_comments().ok_or(PError::MetadataDecodingError));
|
let vorbis = tag.vorbis_comments().ok_or("Missing Vorbis comments")?;
|
||||||
let disc_number = vorbis.get("DISCNUMBER").and_then(|d| d[0].parse::<u32>().ok());
|
let disc_number = vorbis.get("DISCNUMBER").and_then(|d| d[0].parse::<u32>().ok());
|
||||||
let year = vorbis.get("DATE").and_then(|d| d[0].parse::<i32>().ok());
|
let year = vorbis.get("DATE").and_then(|d| d[0].parse::<i32>().ok());
|
||||||
Ok(SongTags {
|
Ok(SongTags {
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::fs::DirBuilder;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::path::*;
|
use std::path::*;
|
||||||
|
|
||||||
use error::*;
|
use errors::*;
|
||||||
use utils;
|
use utils;
|
||||||
|
|
||||||
const THUMBNAILS_PATH: &'static str = "thumbnails";
|
const THUMBNAILS_PATH: &'static str = "thumbnails";
|
||||||
|
@ -22,16 +22,16 @@ fn hash(path: &Path, dimension: u32) -> u64 {
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_thumbnail(real_path: &Path, max_dimension: u32) -> Result<PathBuf, PError> {
|
pub fn get_thumbnail(real_path: &Path, max_dimension: u32) -> Result<PathBuf> {
|
||||||
|
|
||||||
let mut out_path = try!(utils::get_cache_root());
|
let mut out_path = utils::get_cache_root()?;
|
||||||
out_path.push(THUMBNAILS_PATH);
|
out_path.push(THUMBNAILS_PATH);
|
||||||
|
|
||||||
let mut dir_builder = DirBuilder::new();
|
let mut dir_builder = DirBuilder::new();
|
||||||
dir_builder.recursive(true);
|
dir_builder.recursive(true);
|
||||||
try!(dir_builder.create(out_path.as_path()));
|
dir_builder.create(out_path.as_path())?;
|
||||||
|
|
||||||
let source_image = try!(image::open(real_path));
|
let source_image = image::open(real_path)?;
|
||||||
let (source_width, source_height) = source_image.dimensions();
|
let (source_width, source_height) = source_image.dimensions();
|
||||||
let cropped_dimension = cmp::max(source_width, source_height);
|
let cropped_dimension = cmp::max(source_width, source_height);
|
||||||
let out_dimension = cmp::min(max_dimension, cropped_dimension);
|
let out_dimension = cmp::min(max_dimension, cropped_dimension);
|
||||||
|
@ -50,13 +50,13 @@ pub fn get_thumbnail(real_path: &Path, max_dimension: u32) -> Result<PathBuf, PE
|
||||||
out_dimension,
|
out_dimension,
|
||||||
out_dimension,
|
out_dimension,
|
||||||
FilterType::Lanczos3);
|
FilterType::Lanczos3);
|
||||||
try!(out_image.save(out_path.as_path()));
|
out_image.save(out_path.as_path())?;
|
||||||
} else {
|
} else {
|
||||||
let out_image = resize(&source_image,
|
let out_image = resize(&source_image,
|
||||||
out_dimension,
|
out_dimension,
|
||||||
out_dimension,
|
out_dimension,
|
||||||
FilterType::Lanczos3);
|
FilterType::Lanczos3);
|
||||||
try!(out_image.save(out_path.as_path()));
|
out_image.save(out_path.as_path())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
22
src/utils.rs
22
src/utils.rs
|
@ -2,28 +2,24 @@ use app_dirs::{AppDataType, data_root};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
use error::PError;
|
use errors::*;
|
||||||
|
|
||||||
pub fn get_config_root() -> Result<PathBuf, PError> {
|
pub fn get_config_root() -> Result<PathBuf> {
|
||||||
if let Ok(mut root) = data_root(AppDataType::SharedConfig) {
|
if let Ok(mut root) = data_root(AppDataType::SharedConfig) {
|
||||||
root.push("Polaris");
|
root.push("Polaris");
|
||||||
return match fs::create_dir_all(&root) {
|
fs::create_dir_all(&root)?;
|
||||||
Ok(()) => Ok(root),
|
return Ok(root);
|
||||||
Err(_) => Err(PError::CacheDirectoryError),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
Err(PError::ConfigDirectoryError)
|
bail!("Could not retrieve config directory root");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_cache_root() -> Result<PathBuf, PError> {
|
pub fn get_cache_root() -> Result<PathBuf> {
|
||||||
if let Ok(mut root) = data_root(AppDataType::SharedData) {
|
if let Ok(mut root) = data_root(AppDataType::SharedData) {
|
||||||
root.push("Polaris");
|
root.push("Polaris");
|
||||||
return match fs::create_dir_all(&root) {
|
fs::create_dir_all(&root)?;
|
||||||
Ok(()) => Ok(root),
|
return Ok(root);
|
||||||
Err(_) => Err(PError::CacheDirectoryError),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
Err(PError::CacheDirectoryError)
|
bail!("Could not retrieve cache directory root");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
|
|
10
src/vfs.rs
10
src/vfs.rs
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use error::*;
|
use errors::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct VfsConfig {
|
pub struct VfsConfig {
|
||||||
|
@ -24,7 +24,7 @@ impl Vfs {
|
||||||
Vfs { mount_points: config.mount_points }
|
Vfs { mount_points: config.mount_points }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn real_to_virtual(&self, real_path: &Path) -> Result<PathBuf, PError> {
|
pub fn real_to_virtual(&self, real_path: &Path) -> Result<PathBuf> {
|
||||||
for (name, target) in &self.mount_points {
|
for (name, target) in &self.mount_points {
|
||||||
match real_path.strip_prefix(target) {
|
match real_path.strip_prefix(target) {
|
||||||
Ok(p) => {
|
Ok(p) => {
|
||||||
|
@ -34,10 +34,10 @@ impl Vfs {
|
||||||
Err(_) => (),
|
Err(_) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(PError::PathNotInVfs)
|
bail!("Real path has no match in VFS")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn virtual_to_real(&self, virtual_path: &Path) -> Result<PathBuf, PError> {
|
pub fn virtual_to_real(&self, virtual_path: &Path) -> Result<PathBuf> {
|
||||||
for (name, target) in &self.mount_points {
|
for (name, target) in &self.mount_points {
|
||||||
let mount_path = Path::new(&name);
|
let mount_path = Path::new(&name);
|
||||||
match virtual_path.strip_prefix(mount_path) {
|
match virtual_path.strip_prefix(mount_path) {
|
||||||
|
@ -51,7 +51,7 @@ impl Vfs {
|
||||||
Err(_) => (),
|
Err(_) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(PError::PathNotInVfs)
|
bail!("Virtual path has no match in VFS")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mount_points(&self) -> &HashMap<String, PathBuf> {
|
pub fn get_mount_points(&self) -> &HashMap<String, PathBuf> {
|
||||||
|
|
Loading…
Add table
Reference in a new issue