diff --git a/Cargo.lock b/Cargo.lock index f2fcb3f..de639f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,6 +3,7 @@ name = "polaris" version = "0.2.0" dependencies = [ "ape 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "app_dirs 1.1.1 (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.10 (registry+https://github.com/rust-lang/crates.io-index)", "id3 0.1.10 (git+https://github.com/jameshurst/rust-id3)", @@ -44,6 +45,17 @@ dependencies = [ "byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "app_dirs" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.7.0" @@ -606,6 +618,15 @@ dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ole32-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]] name = "openssl" version = "0.7.14" @@ -856,6 +877,15 @@ dependencies = [ "winapi-build 0.1.1 (git+https://github.com/retep998/winapi-rs)", ] +[[package]] +name = "shell32-sys" +version = "0.1.1" +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]] name = "solicit" version = "0.4.4" @@ -1090,9 +1120,15 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "xdg" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] "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 app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b7d1c0d48a81bbb13043847f957971f4d87c81542d80ece5e84ba3cba4058fd4" "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 buf_redux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b115bd9935c68b58f80ff867e1c46942c4aed79e78bcc8c2bc22d50f52bb9099" @@ -1159,6 +1195,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "8359ea48994f253fa958b5b90b013728b06f54872e5a58bce39540fcdd0f2527" "checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" "checksum ogg 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "780fc298e7c28a3d5b49638da41b99136d535564ca7060574dab61a845e4947d" +"checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" "checksum openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "c4117b6244aac42ed0150a6019b4d953d28247c5dd6ae6f46ae469b5f2318733" "checksum openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)" = "89c47ee94c352eea9ddaf8e364be7f978a3bb6d66d73176572484238dd5a5c3f" "checksum openssl-sys-extras 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "11c5e1dba7d3d03d80f045bf0d60111dc69213b67651e7c889527a3badabb9fa" @@ -1189,6 +1226,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_json 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5b3bb42fa42265df8a1822b3db2090bc8f9e17e8142599c76a5b854bc4e7b5b" "checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c" "checksum shell32-sys 0.1.1 (git+https://github.com/retep998/winapi-rs)" = "" +"checksum shell32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f20b8f3c060374edb8046591ba28f62448c369ccbdc7b02075103fb3a9e38d" "checksum solicit 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "172382bac9424588d7840732b250faeeef88942e37b6e35317dce98cafdd75b2" "checksum sqlite 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b0bae8699b7aa134328a75735f9fb18553ff8f7edb41b5160978c327a52831" "checksum sqlite3-src 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6d9d456ae741b07c60ede84b0fa85bafad8275b1bb95bb42a93805d7475313b" @@ -1219,3 +1257,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (git+https://github.com/retep998/winapi-rs)" = "" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum xdg 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77b831a5ba77110f438f0ac5583aafeb087f70432998ba6b7dcb1d32185db453" diff --git a/Cargo.toml b/Cargo.toml index 4640995..f473500 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ ui = [] [dependencies] ape = "0.1.2" +app_dirs = "1.1.1" getopts = "0.2.14" hyper = "0.9.10" id3 = { git = "https://github.com/jameshurst/rust-id3" } diff --git a/src/api.rs b/src/api.rs index 05b6832..b912fb7 100644 --- a/src/api.rs +++ b/src/api.rs @@ -43,6 +43,8 @@ impl From for IronError { 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), diff --git a/src/config.rs b/src/config.rs index 3c4c3ad..2bdd95c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,8 +8,10 @@ use toml; use collection::User; use ddns::DDNSConfig; use index::IndexConfig; +use utils; use vfs::VfsConfig; +const DEFAULT_CONFIG_FILE_NAME: &'static str = "polaris.toml"; const CONFIG_SECRET: &'static str = "auth_secret"; const CONFIG_MOUNT_DIRS: &'static str = "mount_dirs"; const CONFIG_MOUNT_DIR_NAME: &'static str = "name"; @@ -27,6 +29,7 @@ const CONFIG_DDNS_PASSWORD: &'static str = "password"; #[derive(Debug)] pub enum ConfigError { IoError(io::Error), + ConfigDirectoryError, TOMLParseError, RegexError(regex::Error), SecretParseError, @@ -59,7 +62,21 @@ pub struct Config { } impl Config { - pub fn parse(config_path: &path::Path) -> Result { + pub fn parse(custom_path: Option) -> Result { + + let config_path = match custom_path { + Some(p) => p, + None => { + let mut root = match utils::get_config_root() { + Ok(r) => r, + Err(_) => return Err(ConfigError::ConfigDirectoryError), + }; + root.push(DEFAULT_CONFIG_FILE_NAME); + root + }, + }; + println!("Loading config from: {}", config_path.to_string_lossy()); + let mut config_file = try!(fs::File::open(config_path)); let mut config_file_content = String::new(); try!(config_file.read_to_string(&mut config_file_content)); diff --git a/src/error.rs b/src/error.rs index 84b399e..404d1ae 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,6 +12,8 @@ pub enum PError { CannotClearExistingIndex, PathDecoding, Io(io::Error), + CacheDirectoryError, + ConfigDirectoryError, PathNotInVfs, CannotServeDirectory, UnsupportedFileType, @@ -71,6 +73,8 @@ impl error::Error for PError { 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", @@ -105,6 +109,8 @@ impl fmt::Display for PError { 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"), diff --git a/src/index.rs b/src/index.rs index 33e06dd..e8a6291 100644 --- a/src/index.rs +++ b/src/index.rs @@ -10,8 +10,10 @@ use std::time; use error::*; use metadata::SongTags; +use utils; use vfs::Vfs; +const INDEX_FILE_NAME: &'static str = "index.sqlite"; const INDEX_BUILDING_INSERT_BUFFER_SIZE: usize = 250; // Insertions in each transaction const INDEX_LOCK_TIMEOUT: usize = 1000; // In milliseconds @@ -181,11 +183,15 @@ impl<'db> Drop for IndexBuilder<'db> { } impl Index { - pub fn new(path: &Path, - vfs: Arc, + pub fn new(vfs: Arc, config: &IndexConfig) -> Result { + let mut path = try!(utils::get_cache_root()); + path.push(INDEX_FILE_NAME); + + println!("Reading or creating index from {}", path.to_string_lossy()); + let index = Index { path: path.to_string_lossy().deref().to_string(), vfs: vfs, diff --git a/src/main.rs b/src/main.rs index f8125ff..520db64 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ extern crate ape; +extern crate app_dirs; extern crate core; extern crate getopts; extern crate hyper; @@ -33,7 +34,7 @@ use getopts::Options; use iron::prelude::*; use mount::Mount; use staticfile::Static; -use std::path; +use std::path::Path; use std::sync::Arc; mod api; @@ -48,9 +49,6 @@ mod utils; mod thumbnails; mod vfs; -const DEFAULT_CONFIG_FILE_NAME: &'static str = "polaris.toml"; -const INDEX_FILE_NAME: &'static str = "index.sqlite"; - fn main() { // Parse CLI options @@ -61,20 +59,18 @@ fn main() { Ok(m) => m, Err(f) => panic!(f.to_string()), }; - let config_file_name = matches.opt_str("c").unwrap_or(DEFAULT_CONFIG_FILE_NAME.to_owned()); + let config_file_name = matches.opt_str("c"); + let config_file_path = config_file_name.map(|n| Path::new(n.as_str()).to_path_buf()); // Parse config - println!("Reading configuration from {}", config_file_name); - let config_file = path::Path::new(config_file_name.as_str()); - let config = config::Config::parse(&config_file).unwrap(); + let config = config::Config::parse(config_file_path).unwrap(); // Init VFS let vfs = Arc::new(vfs::Vfs::new(config.vfs.clone())); // Init index println!("Starting up index"); - let index_path = path::Path::new(INDEX_FILE_NAME); - let index = Arc::new(index::Index::new(&index_path, vfs.clone(), &config.index) + let index = Arc::new(index::Index::new(vfs.clone(), &config.index) .unwrap()); let index_ref = index.clone(); std::thread::spawn(move || index_ref.run()); @@ -99,7 +95,7 @@ fn main() { let mut mount = Mount::new(); mount.mount("/api/", api_chain); - mount.mount("/", Static::new(path::Path::new("web"))); + mount.mount("/", Static::new(Path::new("web"))); let mut server = Iron::new(mount).http(("0.0.0.0", 5050)).unwrap(); // Start DDNS updates diff --git a/src/thumbnails.rs b/src/thumbnails.rs index a85354e..8fc89de 100644 --- a/src/thumbnails.rs +++ b/src/thumbnails.rs @@ -10,8 +10,9 @@ use std::hash::{Hash, Hasher}; use std::path::*; use error::*; +use utils; -const THUMBNAILS_PATH: &'static str = "tmp/thumbnails"; +const THUMBNAILS_PATH: &'static str = "thumbnails"; fn hash(path: &Path, dimension: u32) -> u64 { let path_string = path.to_string_lossy(); @@ -23,8 +24,9 @@ fn hash(path: &Path, dimension: u32) -> u64 { pub fn get_thumbnail(real_path: &Path, max_dimension: u32) -> Result { - let mut out_path = PathBuf::new(); + let mut out_path = try!(utils::get_cache_root()); out_path.push(THUMBNAILS_PATH); + let mut dir_builder = DirBuilder::new(); dir_builder.recursive(true); try!(dir_builder.create(out_path.as_path())); diff --git a/src/utils.rs b/src/utils.rs index 5de7452..8b0b1e2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,30 @@ -use std::path::Path; +use app_dirs::{AppDataType, data_root}; +use std::path::{Path, PathBuf}; +use std::fs; + +use error::PError; + +pub fn get_config_root() -> Result { + if let Ok(mut root) = data_root(AppDataType::UserConfig){ + root.push("Polaris"); + return match fs::create_dir_all(&root) { + Ok(()) => Ok(root), + Err(_) => Err(PError::CacheDirectoryError), + } + } + Err(PError::ConfigDirectoryError) +} + +pub fn get_cache_root() -> Result { + if let Ok(mut root) = data_root(AppDataType::UserCache){ + root.push("Polaris"); + return match fs::create_dir_all(&root) { + Ok(()) => Ok(root), + Err(_) => Err(PError::CacheDirectoryError), + } + } + Err(PError::CacheDirectoryError) +} pub enum AudioFormat { FLAC,