diff --git a/src/api.rs b/src/api.rs index 3885872..e42f96a 100644 --- a/src/api.rs +++ b/src/api.rs @@ -52,9 +52,8 @@ pub fn get_api_handler(collection: Arc) -> Mount { { let collection = collection.clone(); - api_handler.mount("/auth/", move |request: &mut Request| { - self::auth(request, collection.deref()) - }); + api_handler.mount("/auth/", + move |request: &mut Request| self::auth(request, collection.deref())); } { @@ -189,7 +188,7 @@ fn serve(request: &mut Request, collection: &Collection) -> IronResult } if is_song(real_path.as_path()) { - return Ok(Response::with((status::Ok, real_path))) + return Ok(Response::with((status::Ok, real_path))); } if is_image(real_path.as_path()) { @@ -203,6 +202,6 @@ fn art(_: &mut Request, real_path: &Path) -> IronResult { let thumb = get_thumbnail(real_path, 400); match thumb { Ok(path) => Ok(Response::with((status::Ok, path))), - Err(e) => Err(IronError::from(e)) + Err(e) => Err(IronError::from(e)), } -} \ No newline at end of file +} diff --git a/src/config.rs b/src/config.rs index 2eef759..4617f92 100644 --- a/src/config.rs +++ b/src/config.rs @@ -24,14 +24,14 @@ const CONFIG_DDNS_PASSWORD: &'static str = "password"; #[derive(Debug)] pub enum ConfigError { - IoError(io::Error), - TOMLParseError, - RegexError(regex::Error), - SecretParseError, - AlbumArtPatternParseError, - UsersParseError, - MountDirsParseError, - DDNSParseError, + IoError(io::Error), + TOMLParseError, + RegexError(regex::Error), + SecretParseError, + AlbumArtPatternParseError, + UsersParseError, + MountDirsParseError, + DDNSParseError, ConflictingMounts, } @@ -48,46 +48,46 @@ impl From for ConfigError { } pub struct Config { - pub secret: String, - pub vfs: VfsConfig, + pub secret: String, + pub vfs: VfsConfig, pub users: Vec, pub album_art_pattern: Option, - pub ddns: Option, + pub ddns: Option, } impl Config { - pub fn parse(config_path: &path::Path) -> Result { - let mut config_file = try!(fs::File::open(config_path)); + pub fn parse(config_path: &path::Path) -> Result { + 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)); - let parsed_config = toml::Parser::new(config_file_content.as_str()).parse(); + try!(config_file.read_to_string(&mut config_file_content)); + let parsed_config = toml::Parser::new(config_file_content.as_str()).parse(); let parsed_config = try!(parsed_config.ok_or(ConfigError::TOMLParseError)); - let mut config = Config { - secret: String::new(), - vfs: VfsConfig::new(), - users: Vec::new(), - album_art_pattern: None, - ddns: None, - }; + let mut config = Config { + secret: String::new(), + vfs: VfsConfig::new(), + users: Vec::new(), + album_art_pattern: None, + ddns: None, + }; - try!(config.parse_secret(&parsed_config)); - try!(config.parse_mount_points(&parsed_config)); + try!(config.parse_secret(&parsed_config)); + try!(config.parse_mount_points(&parsed_config)); try!(config.parse_users(&parsed_config)); try!(config.parse_album_art_pattern(&parsed_config)); try!(config.parse_ddns(&parsed_config)); - Ok(config) - } + Ok(config) + } - fn parse_secret(&mut self, source: &toml::Table) -> Result<(), ConfigError> { - let secret = try!(source.get(CONFIG_SECRET).ok_or(ConfigError::SecretParseError)); - let secret = try!(secret.as_str().ok_or(ConfigError::SecretParseError)); - self.secret = secret.to_owned(); - Ok(()) - } + fn parse_secret(&mut self, source: &toml::Table) -> Result<(), ConfigError> { + let secret = try!(source.get(CONFIG_SECRET).ok_or(ConfigError::SecretParseError)); + let secret = try!(secret.as_str().ok_or(ConfigError::SecretParseError)); + self.secret = secret.to_owned(); + Ok(()) + } - fn parse_album_art_pattern(&mut self, source: &toml::Table) -> Result<(), ConfigError> { + fn parse_album_art_pattern(&mut self, source: &toml::Table) -> Result<(), ConfigError> { let pattern = match source.get(CONFIG_ALBUM_ART_PATTERN) { Some(s) => s, None => return Ok(()), @@ -100,7 +100,7 @@ impl Config { Ok(()) } - fn parse_users(&mut self, source: &toml::Table) -> Result<(), ConfigError> { + fn parse_users(&mut self, source: &toml::Table) -> Result<(), ConfigError> { let users = match source.get(CONFIG_USERS) { Some(s) => s, None => return Ok(()), @@ -137,7 +137,7 @@ impl Config { Ok(()) } - fn parse_mount_points(&mut self, source: &toml::Table) -> Result<(), ConfigError> { + fn parse_mount_points(&mut self, source: &toml::Table) -> Result<(), ConfigError> { let mount_dirs = match source.get(CONFIG_MOUNT_DIRS) { Some(s) => s, None => return Ok(()), @@ -177,30 +177,32 @@ impl Config { Ok(()) } - fn parse_ddns(&mut self, source: &toml::Table) -> Result<(), ConfigError> { + fn parse_ddns(&mut self, source: &toml::Table) -> Result<(), ConfigError> { let ddns = match source.get(CONFIG_DDNS) { Some(s) => s, None => return Ok(()), }; - let ddns = match ddns { + let ddns = match ddns { &toml::Value::Table(ref a) => a, _ => return Err(ConfigError::DDNSParseError), }; - let host = try!(ddns.get(CONFIG_DDNS_HOST).ok_or(ConfigError::DDNSParseError)).as_str(); - let username = try!(ddns.get(CONFIG_DDNS_USERNAME).ok_or(ConfigError::DDNSParseError)).as_str(); - let password = try!(ddns.get(CONFIG_DDNS_PASSWORD).ok_or(ConfigError::DDNSParseError)).as_str(); + let host = try!(ddns.get(CONFIG_DDNS_HOST).ok_or(ConfigError::DDNSParseError)).as_str(); + let username = try!(ddns.get(CONFIG_DDNS_USERNAME).ok_or(ConfigError::DDNSParseError)) + .as_str(); + let password = try!(ddns.get(CONFIG_DDNS_PASSWORD).ok_or(ConfigError::DDNSParseError)) + .as_str(); - let host = try!(host.ok_or(ConfigError::DDNSParseError)); - let username = try!(username.ok_or(ConfigError::DDNSParseError)); - let password = try!(password.ok_or(ConfigError::DDNSParseError)); + let host = try!(host.ok_or(ConfigError::DDNSParseError)); + let username = try!(username.ok_or(ConfigError::DDNSParseError)); + let password = try!(password.ok_or(ConfigError::DDNSParseError)); - self.ddns = Some(DDNSConfig { - host: host.to_owned(), - username: username.to_owned(), - password: password.to_owned(), - }); - Ok(()) + self.ddns = Some(DDNSConfig { + host: host.to_owned(), + username: username.to_owned(), + password: password.to_owned(), + }); + Ok(()) } } @@ -217,10 +219,10 @@ fn clean_path_string(path_string: &str) -> path::PathBuf { #[test] fn test_clean_path_string() { let mut correct_path = path::PathBuf::new(); - correct_path.push("C:"); - correct_path.push("some"); + correct_path.push("C:"); + correct_path.push("some"); correct_path.push("path"); - assert_eq!(correct_path, clean_path_string(r#"C:/some/path"#)); - assert_eq!(correct_path, clean_path_string(r#"C:\some\path"#)); - assert_eq!(correct_path, clean_path_string(r#"C:\some\path\"#)); + assert_eq!(correct_path, clean_path_string(r#"C:/some/path"#)); + assert_eq!(correct_path, clean_path_string(r#"C:\some\path"#)); + assert_eq!(correct_path, clean_path_string(r#"C:\some\path\"#)); } diff --git a/src/ddns.rs b/src/ddns.rs index f0f0a43..db644ae 100644 --- a/src/ddns.rs +++ b/src/ddns.rs @@ -1,6 +1,6 @@ use hyper; use hyper::client::Client; -use hyper::header::{Authorization, Basic }; +use hyper::header::{Authorization, Basic}; use std::io; use std::io::Read; use std::thread; @@ -8,16 +8,16 @@ use std::time; #[derive(Debug, Clone)] pub struct DDNSConfig { - pub host: String, - pub username: String, - pub password: String, + pub host: String, + pub username: String, + pub password: String, } #[derive(Debug)] enum DDNSError { - IoError(io::Error), - HyperError(hyper::Error), - UpdateError(hyper::status::StatusCode), + IoError(io::Error), + HyperError(hyper::Error), + UpdateError(hyper::status::StatusCode), } impl From for DDNSError { @@ -36,43 +36,41 @@ const MY_IP_API_URL: &'static str = "http://api.ipify.org"; const DDNS_UPDATE_URL: &'static str = "http://ydns.io/api/v1/update/"; fn get_my_ip() -> Result { - let client = Client::new(); - let mut res = try!(client.get(MY_IP_API_URL).send()); - let mut buf = String::new(); - try!(res.read_to_string(&mut buf)); - Ok(buf) + let client = Client::new(); + let mut res = try!(client.get(MY_IP_API_URL).send()); + let mut buf = String::new(); + try!(res.read_to_string(&mut buf)); + Ok(buf) } fn update_my_ip(ip: &String, config: &DDNSConfig) -> Result<(), DDNSError> { - let client = Client::new(); - let url = DDNS_UPDATE_URL; - let host = &config.host; - let full_url = format!("{}?host={}&ip={}", url, host, ip); - let auth_header = Authorization(Basic { - username: config.username.clone(), - password: Some(config.password.to_owned()) - }); + let client = Client::new(); + let url = DDNS_UPDATE_URL; + let host = &config.host; + let full_url = format!("{}?host={}&ip={}", url, host, ip); + let auth_header = Authorization(Basic { + username: config.username.clone(), + password: Some(config.password.to_owned()), + }); - let res = try!(client.get(full_url.as_str()).header(auth_header).send()); - match res.status { - hyper::status::StatusCode::Ok => Ok(()), - s => Err(DDNSError::UpdateError(s)), - } + let res = try!(client.get(full_url.as_str()).header(auth_header).send()); + match res.status { + hyper::status::StatusCode::Ok => Ok(()), + s => Err(DDNSError::UpdateError(s)), + } } pub fn run(config: DDNSConfig) { - loop { - let my_ip_res = get_my_ip(); - if let Ok(my_ip) = my_ip_res { - match update_my_ip(&my_ip, &config) { - Err(e) => println!("Dynamic DNS Error: {:?}", e), - Ok(_) => (), - }; - } - else - { - println!("Dynamic DNS Error: could not retrieve our own IP address"); - } - thread::sleep(time::Duration::from_secs(60 * 30)); - } -} \ No newline at end of file + loop { + let my_ip_res = get_my_ip(); + if let Ok(my_ip) = my_ip_res { + match update_my_ip(&my_ip, &config) { + Err(e) => println!("Dynamic DNS Error: {:?}", e), + Ok(_) => (), + }; + } else { + println!("Dynamic DNS Error: could not retrieve our own IP address"); + } + thread::sleep(time::Duration::from_secs(60 * 30)); + } +} diff --git a/src/index.rs b/src/index.rs index bf9e055..4e1ead9 100644 --- a/src/index.rs +++ b/src/index.rs @@ -19,9 +19,9 @@ const INDEX_BUILDING_INSERT_BUFFER_SIZE: usize = 500; // Put 500 insertions in e const INDEX_LOCK_TIMEOUT: usize = 100; // In milliseconds pub struct Index { - path: String, - vfs: Arc, - album_art_pattern: Option, + path: String, + vfs: Arc, + album_art_pattern: Option, } struct SongTags { @@ -35,15 +35,15 @@ struct SongTags { impl SongTags { fn read(path: &Path) -> Result { - match utils::get_audio_format(path) { - Some(AudioFormat::MP3) => SongTags::read_id3(path), - Some(AudioFormat::MPC) => SongTags::read_ape(path), - _ => Err(PError::UnsupportedMetadataFormat), - } + match utils::get_audio_format(path) { + Some(AudioFormat::MP3) => SongTags::read_id3(path), + Some(AudioFormat::MPC) => SongTags::read_ape(path), + _ => Err(PError::UnsupportedMetadataFormat), + } } - fn read_id3(path: &Path) -> Result { - let tag = try!(Tag::read_from_path(path)); + fn read_id3(path: &Path) -> Result { + let tag = try!(Tag::read_from_path(path)); let artist = tag.artist().map(|s| s.to_string()); let album_artist = tag.album_artist().map(|s| s.to_string()); @@ -54,7 +54,7 @@ impl SongTags { .map(|y| y as i32) .or(tag.date_released().and_then(|d| d.year)) .or(tag.date_recorded().and_then(|d| d.year)); - + Ok(SongTags { artist: artist, album_artist: album_artist, @@ -63,45 +63,45 @@ impl SongTags { track_number: track_number, year: year, }) - } + } - fn read_ape_string(item: &ape::Item) -> Option { - match item.value { - ape::ItemValue::Text(ref s) => Some(s.clone()), - _ => None, - } - } + fn read_ape_string(item: &ape::Item) -> Option { + match item.value { + ape::ItemValue::Text(ref s) => Some(s.clone()), + _ => None, + } + } - fn read_ape_i32(item: &ape::Item) -> Option { - match item.value { - ape::ItemValue::Text(ref s) => s.parse::().ok(), - _ => None, - } - } + fn read_ape_i32(item: &ape::Item) -> Option { + match item.value { + ape::ItemValue::Text(ref s) => s.parse::().ok(), + _ => None, + } + } - fn read_ape_track_number(item: &ape::Item) -> Option { - match item.value { - ape::ItemValue::Text(ref s) => { - let format = Regex::new(r#"^\d+"#).unwrap(); - if let Some((start, end)) = format.find(s) { - s[start..end].parse().ok() - } else { - None - } - }, - _ => None, - } - } + fn read_ape_track_number(item: &ape::Item) -> Option { + match item.value { + ape::ItemValue::Text(ref s) => { + let format = Regex::new(r#"^\d+"#).unwrap(); + if let Some((start, end)) = format.find(s) { + s[start..end].parse().ok() + } else { + None + } + } + _ => None, + } + } - fn read_ape(path: &Path) -> Result { - let tag = try!(ape::read(path)); - let artist = tag.item("Artist").and_then(SongTags::read_ape_string); - let album = tag.item("Album").and_then(SongTags::read_ape_string); - let album_artist = tag.item("Album artist").and_then(SongTags::read_ape_string); - let title = tag.item("Title").and_then(SongTags::read_ape_string); - let year = tag.item("Year").and_then(SongTags::read_ape_i32); - let track_number = tag.item("Track").and_then(SongTags::read_ape_track_number); - Ok(SongTags { + fn read_ape(path: &Path) -> Result { + let tag = try!(ape::read(path)); + let artist = tag.item("Artist").and_then(SongTags::read_ape_string); + let album = tag.item("Album").and_then(SongTags::read_ape_string); + let album_artist = tag.item("Album artist").and_then(SongTags::read_ape_string); + let title = tag.item("Title").and_then(SongTags::read_ape_string); + let year = tag.item("Year").and_then(SongTags::read_ape_i32); + let track_number = tag.item("Track").and_then(SongTags::read_ape_track_number); + Ok(SongTags { artist: artist, album_artist: album_artist, album: album, @@ -109,7 +109,7 @@ impl SongTags { track_number: track_number, year: year, }) - } + } } #[derive(Debug, RustcEncodable)] @@ -140,464 +140,504 @@ pub enum CollectionFile { } fn string_option_to_value(input: Option) -> Value { - match input { - Some(s) => Value::String(s), - None => Value::Null, - } + match input { + Some(s) => Value::String(s), + None => Value::Null, + } } fn i32_option_to_value(input: Option) -> Value { - match input { - Some(s) => Value::Integer(s as i64), - None => Value::Null, - } + match input { + Some(s) => Value::Integer(s as i64), + None => Value::Null, + } } fn u32_option_to_value(input: Option) -> Value { - match input { - Some(s) => Value::Integer(s as i64), - None => Value::Null, - } + match input { + Some(s) => Value::Integer(s as i64), + None => Value::Null, + } } struct IndexBuilder<'db> { - queue: Vec, - db: &'db Connection, - insert_directory: Statement<'db>, - insert_song: Statement<'db>, + queue: Vec, + db: &'db Connection, + insert_directory: Statement<'db>, + insert_song: Statement<'db>, } impl<'db> IndexBuilder<'db> { - fn new(db: &Connection) -> IndexBuilder { - let mut queue = Vec::new(); - queue.reserve_exact(INDEX_BUILDING_INSERT_BUFFER_SIZE); - IndexBuilder { - queue: queue, - db: db, - insert_directory: db.prepare("INSERT OR REPLACE INTO directories (path, parent, artwork, year, artist, album) VALUES (?, ?, ?, ?, ?, ?)").unwrap(), - insert_song: db.prepare("INSERT OR REPLACE INTO songs (path, parent, track_number, title, year, album_artist, artist, album, artwork) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)").unwrap(), - } - } + fn new(db: &Connection) -> IndexBuilder { + let mut queue = Vec::new(); + queue.reserve_exact(INDEX_BUILDING_INSERT_BUFFER_SIZE); + IndexBuilder { + queue: queue, + db: db, + insert_directory: + db.prepare("INSERT OR REPLACE INTO directories (path, parent, artwork, year, \ + artist, album) VALUES (?, ?, ?, ?, ?, ?)") + .unwrap(), + insert_song: + db.prepare("INSERT OR REPLACE INTO songs (path, parent, track_number, title, year, \ + album_artist, artist, album, artwork) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)") + .unwrap(), + } + } - fn get_parent(path: &str) -> Option { - let parent_path = Path::new(path); - if let Some(parent_dir) = parent_path.parent() { - if let Some(parent_path) = parent_dir.to_str() { - return Some(parent_path.to_owned()); - } - } - None - } + fn get_parent(path: &str) -> Option { + let parent_path = Path::new(path); + if let Some(parent_dir) = parent_path.parent() { + if let Some(parent_path) = parent_dir.to_str() { + return Some(parent_path.to_owned()); + } + } + None + } - fn flush(&mut self) { - self.db.execute("BEGIN TRANSACTION").ok(); - while let Some(file) = self.queue.pop() { - match file { + fn flush(&mut self) { + self.db.execute("BEGIN TRANSACTION").ok(); + while let Some(file) = self.queue.pop() { + match file { - // Insert directory - CollectionFile::Directory(directory) => { - let parent = IndexBuilder::get_parent(directory.path.as_str()); - self.insert_directory.reset().ok(); - self.insert_directory.bind(1, &Value::String(directory.path)).unwrap(); - self.insert_directory.bind(2, &string_option_to_value(parent)).unwrap(); - self.insert_directory.bind(3, &string_option_to_value(directory.artwork)).unwrap(); - self.insert_directory.bind(4, &i32_option_to_value(directory.year)).unwrap(); - self.insert_directory.bind(5, &string_option_to_value(directory.artist)).unwrap(); - self.insert_directory.bind(6, &string_option_to_value(directory.album)).unwrap(); - self.insert_directory.next().ok(); - }, + // Insert directory + CollectionFile::Directory(directory) => { + let parent = IndexBuilder::get_parent(directory.path.as_str()); + self.insert_directory.reset().ok(); + self.insert_directory.bind(1, &Value::String(directory.path)).unwrap(); + self.insert_directory.bind(2, &string_option_to_value(parent)).unwrap(); + self.insert_directory + .bind(3, &string_option_to_value(directory.artwork)) + .unwrap(); + self.insert_directory.bind(4, &i32_option_to_value(directory.year)).unwrap(); + self.insert_directory + .bind(5, &string_option_to_value(directory.artist)) + .unwrap(); + self.insert_directory + .bind(6, &string_option_to_value(directory.album)) + .unwrap(); + self.insert_directory.next().ok(); + } - // Insert song - CollectionFile::Song(song) => { - let parent = IndexBuilder::get_parent(song.path.as_str()); - self.insert_song.reset().ok(); - self.insert_song.bind(1, &Value::String(song.path)).unwrap(); - self.insert_song.bind(2, &string_option_to_value(parent)).unwrap(); - self.insert_song.bind(3, &u32_option_to_value(song.track_number)).unwrap(); - self.insert_song.bind(4, &string_option_to_value(song.title)).unwrap(); - self.insert_song.bind(5, &i32_option_to_value(song.year)).unwrap(); - self.insert_song.bind(6, &string_option_to_value(song.album_artist)).unwrap(); - self.insert_song.bind(7, &string_option_to_value(song.artist)).unwrap(); - self.insert_song.bind(8, &string_option_to_value(song.album)).unwrap(); - self.insert_song.bind(9, &string_option_to_value(song.artwork)).unwrap(); - self.insert_song.next().ok(); - } + // Insert song + CollectionFile::Song(song) => { + let parent = IndexBuilder::get_parent(song.path.as_str()); + self.insert_song.reset().ok(); + self.insert_song.bind(1, &Value::String(song.path)).unwrap(); + self.insert_song.bind(2, &string_option_to_value(parent)).unwrap(); + self.insert_song.bind(3, &u32_option_to_value(song.track_number)).unwrap(); + self.insert_song.bind(4, &string_option_to_value(song.title)).unwrap(); + self.insert_song.bind(5, &i32_option_to_value(song.year)).unwrap(); + self.insert_song.bind(6, &string_option_to_value(song.album_artist)).unwrap(); + self.insert_song.bind(7, &string_option_to_value(song.artist)).unwrap(); + self.insert_song.bind(8, &string_option_to_value(song.album)).unwrap(); + self.insert_song.bind(9, &string_option_to_value(song.artwork)).unwrap(); + self.insert_song.next().ok(); + } - } - } - self.db.execute("END TRANSACTION").ok(); - } + } + } + self.db.execute("END TRANSACTION").ok(); + } - fn push(&mut self, file: CollectionFile) { - if self.queue.len() == self.queue.capacity() { - self.flush(); - } - self.queue.push(file); - } + fn push(&mut self, file: CollectionFile) { + if self.queue.len() == self.queue.capacity() { + self.flush(); + } + self.queue.push(file); + } } impl<'db> Drop for IndexBuilder<'db> { - fn drop(&mut self) { + fn drop(&mut self) { self.flush(); } } impl Index { + pub fn new(path: &Path, + vfs: Arc, + album_art_pattern: &Option) + -> Result { - pub fn new(path: &Path, vfs: Arc, album_art_pattern: &Option) -> Result { + let index = Index { + path: path.to_string_lossy().deref().to_string(), + vfs: vfs, + album_art_pattern: album_art_pattern.clone(), + }; - let index = Index { - path: path.to_string_lossy().deref().to_string(), - vfs: vfs, - album_art_pattern: album_art_pattern.clone(), - }; + if path.exists() { + // Migration + } else { + index.init(); + } - if path.exists() { - // Migration - } else { - index.init(); - } + Ok(index) + } - Ok(index) - } + fn init(&self) { - fn init(&self) { + println!("Initializing index database"); - println!("Initializing index database"); - - let db = self.connect(); - db.execute("PRAGMA synchronous = NORMAL").unwrap(); - db.execute(" + let db = self.connect(); + db.execute("PRAGMA synchronous = NORMAL").unwrap(); + db.execute(" CREATE TABLE version ( id INTEGER PRIMARY KEY NOT NULL - , number INTEGER NULL + , number \ + INTEGER NULL ); INSERT INTO version (number) VALUES(1); - CREATE TABLE directories + CREATE \ + TABLE directories ( id INTEGER PRIMARY KEY NOT NULL - , path TEXT NOT NULL + , path TEXT NOT \ + NULL , parent TEXT , artist TEXT , year INTEGER , album TEXT - , artwork TEXT + \ + , artwork TEXT , UNIQUE(path) ); CREATE TABLE songs - ( id INTEGER PRIMARY KEY NOT NULL + ( id \ + INTEGER PRIMARY KEY NOT NULL , path TEXT NOT NULL - , parent TEXT NOT NULL + , parent TEXT NOT \ + NULL , track_number INTEGER , title TEXT , artist TEXT - , album_artist TEXT + , \ + album_artist TEXT , year INTEGER , album TEXT , artwork TEXT - , UNIQUE(path) + , \ + UNIQUE(path) ); - ").unwrap(); - } + ") + .unwrap(); + } - fn connect(&self) -> Connection { - let mut db = sqlite::open(self.path.clone()).unwrap(); - db.set_busy_timeout(INDEX_LOCK_TIMEOUT).ok(); - db - } + fn connect(&self) -> Connection { + let mut db = sqlite::open(self.path.clone()).unwrap(); + db.set_busy_timeout(INDEX_LOCK_TIMEOUT).ok(); + db + } - fn update_index(&self, db: &Connection) { - let start = time::Instant::now(); - println!("Beginning library index update"); - self.clean(db); - self.populate(db); - println!("Library index update took {} seconds", start.elapsed().as_secs()); - } + fn update_index(&self, db: &Connection) { + let start = time::Instant::now(); + println!("Beginning library index update"); + self.clean(db); + self.populate(db); + println!("Library index update took {} seconds", + start.elapsed().as_secs()); + } - fn clean(&self, db: &Connection) { - { - let mut select = db.prepare("SELECT path FROM songs").unwrap(); - let mut delete = db.prepare("DELETE FROM songs WHERE path = ?").unwrap(); - while let State::Row = select.next().unwrap() { - let path_string : String = select.read(0).unwrap(); - let path = Path::new(path_string.as_str()); - if !path.exists() || self.vfs.real_to_virtual(path).is_err() { - delete.reset().ok(); - delete.bind(1, &Value::String(path_string.to_owned())).ok(); - delete.next().ok(); - } - } - } + fn clean(&self, db: &Connection) { + { + let mut select = db.prepare("SELECT path FROM songs").unwrap(); + let mut delete = db.prepare("DELETE FROM songs WHERE path = ?").unwrap(); + while let State::Row = select.next().unwrap() { + let path_string: String = select.read(0).unwrap(); + let path = Path::new(path_string.as_str()); + if !path.exists() || self.vfs.real_to_virtual(path).is_err() { + delete.reset().ok(); + delete.bind(1, &Value::String(path_string.to_owned())).ok(); + delete.next().ok(); + } + } + } - { - let mut select = db.prepare("SELECT path FROM directories").unwrap(); - let mut delete = db.prepare("DELETE FROM directories WHERE path = ?").unwrap(); - while let State::Row = select.next().unwrap() { - let path_string : String = select.read(0).unwrap(); - let path = Path::new(path_string.as_str()); - if !path.exists() || self.vfs.real_to_virtual(path).is_err() { - delete.reset().ok(); - delete.bind(1, &Value::String(path_string.to_owned())).ok(); - delete.next().ok(); - } - } - } - } + { + let mut select = db.prepare("SELECT path FROM directories").unwrap(); + let mut delete = db.prepare("DELETE FROM directories WHERE path = ?").unwrap(); + while let State::Row = select.next().unwrap() { + let path_string: String = select.read(0).unwrap(); + let path = Path::new(path_string.as_str()); + if !path.exists() || self.vfs.real_to_virtual(path).is_err() { + delete.reset().ok(); + delete.bind(1, &Value::String(path_string.to_owned())).ok(); + delete.next().ok(); + } + } + } + } - fn populate(&self, db: &Connection) { - let vfs = self.vfs.deref(); - let mount_points = vfs.get_mount_points(); - let mut builder = IndexBuilder::new(db); - for (_, target) in mount_points { - self.populate_directory(&mut builder, target.as_path()); - } - } + fn populate(&self, db: &Connection) { + let vfs = self.vfs.deref(); + let mount_points = vfs.get_mount_points(); + let mut builder = IndexBuilder::new(db); + for (_, target) in mount_points { + self.populate_directory(&mut builder, target.as_path()); + } + } - fn get_artwork(&self, dir: &Path) -> Option { - let pattern = match self.album_art_pattern { - Some(ref p) => p, - _ => return None, - }; + fn get_artwork(&self, dir: &Path) -> Option { + let pattern = match self.album_art_pattern { + Some(ref p) => p, + _ => return None, + }; - if let Ok(dir_content) = fs::read_dir(dir) { - for file in dir_content { - if let Ok(file) = file { - if let Some(name_string) = file.file_name().to_str() { - if pattern.is_match(name_string) { - return file.path().to_str().map(|p| p.to_owned()); - } - } - } - } - } + if let Ok(dir_content) = fs::read_dir(dir) { + for file in dir_content { + if let Ok(file) = file { + if let Some(name_string) = file.file_name().to_str() { + if pattern.is_match(name_string) { + return file.path().to_str().map(|p| p.to_owned()); + } + } + } + } + } - None - } + None + } - fn populate_directory(&self, builder: &mut IndexBuilder, path: &Path) { - - // Find artwork - let artwork = self.get_artwork(path); + fn populate_directory(&self, builder: &mut IndexBuilder, path: &Path) { - let path_string = match path.to_str() { - Some(p) => p, - _ => return, - }; - - let mut directory_album = None; - let mut directory_year = None; - let mut directory_artist = None; - let mut inconsistent_directory_album = false; - let mut inconsistent_directory_year = false; - let mut inconsistent_directory_artist = false; + // Find artwork + let artwork = self.get_artwork(path); - // Insert content - if let Ok(dir_content) = fs::read_dir(path) { - for file in dir_content { - let file_path = match file { - Ok(f) => f.path(), - _ => continue, - }; + let path_string = match path.to_str() { + Some(p) => p, + _ => return, + }; - if file_path.is_dir() { - self.populate_directory(builder, file_path.as_path()); - } else { - if let Some(file_path_string) = file_path.to_str() { - if let Ok(tags) = SongTags::read(file_path.as_path()) { - if tags.year.is_some() { - inconsistent_directory_year |= directory_year.is_some() && directory_year != tags.year; - directory_year = tags.year; - } + let mut directory_album = None; + let mut directory_year = None; + let mut directory_artist = None; + let mut inconsistent_directory_album = false; + let mut inconsistent_directory_year = false; + let mut inconsistent_directory_artist = false; - if tags.album.is_some() { - inconsistent_directory_album |= directory_album.is_some() && directory_album != tags.album; - directory_album = Some(tags.album.as_ref().unwrap().clone()); - } + // Insert content + if let Ok(dir_content) = fs::read_dir(path) { + for file in dir_content { + let file_path = match file { + Ok(f) => f.path(), + _ => continue, + }; - if tags.album_artist.is_some() { - inconsistent_directory_artist |= directory_artist.is_some() && directory_artist != tags.album_artist; - directory_artist = Some(tags.album_artist.as_ref().unwrap().clone()); - } else if tags.artist.is_some() { - inconsistent_directory_artist |= directory_artist.is_some() && directory_artist != tags.artist; - directory_artist = Some(tags.artist.as_ref().unwrap().clone()); - } + if file_path.is_dir() { + self.populate_directory(builder, file_path.as_path()); + } else { + if let Some(file_path_string) = file_path.to_str() { + if let Ok(tags) = SongTags::read(file_path.as_path()) { + if tags.year.is_some() { + inconsistent_directory_year |= directory_year.is_some() && + directory_year != tags.year; + directory_year = tags.year; + } - let song = Song { - path: file_path_string.to_owned(), - track_number: tags.track_number, - title: tags.title, - artist: tags.artist, - album_artist: tags.album_artist, - album: tags.album, - year: tags.year, - artwork: artwork.as_ref().map(|s| s.to_owned()), - }; + if tags.album.is_some() { + inconsistent_directory_album |= directory_album.is_some() && + directory_album != tags.album; + directory_album = Some(tags.album.as_ref().unwrap().clone()); + } - builder.push(CollectionFile::Song(song)); - } - } - } - } - } + if tags.album_artist.is_some() { + inconsistent_directory_artist |= directory_artist.is_some() && + directory_artist != + tags.album_artist; + directory_artist = + Some(tags.album_artist.as_ref().unwrap().clone()); + } else if tags.artist.is_some() { + inconsistent_directory_artist |= directory_artist.is_some() && + directory_artist != tags.artist; + directory_artist = Some(tags.artist.as_ref().unwrap().clone()); + } - // Insert directory - if inconsistent_directory_year { - directory_year = None; - } - if inconsistent_directory_album { - directory_album = None; - } - if inconsistent_directory_artist { - directory_artist = None; - } + let song = Song { + path: file_path_string.to_owned(), + track_number: tags.track_number, + title: tags.title, + artist: tags.artist, + album_artist: tags.album_artist, + album: tags.album, + year: tags.year, + artwork: artwork.as_ref().map(|s| s.to_owned()), + }; - let directory = Directory { - path: path_string.to_owned(), - artwork: artwork, - album: directory_album, - artist: directory_artist, - year: directory_year, - }; - builder.push(CollectionFile::Directory(directory)); - } + builder.push(CollectionFile::Song(song)); + } + } + } + } + } - pub fn run(&self) - { - loop { - { - let db = self.connect(); - self.update_index(&db); - } - thread::sleep(time::Duration::from_secs(60 * 20)); // TODO expose in configuration - } - } + // Insert directory + if inconsistent_directory_year { + directory_year = None; + } + if inconsistent_directory_album { + directory_album = None; + } + if inconsistent_directory_artist { + directory_artist = None; + } - fn select_songs(&self, select: &mut Statement) -> Vec { + let directory = Directory { + path: path_string.to_owned(), + artwork: artwork, + album: directory_album, + artist: directory_artist, + year: directory_year, + }; + builder.push(CollectionFile::Directory(directory)); + } - let mut output = Vec::new(); + pub fn run(&self) { + loop { + { + let db = self.connect(); + self.update_index(&db); + } + thread::sleep(time::Duration::from_secs(60 * 20)); // TODO expose in configuration + } + } - while let State::Row = select.next().unwrap() { + fn select_songs(&self, select: &mut Statement) -> Vec { - let song_path : String = select.read(0).unwrap(); - let track_number : Value = select.read(1).unwrap(); - let title : Value = select.read(2).unwrap(); - let year : Value = select.read(3).unwrap(); - let album_artist : Value = select.read(4).unwrap(); - let artist : Value = select.read(5).unwrap(); - let album : Value = select.read(6).unwrap(); - let artwork : Value = select.read(7).unwrap(); + let mut output = Vec::new(); - let song_path = Path::new(song_path.as_str()); - let song_path = match self.vfs.real_to_virtual(song_path) { - Ok(p) => p, - _ => continue, - }; + while let State::Row = select.next().unwrap() { - let artwork = artwork.as_string().map(|p| Path::new(p)).and_then(|p| self.vfs.real_to_virtual(p).ok()); + let song_path: String = select.read(0).unwrap(); + let track_number: Value = select.read(1).unwrap(); + let title: Value = select.read(2).unwrap(); + let year: Value = select.read(3).unwrap(); + let album_artist: Value = select.read(4).unwrap(); + let artist: Value = select.read(5).unwrap(); + let album: Value = select.read(6).unwrap(); + let artwork: Value = select.read(7).unwrap(); - let song = Song { - path: song_path.to_str().unwrap().to_owned(), - track_number: track_number.as_integer().map(|n| n as u32), - title: title.as_string().map(|s| s.to_owned()), - year: year.as_integer().map(|n| n as i32), - album_artist: album_artist.as_string().map(|s| s.to_owned()), - artist: artist.as_string().map(|s| s.to_owned()), - album: album.as_string().map(|s| s.to_owned()), - artwork: artwork.map(|p| p.to_str().unwrap().to_owned() ), - }; - output.push(song); - } + let song_path = Path::new(song_path.as_str()); + let song_path = match self.vfs.real_to_virtual(song_path) { + Ok(p) => p, + _ => continue, + }; - output - } + let artwork = artwork.as_string() + .map(|p| Path::new(p)) + .and_then(|p| self.vfs.real_to_virtual(p).ok()); - // List sub-directories within a directory - fn browse_directories(&self, real_path: &Path) -> Vec { - let db = self.connect(); - let mut output = Vec::new(); + let song = Song { + path: song_path.to_str().unwrap().to_owned(), + track_number: track_number.as_integer().map(|n| n as u32), + title: title.as_string().map(|s| s.to_owned()), + year: year.as_integer().map(|n| n as i32), + album_artist: album_artist.as_string().map(|s| s.to_owned()), + artist: artist.as_string().map(|s| s.to_owned()), + album: album.as_string().map(|s| s.to_owned()), + artwork: artwork.map(|p| p.to_str().unwrap().to_owned()), + }; + output.push(song); + } - let path_string = real_path.to_string_lossy(); - let mut select = db.prepare("SELECT path, artwork, year, artist, album FROM directories WHERE parent = ? ORDER BY path COLLATE NOCASE ASC").unwrap(); - select.bind(1, &Value::String(path_string.deref().to_owned())).unwrap(); + output + } - while let State::Row = select.next().unwrap() { + // List sub-directories within a directory + fn browse_directories(&self, real_path: &Path) -> Vec { + let db = self.connect(); + let mut output = Vec::new(); - let directory_value : String = select.read(0).unwrap(); - let artwork_path : Value = select.read(1).unwrap(); - let year : Value = select.read(2).unwrap(); - let artist : Value = select.read(3).unwrap(); - let album : Value = select.read(4).unwrap(); + let path_string = real_path.to_string_lossy(); + let mut select = + db.prepare("SELECT path, artwork, year, artist, album FROM directories WHERE \ + parent = ? ORDER BY path COLLATE NOCASE ASC") + .unwrap(); + select.bind(1, &Value::String(path_string.deref().to_owned())).unwrap(); - let directory_path = Path::new(directory_value.as_str()); - let directory_path = match self.vfs.real_to_virtual(directory_path) { - Ok(p) => p, - _ => continue, - }; + while let State::Row = select.next().unwrap() { - let artwork_path = artwork_path.as_string() - .map(|p| Path::new(p)) - .and_then(|p| self.vfs.real_to_virtual(p).ok()); + let directory_value: String = select.read(0).unwrap(); + let artwork_path: Value = select.read(1).unwrap(); + let year: Value = select.read(2).unwrap(); + let artist: Value = select.read(3).unwrap(); + let album: Value = select.read(4).unwrap(); - let directory = Directory { - path: directory_path.to_str().unwrap().to_owned(), - artwork: artwork_path.map(|p| p.to_str().unwrap().to_owned() ), - year: year.as_integer().map(|n| n as i32), - artist: artist.as_string().map(|s| s.to_owned()), - album: album.as_string().map(|s| s.to_owned()), - }; - output.push(CollectionFile::Directory(directory)); - } + let directory_path = Path::new(directory_value.as_str()); + let directory_path = match self.vfs.real_to_virtual(directory_path) { + Ok(p) => p, + _ => continue, + }; - output - } + let artwork_path = artwork_path.as_string() + .map(|p| Path::new(p)) + .and_then(|p| self.vfs.real_to_virtual(p).ok()); - // List songs within a directory - fn browse_songs(&self, real_path: &Path) -> Vec { - let db = self.connect(); - let path_string = real_path.to_string_lossy(); - let mut select = db.prepare("SELECT path, track_number, title, year, album_artist, artist, album, artwork FROM songs WHERE parent = ? ORDER BY path COLLATE NOCASE ASC").unwrap(); - select.bind(1, &Value::String(path_string.deref().to_owned())).unwrap(); - self.select_songs(&mut select).into_iter().map(|s| CollectionFile::Song(s)).collect() - } + let directory = Directory { + path: directory_path.to_str().unwrap().to_owned(), + artwork: artwork_path.map(|p| p.to_str().unwrap().to_owned()), + year: year.as_integer().map(|n| n as i32), + artist: artist.as_string().map(|s| s.to_owned()), + album: album.as_string().map(|s| s.to_owned()), + }; + output.push(CollectionFile::Directory(directory)); + } - pub fn browse(&self, virtual_path: &Path) -> Result, PError> { + output + } - let mut output = Vec::new(); + // List songs within a directory + fn browse_songs(&self, real_path: &Path) -> Vec { + let db = self.connect(); + let path_string = real_path.to_string_lossy(); + let mut select = + db.prepare("SELECT path, track_number, title, year, album_artist, artist, album, \ + artwork FROM songs WHERE parent = ? ORDER BY path COLLATE NOCASE ASC") + .unwrap(); + select.bind(1, &Value::String(path_string.deref().to_owned())).unwrap(); + self.select_songs(&mut select).into_iter().map(|s| CollectionFile::Song(s)).collect() + } - // Browse top-level - if virtual_path.components().count() == 0 { - for (n, _) in self.vfs.get_mount_points() { - let directory = Directory { - path: n.to_owned(), - artwork: None, - year: None, - artist: None, - album: None, - }; - output.push(CollectionFile::Directory(directory)); - } + pub fn browse(&self, virtual_path: &Path) -> Result, PError> { - // Browse sub-directory - } else { - let real_path = try!(self.vfs.virtual_to_real(virtual_path)); - let directories = self.browse_directories(real_path.as_path()); - let songs = self.browse_songs(real_path.as_path()); - output.extend(directories); - output.extend(songs); - } + let mut output = Vec::new(); - Ok(output) - } + // Browse top-level + if virtual_path.components().count() == 0 { + for (n, _) in self.vfs.get_mount_points() { + let directory = Directory { + path: n.to_owned(), + artwork: None, + year: None, + artist: None, + album: None, + }; + output.push(CollectionFile::Directory(directory)); + } - pub fn flatten(&self, virtual_path: &Path) -> Result, PError> { - let db = self.connect(); - let real_path = try!(self.vfs.virtual_to_real(virtual_path)); - let path_string = real_path.to_string_lossy().into_owned() + "%"; - let mut select = db.prepare("SELECT path, track_number, title, year, album_artist, artist, album, artwork FROM songs WHERE path LIKE ? ORDER BY path COLLATE NOCASE ASC").unwrap(); - select.bind(1, &Value::String(path_string.deref().to_owned())).unwrap(); - Ok(self.select_songs(&mut select)) - } + // Browse sub-directory + } else { + let real_path = try!(self.vfs.virtual_to_real(virtual_path)); + let directories = self.browse_directories(real_path.as_path()); + let songs = self.browse_songs(real_path.as_path()); + output.extend(directories); + output.extend(songs); + } + + Ok(output) + } + + pub fn flatten(&self, virtual_path: &Path) -> Result, PError> { + let db = self.connect(); + let real_path = try!(self.vfs.virtual_to_real(virtual_path)); + let path_string = real_path.to_string_lossy().into_owned() + "%"; + let mut select = + db.prepare("SELECT path, track_number, title, year, album_artist, artist, album, \ + artwork FROM songs WHERE path LIKE ? ORDER BY path COLLATE NOCASE ASC") + .unwrap(); + select.bind(1, &Value::String(path_string.deref().to_owned())).unwrap(); + Ok(self.select_songs(&mut select)) + } } diff --git a/src/main.rs b/src/main.rs index 1899d43..de2cdc5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,7 +70,8 @@ fn main() { // 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.album_art_pattern).unwrap()); + let index = Arc::new(index::Index::new(&index_path, vfs.clone(), &config.album_art_pattern) + .unwrap()); let index_ref = index.clone(); std::thread::spawn(move || index_ref.run()); @@ -104,8 +105,8 @@ fn main() { std::thread::spawn(|| { ddns::run(ddns_config); }); - }, - None => (), + } + None => (), }; // Run UI diff --git a/src/thumbnails.rs b/src/thumbnails.rs index 2729eaf..a85354e 100644 --- a/src/thumbnails.rs +++ b/src/thumbnails.rs @@ -14,42 +14,49 @@ use error::*; const THUMBNAILS_PATH: &'static str = "tmp/thumbnails"; fn hash(path: &Path, dimension: u32) -> u64 { - let path_string = path.to_string_lossy(); - let hash_input = format!("{}:{}", path_string, dimension.to_string()); - let mut hasher = DefaultHasher::new(); + let path_string = path.to_string_lossy(); + let hash_input = format!("{}:{}", path_string, dimension.to_string()); + let mut hasher = DefaultHasher::new(); hash_input.hash(&mut hasher); hasher.finish() } pub fn get_thumbnail(real_path: &Path, max_dimension: u32) -> Result { - let mut out_path = PathBuf::new(); - out_path.push(THUMBNAILS_PATH); - let mut dir_builder = DirBuilder::new(); - dir_builder.recursive(true); - try!(dir_builder.create(out_path.as_path())); + let mut out_path = PathBuf::new(); + out_path.push(THUMBNAILS_PATH); + let mut dir_builder = DirBuilder::new(); + dir_builder.recursive(true); + try!(dir_builder.create(out_path.as_path())); - let source_image = try!(image::open(real_path)); - let (source_width, source_height) = source_image.dimensions(); - let cropped_dimension = cmp::max(source_width, source_height); - let out_dimension = cmp::min(max_dimension, cropped_dimension); + let source_image = try!(image::open(real_path)); + let (source_width, source_height) = source_image.dimensions(); + let cropped_dimension = cmp::max(source_width, source_height); + let out_dimension = cmp::min(max_dimension, cropped_dimension); - let hash = hash(real_path, out_dimension); - out_path.push(format!("{}.png", hash.to_string())); + let hash = hash(real_path, out_dimension); + out_path.push(format!("{}.png", hash.to_string())); - if !out_path.exists() { - let source_aspect_ratio : f32 = source_width as f32 / source_height as f32; - if source_aspect_ratio < 0.8 || source_aspect_ratio > 1.2 { - let mut cropped_image = ImageBuffer::new(cropped_dimension, cropped_dimension); - cropped_image.copy_from(&source_image, (cropped_dimension - source_width)/2, (cropped_dimension - source_height)/2); - let out_image = resize(&cropped_image, out_dimension, out_dimension, FilterType::Lanczos3); - try!(out_image.save(out_path.as_path())); - } else { - let out_image = resize(&source_image, out_dimension, out_dimension, FilterType::Lanczos3); - try!(out_image.save(out_path.as_path())); - } - } + if !out_path.exists() { + let source_aspect_ratio: f32 = source_width as f32 / source_height as f32; + if source_aspect_ratio < 0.8 || source_aspect_ratio > 1.2 { + let mut cropped_image = ImageBuffer::new(cropped_dimension, cropped_dimension); + cropped_image.copy_from(&source_image, + (cropped_dimension - source_width) / 2, + (cropped_dimension - source_height) / 2); + let out_image = resize(&cropped_image, + out_dimension, + out_dimension, + FilterType::Lanczos3); + try!(out_image.save(out_path.as_path())); + } else { + let out_image = resize(&source_image, + out_dimension, + out_dimension, + FilterType::Lanczos3); + try!(out_image.save(out_path.as_path())); + } + } - Ok(out_path) + Ok(out_path) } - diff --git a/src/utils.rs b/src/utils.rs index 268ad96..5de7452 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,51 +1,51 @@ use std::path::Path; pub enum AudioFormat { - FLAC, - MP3, - MP4, - MPC, - OGG, + FLAC, + MP3, + MP4, + MPC, + OGG, } pub fn get_audio_format(path: &Path) -> Option { - let extension = match path.extension() { - Some(e) => e, - _ => return None, - }; - let extension = match extension.to_str() { - Some(e) => e, - _ => return None, - }; - match extension.to_lowercase().as_str() { - "flac" => Some(AudioFormat::FLAC), - "mp3" => Some(AudioFormat::MP3), - "m4a" => Some(AudioFormat::MP4), - "mpc" => Some(AudioFormat::MPC), - "ogg" => Some(AudioFormat::OGG), - _ => None, - } + let extension = match path.extension() { + Some(e) => e, + _ => return None, + }; + let extension = match extension.to_str() { + Some(e) => e, + _ => return None, + }; + match extension.to_lowercase().as_str() { + "flac" => Some(AudioFormat::FLAC), + "mp3" => Some(AudioFormat::MP3), + "m4a" => Some(AudioFormat::MP4), + "mpc" => Some(AudioFormat::MPC), + "ogg" => Some(AudioFormat::OGG), + _ => None, + } } pub fn is_song(path: &Path) -> bool { - get_audio_format(path).is_some() + get_audio_format(path).is_some() } pub fn is_image(path: &Path) -> bool { - let extension = match path.extension() { - Some(e) => e, - _ => return false, - }; - let extension = match extension.to_str() { - Some(e) => e, - _ => return false, - }; - match extension.to_lowercase().as_str() { - "png" => true, - "gif" => true, - "jpg" => true, - "jpeg" => true, - "bmp" => true, - _ => false, - } -} \ No newline at end of file + let extension = match path.extension() { + Some(e) => e, + _ => return false, + }; + let extension = match extension.to_str() { + Some(e) => e, + _ => return false, + }; + match extension.to_lowercase().as_str() { + "png" => true, + "gif" => true, + "jpg" => true, + "jpeg" => true, + "bmp" => true, + _ => false, + } +} diff --git a/src/vfs.rs b/src/vfs.rs index d5e49e3..4b4e6d7 100644 --- a/src/vfs.rs +++ b/src/vfs.rs @@ -6,14 +6,12 @@ use error::*; #[derive(Debug, Clone)] pub struct VfsConfig { - pub mount_points: HashMap, + pub mount_points: HashMap, } impl VfsConfig { pub fn new() -> VfsConfig { - VfsConfig { - mount_points: HashMap::new(), - } + VfsConfig { mount_points: HashMap::new() } } } @@ -43,11 +41,13 @@ impl Vfs { for (name, target) in &self.mount_points { let mount_path = Path::new(&name); match virtual_path.strip_prefix(mount_path) { - Ok(p) => return if p.components().count() == 0 { - Ok(target.clone()) - } else { - Ok(target.join(p)) - }, + Ok(p) => { + return if p.components().count() == 0 { + Ok(target.clone()) + } else { + Ok(target.join(p)) + } + } Err(_) => (), } }