From 0297b351bf592577a0b2a3254a97048a976bcb94 Mon Sep 17 00:00:00 2001 From: Antoine Gersant <antoine.gersant@lesforges.org> Date: Sat, 6 Oct 2018 15:46:30 -0700 Subject: [PATCH] Rustfmt --- src/api.rs | 188 ++++++++++++++++++++++++--------------------- src/config.rs | 182 +++++++++++++++++++++---------------------- src/db/mod.rs | 20 +++-- src/ddns.rs | 26 +++---- src/errors.rs | 84 ++++++++++---------- src/index.rs | 171 ++++++++++++++++++++++------------------- src/lastfm.rs | 42 +++++----- src/main.rs | 53 +++++++------ src/metadata.rs | 64 +++++++-------- src/playlist.rs | 1 + src/serve.rs | 59 +++++++------- src/thumbnails.rs | 11 +-- src/ui/headless.rs | 2 +- src/ui/windows.rs | 114 ++++++++++++++------------- src/user.rs | 60 +++++++++------ src/utils.rs | 19 +++-- src/vfs.rs | 26 ++++--- 17 files changed, 592 insertions(+), 530 deletions(-) diff --git a/src/api.rs b/src/api.rs index fa189dc..48d3635 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,39 +1,38 @@ use diesel::prelude::*; -use iron::prelude::*; use iron::headers::{Authorization, Basic, Range}; -use iron::{AroundMiddleware, Handler, status}; +use iron::prelude::*; +use iron::{status, AroundMiddleware, Handler}; use mount::Mount; -use router::Router; use params; -use secure_session::middleware::{SessionMiddleware, SessionConfig}; -use secure_session::session::{SessionManager, ChaCha20Poly1305SessionManager}; +use router::Router; +use secure_session::middleware::{SessionConfig, SessionMiddleware}; +use secure_session::session::{ChaCha20Poly1305SessionManager, SessionManager}; use serde_json; use std::fs; use std::io; -use std::path::*; use std::ops::Deref; -use std::sync::{Arc, Mutex}; +use std::path::*; use std::sync::mpsc::Sender; +use std::sync::{Arc, Mutex}; use typemap; use url::percent_encoding::percent_decode; use config; -use db::{ConnectionSource, DB}; use db::misc_settings; +use db::{ConnectionSource, DB}; use errors::*; use index; use lastfm; use playlist; -use user; use serve; use thumbnails::*; +use user; use utils::*; use vfs::VFSSource; const CURRENT_MAJOR_VERSION: i32 = 2; const CURRENT_MINOR_VERSION: i32 = 2; - #[derive(Deserialize, Serialize)] struct Session { username: String, @@ -46,7 +45,8 @@ impl typemap::Key for SessionKey { } fn get_auth_secret<T>(db: &T) -> Result<String> - where T: ConnectionSource +where + T: ConnectionSource, { use self::misc_settings::dsl::*; let connection = db.get_connection(); @@ -62,11 +62,11 @@ pub fn get_handler(db: Arc<DB>, index: Arc<Mutex<Sender<index::Command>>>) -> Re let session_manager = ChaCha20Poly1305SessionManager::<Session>::from_password(auth_secret.as_bytes()); let session_config = SessionConfig::default(); - let session_middleware = - SessionMiddleware::<Session, - SessionKey, - ChaCha20Poly1305SessionManager<Session>>::new(session_manager, - session_config); + let session_middleware = SessionMiddleware::< + Session, + SessionKey, + ChaCha20Poly1305SessionManager<Session>, + >::new(session_manager, session_config); api_chain.link_around(session_middleware); Ok(api_chain) @@ -79,8 +79,9 @@ fn get_endpoints(db: Arc<DB>, index_channel: Arc<Mutex<Sender<index::Command>>>) api_handler.mount("/version/", self::version); { let db = db.clone(); - api_handler.mount("/auth/", - move |request: &mut Request| self::auth(request, db.deref())); + api_handler.mount("/auth/", move |request: &mut Request| { + self::auth(request, db.deref()) + }); } { let db = db.clone(); @@ -94,64 +95,70 @@ fn get_endpoints(db: Arc<DB>, index_channel: Arc<Mutex<Sender<index::Command>>>) let mut auth_api_mount = Mount::new(); { let db = db.clone(); - auth_api_mount.mount("/browse/", - move |request: &mut Request| self::browse(request, db.deref())); + auth_api_mount.mount("/browse/", move |request: &mut Request| { + self::browse(request, db.deref()) + }); } { let db = db.clone(); - auth_api_mount.mount("/flatten/", - move |request: &mut Request| self::flatten(request, db.deref())); + auth_api_mount.mount("/flatten/", move |request: &mut Request| { + self::flatten(request, db.deref()) + }); } { let db = db.clone(); - auth_api_mount.mount("/random/", - move |request: &mut Request| self::random(request, db.deref())); + auth_api_mount.mount("/random/", move |request: &mut Request| { + self::random(request, db.deref()) + }); } { let db = db.clone(); - auth_api_mount.mount("/recent/", - move |request: &mut Request| self::recent(request, db.deref())); + auth_api_mount.mount("/recent/", move |request: &mut Request| { + self::recent(request, db.deref()) + }); } { let db = db.clone(); - auth_api_mount.mount("/search/", - move |request: &mut Request| self::search(request, db.deref())); + auth_api_mount.mount("/search/", move |request: &mut Request| { + self::search(request, db.deref()) + }); } { let db = db.clone(); - auth_api_mount.mount("/serve/", - move |request: &mut Request| self::serve(request, db.deref())); + auth_api_mount.mount("/serve/", move |request: &mut Request| { + self::serve(request, db.deref()) + }); } { let mut preferences_router = Router::new(); let get_db = db.clone(); let put_db = db.clone(); - preferences_router.get("/", - move |request: &mut Request| { - self::get_preferences(request, get_db.deref()) - }, - "get_preferences"); - preferences_router.put("/", - move |request: &mut Request| { - self::put_preferences(request, put_db.deref()) - }, - "put_preferences"); + preferences_router.get( + "/", + move |request: &mut Request| self::get_preferences(request, get_db.deref()), + "get_preferences", + ); + preferences_router.put( + "/", + move |request: &mut Request| self::put_preferences(request, put_db.deref()), + "put_preferences", + ); auth_api_mount.mount("/preferences/", preferences_router); } { let mut settings_router = Router::new(); let get_db = db.clone(); let put_db = db.clone(); - settings_router.get("/", - move |request: &mut Request| { - self::get_config(request, get_db.deref()) - }, - "get_config"); - settings_router.put("/", - move |request: &mut Request| { - self::put_config(request, put_db.deref()) - }, - "put_config"); + settings_router.get( + "/", + move |request: &mut Request| self::get_config(request, get_db.deref()), + "get_config", + ); + settings_router.put( + "/", + move |request: &mut Request| self::put_config(request, put_db.deref()), + "put_config", + ); let mut settings_api_chain = Chain::new(settings_router); let admin_req = AdminRequirement { db: db.clone() }; @@ -162,9 +169,11 @@ fn get_endpoints(db: Arc<DB>, index_channel: Arc<Mutex<Sender<index::Command>>>) { let index_channel = index_channel.clone(); let mut reindex_router = Router::new(); - reindex_router.post("/", - move |_: &mut Request| self::trigger_index(index_channel.deref()), - "trigger_index"); + reindex_router.post( + "/", + move |_: &mut Request| self::trigger_index(index_channel.deref()), + "trigger_index", + ); let mut reindex_api_chain = Chain::new(reindex_router); let admin_req = AdminRequirement { db: db.clone() }; @@ -178,29 +187,29 @@ fn get_endpoints(db: Arc<DB>, index_channel: Arc<Mutex<Sender<index::Command>>>) let list_db = db.clone(); let read_db = db.clone(); let delete_db = db.clone(); - playlist_router.put("/", - move |request: &mut Request| { - self::save_playlist(request, put_db.deref()) - }, - "save_playlist"); + playlist_router.put( + "/", + move |request: &mut Request| self::save_playlist(request, put_db.deref()), + "save_playlist", + ); - playlist_router.get("/list", - move |request: &mut Request| { - self::list_playlists(request, list_db.deref()) - }, - "list_playlists"); + playlist_router.get( + "/list", + move |request: &mut Request| self::list_playlists(request, list_db.deref()), + "list_playlists", + ); - playlist_router.get("/read/:playlist_name", - move |request: &mut Request| { - self::read_playlist(request, read_db.deref()) - }, - "read_playlist"); + playlist_router.get( + "/read/:playlist_name", + move |request: &mut Request| self::read_playlist(request, read_db.deref()), + "read_playlist", + ); - playlist_router.delete("/:playlist_name", - move |request: &mut Request| { - self::delete_playlist(request, delete_db.deref()) - }, - "delete_playlist"); + playlist_router.delete( + "/:playlist_name", + move |request: &mut Request| self::delete_playlist(request, delete_db.deref()), + "delete_playlist", + ); auth_api_mount.mount("/playlist/", playlist_router); } @@ -249,9 +258,9 @@ struct AuthRequirement { impl AroundMiddleware for AuthRequirement { fn around(self, handler: Box<Handler>) -> Box<Handler> { Box::new(AuthHandler { - db: self.db, - handler: handler, - }) as Box<Handler> + db: self.db, + handler: handler, + }) as Box<Handler> } } @@ -277,8 +286,9 @@ impl Handler for AuthHandler { auth_success = user::auth(self.db.deref(), auth.username.as_str(), password.as_str())?; if auth_success { - req.extensions - .insert::<SessionKey>(Session { username: auth.username.clone() }); + req.extensions.insert::<SessionKey>(Session { + username: auth.username.clone(), + }); } } } @@ -299,7 +309,6 @@ impl Handler for AuthHandler { } } - struct AdminRequirement { db: Arc<DB>, } @@ -307,9 +316,9 @@ struct AdminRequirement { impl AroundMiddleware for AdminRequirement { fn around(self, handler: Box<Handler>) -> Box<Handler> { Box::new(AdminHandler { - db: self.db, - handler: handler, - }) as Box<Handler> + db: self.db, + handler: handler, + }) as Box<Handler> } } @@ -368,7 +377,9 @@ fn initial_setup(_: &mut Request, db: &DB) -> IronResult<Response> { has_any_users: bool, }; - let initial_setup = InitialSetup { has_any_users: user::count(db)? > 0 }; + let initial_setup = InitialSetup { + has_any_users: user::count(db)? > 0, + }; match serde_json::to_string(&initial_setup) { Ok(result_json) => Ok(Response::with((status::Ok, result_json))), @@ -395,16 +406,18 @@ fn auth(request: &mut Request, db: &DB) -> IronResult<Response> { return Err(Error::from(ErrorKind::IncorrectCredentials).into()); } - request - .extensions - .insert::<SessionKey>(Session { username: username.clone() }); + request.extensions.insert::<SessionKey>(Session { + username: username.clone(), + }); #[derive(Serialize)] struct AuthOutput { admin: bool, } - let auth_output = AuthOutput { admin: user::is_admin(db.deref(), &username)? }; + let auth_output = AuthOutput { + admin: user::is_admin(db.deref(), &username)?, + }; let result_json = serde_json::to_string(&auth_output); let result_json = match result_json { Ok(j) => j, @@ -602,7 +615,6 @@ fn trigger_index(channel: &Mutex<Sender<index::Command>>) -> IronResult<Response } fn save_playlist(request: &mut Request, db: &DB) -> IronResult<Response> { - let username = match request.extensions.get::<SessionKey>() { Some(s) => s.username.clone(), None => return Err(Error::from(ErrorKind::AuthenticationRequired).into()), diff --git a/src/config.rs b/src/config.rs index 7cb62bb..240c68f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -8,8 +8,8 @@ use std::io::Read; use std::path; use toml; -use db::DB; use db::ConnectionSource; +use db::DB; use db::{ddns_config, misc_settings, mount_points, users}; use ddns::DDNSConfig; use errors::*; @@ -76,10 +76,11 @@ pub fn parse_toml_file(path: &path::Path) -> Result<Config> { } pub fn read<T>(db: &T) -> Result<Config> - where T: ConnectionSource +where + T: ConnectionSource, { - use self::misc_settings::dsl::*; use self::ddns_config::dsl::*; + use self::misc_settings::dsl::*; let connection = db.get_connection(); @@ -93,8 +94,11 @@ pub fn read<T>(db: &T) -> Result<Config> }; let (art_pattern, sleep_duration, url) = misc_settings - .select((index_album_art_pattern, index_sleep_duration_seconds, prefix_url)) - .get_result(connection.deref())?; + .select(( + index_album_art_pattern, + index_sleep_duration_seconds, + prefix_url, + )).get_result(connection.deref())?; config.album_art_pattern = Some(art_pattern); config.reindex_every_n_seconds = Some(sleep_duration); config.prefix_url = if url != "" { Some(url) } else { None }; @@ -111,16 +115,15 @@ pub fn read<T>(db: &T) -> Result<Config> let found_users: Vec<(String, i32)> = users::table .select((users::columns::name, users::columns::admin)) .get_results(connection.deref())?; - config.users = Some(found_users - .into_iter() - .map(|(name, admin)| { - ConfigUser { - name: name, - password: "".to_owned(), - admin: admin != 0, - } - }) - .collect::<_>()); + config.users = Some( + found_users + .into_iter() + .map(|(name, admin)| ConfigUser { + name: name, + password: "".to_owned(), + admin: admin != 0, + }).collect::<_>(), + ); let ydns = ddns_config .select((host, username, password)) @@ -131,13 +134,13 @@ pub fn read<T>(db: &T) -> Result<Config> } fn reset<T>(db: &T) -> Result<()> - where T: ConnectionSource +where + T: ConnectionSource, { use self::ddns_config::dsl::*; let connection = db.get_connection(); - diesel::delete(mount_points::table) - .execute(connection.deref())?; + diesel::delete(mount_points::table).execute(connection.deref())?; diesel::delete(users::table).execute(connection.deref())?; diesel::update(ddns_config) .set((host.eq(""), username.eq(""), password.eq(""))) @@ -147,20 +150,21 @@ fn reset<T>(db: &T) -> Result<()> } pub fn overwrite<T>(db: &T, new_config: &Config) -> Result<()> - where T: ConnectionSource +where + T: ConnectionSource, { reset(db)?; amend(db, new_config) } pub fn amend<T>(db: &T, new_config: &Config) -> Result<()> - where T: ConnectionSource +where + T: ConnectionSource, { let connection = db.get_connection(); if let Some(ref mount_dirs) = new_config.mount_dirs { - diesel::delete(mount_points::table) - .execute(connection.deref())?; + diesel::delete(mount_points::table).execute(connection.deref())?; diesel::insert_into(mount_points::table) .values(mount_dirs) .execute(connection.deref())?; @@ -175,12 +179,7 @@ pub fn amend<T>(db: &T, new_config: &Config) -> Result<()> let delete_usernames: Vec<String> = old_usernames .iter() .cloned() - .filter(|old_name| { - config_users - .iter() - .find(|u| &u.name == old_name) - .is_none() - }) + .filter(|old_name| config_users.iter().find(|u| &u.name == old_name).is_none()) .collect::<_>(); diesel::delete(users::table.filter(users::name.eq_any(&delete_usernames))) .execute(connection.deref())?; @@ -189,12 +188,11 @@ pub fn amend<T>(db: &T, new_config: &Config) -> Result<()> let insert_users: Vec<&ConfigUser> = config_users .iter() .filter(|u| { - old_usernames - .iter() - .find(|old_name| *old_name == &u.name) - .is_none() - }) - .collect::<_>(); + old_usernames + .iter() + .find(|old_name| *old_name == &u.name) + .is_none() + }).collect::<_>(); for ref config_user in insert_users { let new_user = User::new(&config_user.name, &config_user.password); diesel::insert_into(users::table) @@ -238,10 +236,11 @@ pub fn amend<T>(db: &T, new_config: &Config) -> Result<()> if let Some(ref ydns) = new_config.ydns { use self::ddns_config::dsl::*; diesel::update(ddns_config) - .set((host.eq(ydns.host.clone()), - username.eq(ydns.username.clone()), - password.eq(ydns.password.clone()))) - .execute(connection.deref())?; + .set(( + host.eq(ydns.host.clone()), + username.eq(ydns.username.clone()), + password.eq(ydns.password.clone()), + )).execute(connection.deref())?; } if let Some(ref prefix_url) = new_config.prefix_url { @@ -254,13 +253,15 @@ pub fn amend<T>(db: &T, new_config: &Config) -> Result<()> } pub fn read_preferences<T>(_: &T, _: &str) -> Result<Preferences> - where T: ConnectionSource +where + T: ConnectionSource, { Ok(Preferences {}) } pub fn write_preferences<T>(_: &T, _: &str, _: &Preferences) -> Result<()> - where T: ConnectionSource +where + T: ConnectionSource, { Ok(()) } @@ -294,14 +295,14 @@ fn test_amend() { reindex_every_n_seconds: Some(123), prefix_url: None, mount_dirs: Some(vec![MountPoint { - source: "C:\\Music".into(), - name: "root".into(), - }]), + source: "C:\\Music".into(), + name: "root".into(), + }]), users: Some(vec![ConfigUser { - name: "Teddy🐻".into(), - password: "Tasty🍖".into(), - admin: false, - }]), + name: "Teddy🐻".into(), + password: "Tasty🍖".into(), + admin: false, + }]), ydns: None, }; @@ -310,19 +311,19 @@ fn test_amend() { reindex_every_n_seconds: None, prefix_url: Some("polaris".into()), mount_dirs: Some(vec![MountPoint { - source: "/home/music".into(), - name: "🎵📁".into(), - }]), + source: "/home/music".into(), + name: "🎵📁".into(), + }]), users: Some(vec![ConfigUser { - name: "Kermit🐸".into(), - password: "🐞🐞".into(), - admin: false, - }]), + name: "Kermit🐸".into(), + password: "🐞🐞".into(), + admin: false, + }]), ydns: Some(DDNSConfig { - host: "🐸🐸🐸.ydns.eu".into(), - username: "kfr🐸g".into(), - password: "tasty🐞".into(), - }), + host: "🐸🐸🐸.ydns.eu".into(), + username: "kfr🐸g".into(), + password: "tasty🐞".into(), + }), }; let mut expected_config = new_config.clone(); @@ -351,10 +352,10 @@ fn test_amend_preserve_password_hashes() { prefix_url: None, mount_dirs: None, users: Some(vec![ConfigUser { - name: "Teddy🐻".into(), - password: "Tasty🍖".into(), - admin: false, - }]), + name: "Teddy🐻".into(), + password: "Tasty🍖".into(), + admin: false, + }]), ydns: None, }; amend(&db, &initial_config).unwrap(); @@ -373,16 +374,18 @@ fn test_amend_preserve_password_hashes() { reindex_every_n_seconds: None, prefix_url: None, mount_dirs: None, - users: Some(vec![ConfigUser { - name: "Kermit🐸".into(), - password: "tasty🐞".into(), - admin: false, - }, - ConfigUser { - name: "Teddy🐻".into(), - password: "".into(), - admin: false, - }]), + users: Some(vec![ + ConfigUser { + name: "Kermit🐸".into(), + password: "tasty🐞".into(), + admin: false, + }, + ConfigUser { + name: "Teddy🐻".into(), + password: "".into(), + admin: false, + }, + ]), ydns: None, }; amend(&db, &new_config).unwrap(); @@ -411,20 +414,17 @@ fn test_toggle_admin() { prefix_url: None, mount_dirs: None, users: Some(vec![ConfigUser { - name: "Teddy🐻".into(), - password: "Tasty🍖".into(), - admin: true, - }]), + name: "Teddy🐻".into(), + password: "Tasty🍖".into(), + admin: true, + }]), ydns: None, }; amend(&db, &initial_config).unwrap(); { let connection = db.get_connection(); - let is_admin: i32 = users - .select(admin) - .get_result(connection.deref()) - .unwrap(); + let is_admin: i32 = users.select(admin).get_result(connection.deref()).unwrap(); assert_eq!(is_admin, 1); } @@ -434,27 +434,23 @@ fn test_toggle_admin() { prefix_url: None, mount_dirs: None, users: Some(vec![ConfigUser { - name: "Teddy🐻".into(), - password: "".into(), - admin: false, - }]), + name: "Teddy🐻".into(), + password: "".into(), + admin: false, + }]), ydns: None, }; amend(&db, &new_config).unwrap(); { let connection = db.get_connection(); - let is_admin: i32 = users - .select(admin) - .get_result(connection.deref()) - .unwrap(); + let is_admin: i32 = users.select(admin).get_result(connection.deref()).unwrap(); assert_eq!(is_admin, 0); } } #[test] fn test_preferences_read_write() { - let db = _get_test_db("preferences_read_write.sqlite"); let initial_config = Config { @@ -463,10 +459,10 @@ fn test_preferences_read_write() { prefix_url: None, mount_dirs: None, users: Some(vec![ConfigUser { - name: "Teddy🐻".into(), - password: "Tasty🍖".into(), - admin: false, - }]), + name: "Teddy🐻".into(), + password: "Tasty🍖".into(), + admin: false, + }]), ydns: None, }; amend(&db, &initial_config).unwrap(); diff --git a/src/db/mod.rs b/src/db/mod.rs index 77d3709..05f15c4 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,7 +1,7 @@ use core::ops::Deref; -use diesel_migrations; use diesel::prelude::*; use diesel::sqlite::SqliteConnection; +use diesel_migrations; use std::fs; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex, MutexGuard}; @@ -28,9 +28,12 @@ pub struct DB { impl DB { pub fn new(path: &Path) -> Result<DB> { info!("Database file path: {}", path.to_string_lossy()); - let connection = - Arc::new(Mutex::new(SqliteConnection::establish(&path.to_string_lossy())?)); - let db = DB { connection: connection.clone() }; + let connection = Arc::new(Mutex::new(SqliteConnection::establish( + &path.to_string_lossy(), + )?)); + let db = DB { + connection: connection.clone(), + }; db.init()?; Ok(db) } @@ -49,9 +52,14 @@ impl DB { let connection = self.connection.lock().unwrap(); let connection = connection.deref(); loop { - match diesel_migrations::revert_latest_migration_in_directory(connection, Path::new(DB_MIGRATIONS_PATH)) { + match diesel_migrations::revert_latest_migration_in_directory( + connection, + Path::new(DB_MIGRATIONS_PATH), + ) { Ok(_) => (), - Err(diesel_migrations::RunMigrationsError::MigrationError(diesel_migrations::MigrationError::NoMigrationRun)) => break, + Err(diesel_migrations::RunMigrationsError::MigrationError( + diesel_migrations::MigrationError::NoMigrationRun, + )) => break, Err(e) => bail!(e), } } diff --git a/src/ddns.rs b/src/ddns.rs index 3e0df7e..e6de3ae 100644 --- a/src/ddns.rs +++ b/src/ddns.rs @@ -6,12 +6,12 @@ use std::io; use std::thread; use std::time; -use db::{ConnectionSource, DB}; use db::ddns_config; +use db::{ConnectionSource, DB}; use errors; #[derive(Clone, Debug, Deserialize, Insertable, PartialEq, Queryable, Serialize)] -#[table_name="ddns_config"] +#[table_name = "ddns_config"] pub struct DDNSConfig { pub host: String, pub username: String, @@ -27,8 +27,8 @@ impl DDNSConfigSource for DB { use self::ddns_config::dsl::*; let connection = self.get_connection(); Ok(ddns_config - .select((host, username, password)) - .get_result(connection.deref())?) + .select((host, username, password)) + .get_result(connection.deref())?) } } @@ -60,9 +60,9 @@ impl From<reqwest::Error> for DDNSError { const DDNS_UPDATE_URL: &'static str = "https://ydns.io/api/v1/update/"; - fn update_my_ip<T>(config_source: &T) -> Result<(), DDNSError> - where T: DDNSConfigSource +where + T: DDNSConfigSource, { let config = config_source.get_ddns_config()?; if config.host.len() == 0 || config.username.len() == 0 { @@ -72,14 +72,11 @@ fn update_my_ip<T>(config_source: &T) -> Result<(), DDNSError> let full_url = format!("{}?host={}", DDNS_UPDATE_URL, &config.host); let auth_header = Authorization(Basic { - username: config.username.clone(), - password: Some(config.password.to_owned()), - }); + username: config.username.clone(), + password: Some(config.password.to_owned()), + }); let client = reqwest::Client::new()?; - let res = client - .get(full_url.as_str()) - .header(auth_header) - .send()?; + let res = client.get(full_url.as_str()).header(auth_header).send()?; if !res.status().is_success() { return Err(DDNSError::UpdateError(*res.status())); } @@ -87,7 +84,8 @@ fn update_my_ip<T>(config_source: &T) -> Result<(), DDNSError> } pub fn run<T>(config_source: &T) - where T: DDNSConfigSource +where + T: DDNSConfigSource, { loop { if let Err(e) = update_my_ip(config_source) { diff --git a/src/errors.rs b/src/errors.rs index 2d0cd09..1243176 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -2,12 +2,12 @@ use ape; use core; use diesel; use diesel_migrations; -use id3; use getopts; -use image; use hyper; -use iron::IronError; +use id3; +use image; use iron::status::Status; +use iron::IronError; use lewton; use metaflac; use regex; @@ -17,46 +17,46 @@ use std; use toml; error_chain! { - foreign_links { - Ape(ape::Error); - Diesel(diesel::result::Error); - DieselConnection(diesel::ConnectionError); - DieselMigration(diesel_migrations::RunMigrationsError); - Encoding(core::str::Utf8Error); - Flac(metaflac::Error); - GetOpts(getopts::Fail); - Hyper(hyper::Error); - Id3(id3::Error); - Image(image::ImageError); - Io(std::io::Error); - Json(serde_json::Error); - Time(std::time::SystemTimeError); - Toml(toml::de::Error); - Regex(regex::Error); - Scrobbler(rustfm_scrobble::ScrobblerError); - Vorbis(lewton::VorbisError); - } + foreign_links { + Ape(ape::Error); + Diesel(diesel::result::Error); + DieselConnection(diesel::ConnectionError); + DieselMigration(diesel_migrations::RunMigrationsError); + Encoding(core::str::Utf8Error); + Flac(metaflac::Error); + GetOpts(getopts::Fail); + Hyper(hyper::Error); + Id3(id3::Error); + Image(image::ImageError); + Io(std::io::Error); + Json(serde_json::Error); + Time(std::time::SystemTimeError); + Toml(toml::de::Error); + Regex(regex::Error); + Scrobbler(rustfm_scrobble::ScrobblerError); + Vorbis(lewton::VorbisError); + } - errors { - DaemonError {} - AuthenticationRequired {} - AdminPrivilegeRequired {} - MissingConfig {} - MissingPreferences {} - MissingUsername {} - MissingPassword {} - MissingPlaylist {} - IncorrectCredentials {} - CannotServeDirectory {} - UnsupportedFileType {} - FileNotFound {} - MissingIndexVersion {} - MissingPlaylistName {} - EncodingError {} - MissingLastFMCredentials {} - LastFMAuthError {} - LastFMDeserializationError {} - } + errors { + DaemonError {} + AuthenticationRequired {} + AdminPrivilegeRequired {} + MissingConfig {} + MissingPreferences {} + MissingUsername {} + MissingPassword {} + MissingPlaylist {} + IncorrectCredentials {} + CannotServeDirectory {} + UnsupportedFileType {} + FileNotFound {} + MissingIndexVersion {} + MissingPlaylistName {} + EncodingError {} + MissingLastFMCredentials {} + LastFMAuthError {} + LastFMDeserializationError {} + } } impl From<Error> for IronError { diff --git a/src/index.rs b/src/index.rs index 56df257..b589ba2 100644 --- a/src/index.rs +++ b/src/index.rs @@ -9,8 +9,8 @@ use std::fs; use std::path::Path; #[cfg(test)] use std::path::PathBuf; -use std::sync::{Arc, Mutex}; use std::sync::mpsc::*; +use std::sync::{Arc, Mutex}; use std::thread; use std::time; @@ -19,16 +19,18 @@ use config::MiscSettings; use db; use db::ConnectionSource; use db::{directories, misc_settings, songs}; -use vfs::{VFS, VFSSource}; use errors; use metadata; +use vfs::{VFSSource, VFS}; const INDEX_BUILDING_INSERT_BUFFER_SIZE: usize = 1000; // Insertions in each transaction const INDEX_BUILDING_CLEAN_BUFFER_SIZE: usize = 500; // Insertions in each transaction -no_arg_sql_function!(random, - types::Integer, - "Represents the SQL RANDOM() function"); +no_arg_sql_function!( + random, + types::Integer, + "Represents the SQL RANDOM() function" +); pub enum Command { REINDEX, @@ -74,7 +76,7 @@ pub enum CollectionFile { } #[derive(Debug, Insertable)] -#[table_name="songs"] +#[table_name = "songs"] struct NewSong { path: String, parent: String, @@ -90,7 +92,7 @@ struct NewSong { } #[derive(Debug, Insertable)] -#[table_name="directories"] +#[table_name = "directories"] struct NewDirectory { path: String, parent: Option<String>, @@ -109,31 +111,31 @@ struct IndexBuilder<'conn> { } impl<'conn> IndexBuilder<'conn> { - fn new(connection: &Mutex<SqliteConnection>, - album_art_pattern: Regex) - -> Result<IndexBuilder, errors::Error> { + fn new( + connection: &Mutex<SqliteConnection>, + album_art_pattern: Regex, + ) -> Result<IndexBuilder, errors::Error> { let mut new_songs = Vec::new(); let mut new_directories = Vec::new(); new_songs.reserve_exact(INDEX_BUILDING_INSERT_BUFFER_SIZE); new_directories.reserve_exact(INDEX_BUILDING_INSERT_BUFFER_SIZE); Ok(IndexBuilder { - new_songs: new_songs, - new_directories: new_directories, - connection: connection, - album_art_pattern: album_art_pattern, - }) + new_songs: new_songs, + new_directories: new_directories, + connection: connection, + album_art_pattern: album_art_pattern, + }) } fn flush_songs(&mut self) -> Result<(), errors::Error> { let connection = self.connection.lock().unwrap(); let connection = connection.deref(); - connection - .transaction::<_, errors::Error, _>(|| { - diesel::insert_into(songs::table) - .values(&self.new_songs) - .execute(connection)?; - Ok(()) - })?; + connection.transaction::<_, errors::Error, _>(|| { + diesel::insert_into(songs::table) + .values(&self.new_songs) + .execute(connection)?; + Ok(()) + })?; self.new_songs.clear(); Ok(()) } @@ -141,13 +143,12 @@ impl<'conn> IndexBuilder<'conn> { fn flush_directories(&mut self) -> Result<(), errors::Error> { let connection = self.connection.lock().unwrap(); let connection = connection.deref(); - connection - .transaction::<_, errors::Error, _>(|| { - diesel::insert_into(directories::table) - .values(&self.new_directories) - .execute(connection)?; - Ok(()) - })?; + connection.transaction::<_, errors::Error, _>(|| { + diesel::insert_into(directories::table) + .values(&self.new_directories) + .execute(connection)?; + Ok(()) + })?; self.new_directories.clear(); Ok(()) } @@ -180,11 +181,11 @@ impl<'conn> IndexBuilder<'conn> { Ok(None) } - fn populate_directory(&mut self, - parent: Option<&Path>, - path: &Path) - -> Result<(), errors::Error> { - + fn populate_directory( + &mut self, + parent: Option<&Path>, + path: &Path, + ) -> Result<(), errors::Error> { // Find artwork let artwork = self.get_artwork(path).unwrap_or(None); @@ -228,24 +229,24 @@ impl<'conn> IndexBuilder<'conn> { if let Some(file_path_string) = file_path.to_str() { if let Ok(tags) = metadata::read(file_path.as_path()) { if tags.year.is_some() { - inconsistent_directory_year |= directory_year.is_some() && - directory_year != tags.year; + inconsistent_directory_year |= + directory_year.is_some() && directory_year != tags.year; directory_year = tags.year; } if tags.album.is_some() { - inconsistent_directory_album |= directory_album.is_some() && - directory_album != tags.album; + inconsistent_directory_album |= + directory_album.is_some() && directory_album != tags.album; directory_album = tags.album.as_ref().map(|a| a.clone()); } if tags.album_artist.is_some() { - inconsistent_directory_artist |= directory_artist.is_some() && - directory_artist != tags.album_artist; + inconsistent_directory_artist |= + directory_artist.is_some() && directory_artist != tags.album_artist; directory_artist = tags.album_artist.as_ref().map(|a| a.clone()); } else if tags.artist.is_some() { - inconsistent_directory_artist |= directory_artist.is_some() && - directory_artist != tags.artist; + inconsistent_directory_artist |= + directory_artist.is_some() && directory_artist != tags.artist; directory_artist = tags.artist.as_ref().map(|a| a.clone()); } @@ -300,7 +301,8 @@ impl<'conn> IndexBuilder<'conn> { } fn clean<T>(db: &T) -> Result<(), errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { let vfs = db.get_vfs()?; @@ -308,18 +310,15 @@ fn clean<T>(db: &T) -> Result<(), errors::Error> let all_songs: Vec<String>; { let connection = db.get_connection(); - all_songs = songs::table - .select(songs::path) - .load(connection.deref())?; + all_songs = songs::table.select(songs::path).load(connection.deref())?; } let missing_songs = all_songs .into_iter() .filter(|ref song_path| { - let path = Path::new(&song_path); - !path.exists() || vfs.real_to_virtual(path).is_err() - }) - .collect::<Vec<_>>(); + let path = Path::new(&song_path); + !path.exists() || vfs.real_to_virtual(path).is_err() + }).collect::<Vec<_>>(); { let connection = db.get_connection(); @@ -327,7 +326,6 @@ fn clean<T>(db: &T) -> Result<(), errors::Error> diesel::delete(songs::table.filter(songs::path.eq_any(chunk))) .execute(connection.deref())?; } - } } @@ -343,10 +341,9 @@ fn clean<T>(db: &T) -> Result<(), errors::Error> let missing_directories = all_directories .into_iter() .filter(|ref directory_path| { - let path = Path::new(&directory_path); - !path.exists() || vfs.real_to_virtual(path).is_err() - }) - .collect::<Vec<_>>(); + let path = Path::new(&directory_path); + !path.exists() || vfs.real_to_virtual(path).is_err() + }).collect::<Vec<_>>(); { let connection = db.get_connection(); @@ -361,7 +358,8 @@ fn clean<T>(db: &T) -> Result<(), errors::Error> } fn populate<T>(db: &T) -> Result<(), errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { let vfs = db.get_vfs()?; let mount_points = vfs.get_mount_points(); @@ -384,19 +382,23 @@ fn populate<T>(db: &T) -> Result<(), errors::Error> } pub fn update<T>(db: &T) -> Result<(), errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { let start = time::Instant::now(); info!("Beginning library index update"); clean(db)?; populate(db)?; - info!("Library index update took {} seconds", - start.elapsed().as_secs()); + info!( + "Library index update took {} seconds", + start.elapsed().as_secs() + ); Ok(()) } pub fn update_loop<T>(db: &T, command_buffer: Receiver<Command>) - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { loop { // Wait for a command @@ -425,7 +427,8 @@ pub fn update_loop<T>(db: &T, command_buffer: Receiver<Command>) } pub fn self_trigger<T>(db: &T, command_buffer: Arc<Mutex<Sender<Command>>>) - where T: ConnectionSource +where + T: ConnectionSource, { loop { { @@ -482,7 +485,8 @@ fn virtualize_directory(vfs: &VFS, mut directory: Directory) -> Option<Directory } pub fn browse<T>(db: &T, virtual_path: &Path) -> Result<Vec<CollectionFile>, errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { let mut output = Vec::new(); let vfs = db.get_vfs()?; @@ -496,10 +500,11 @@ pub fn browse<T>(db: &T, virtual_path: &Path) -> Result<Vec<CollectionFile>, err let virtual_directories = real_directories .into_iter() .filter_map(|s| virtualize_directory(&vfs, s)); - output.extend(virtual_directories - .into_iter() - .map(|d| CollectionFile::Directory(d))); - + output.extend( + virtual_directories + .into_iter() + .map(|d| CollectionFile::Directory(d)), + ); } else { // Browse sub-directory let real_path = vfs.virtual_to_real(virtual_path)?; @@ -528,7 +533,8 @@ pub fn browse<T>(db: &T, virtual_path: &Path) -> Result<Vec<CollectionFile>, err } pub fn flatten<T>(db: &T, virtual_path: &Path) -> Result<Vec<Song>, errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { use self::songs::dsl::*; let vfs = db.get_vfs()?; @@ -552,7 +558,8 @@ pub fn flatten<T>(db: &T, virtual_path: &Path) -> Result<Vec<Song>, errors::Erro } pub fn get_random_albums<T>(db: &T, count: i64) -> Result<Vec<Directory>, errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { use self::directories::dsl::*; let vfs = db.get_vfs()?; @@ -569,7 +576,8 @@ pub fn get_random_albums<T>(db: &T, count: i64) -> Result<Vec<Directory>, errors } pub fn get_recent_albums<T>(db: &T, count: i64) -> Result<Vec<Directory>, errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { use self::directories::dsl::*; let vfs = db.get_vfs()?; @@ -586,7 +594,8 @@ pub fn get_recent_albums<T>(db: &T, count: i64) -> Result<Vec<Directory>, errors } pub fn search<T>(db: &T, query: &str) -> Result<Vec<CollectionFile>, errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { let vfs = db.get_vfs()?; let connection = db.get_connection(); @@ -612,12 +621,13 @@ pub fn search<T>(db: &T, query: &str) -> Result<Vec<CollectionFile>, errors::Err { use self::songs::dsl::*; let real_songs: Vec<Song> = songs - .filter(path.like(&like_test) - .or(title.like(&like_test)) - .or(album.like(&like_test)) - .or(artist.like(&like_test)) - .or(album_artist.like(&like_test))) - .filter(parent.not_like(&like_test)) + .filter( + path.like(&like_test) + .or(title.like(&like_test)) + .or(album.like(&like_test)) + .or(artist.like(&like_test)) + .or(album_artist.like(&like_test)), + ).filter(parent.not_like(&like_test)) .load(connection.deref())?; let virtual_songs = real_songs @@ -631,7 +641,8 @@ pub fn search<T>(db: &T, query: &str) -> Result<Vec<CollectionFile>, errors::Err } pub fn get_song<T>(db: &T, virtual_path: &Path) -> Result<Song, errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { let vfs = db.get_vfs()?; let connection = db.get_connection(); @@ -695,8 +706,10 @@ fn test_metadata() { assert_eq!(song.album_artist, None); assert_eq!(song.album, Some("Picnic".to_owned())); assert_eq!(song.year, Some(2016)); - assert_eq!(song.artwork, - Some(artwork_path.to_string_lossy().into_owned())); + assert_eq!( + song.artwork, + Some(artwork_path.to_string_lossy().into_owned()) + ); } #[test] diff --git a/src/lastfm.rs b/src/lastfm.rs index c259181..d4c4e6f 100644 --- a/src/lastfm.rs +++ b/src/lastfm.rs @@ -1,6 +1,6 @@ use md5; use reqwest; -use rustfm_scrobble::{Scrobbler, Scrobble}; +use rustfm_scrobble::{Scrobble, Scrobbler}; use serde_xml_rs::deserialize; use std::collections::HashMap; use std::io::Read; @@ -48,16 +48,20 @@ struct AuthResponse { } fn scrobble_from_path<T>(db: &T, track: &Path) -> Result<Scrobble, errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { let song = index::get_song(db, track)?; - Ok(Scrobble::new(song.artist.unwrap_or("".into()), - song.title.unwrap_or("".into()), - song.album.unwrap_or("".into()))) + Ok(Scrobble::new( + song.artist.unwrap_or("".into()), + song.title.unwrap_or("".into()), + song.album.unwrap_or("".into()), + )) } pub fn auth<T>(db: &T, username: &str, token: &str) -> Result<(), errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { let mut params = HashMap::new(); params.insert("token".to_string(), token.to_string()); @@ -75,14 +79,15 @@ pub fn auth<T>(db: &T, username: &str, token: &str) -> Result<(), errors::Error> let auth_response: AuthResponse = match deserialize(body.as_bytes()) { Ok(d) => d, - Err(_) => bail!(errors::ErrorKind::LastFMDeserializationError) + Err(_) => bail!(errors::ErrorKind::LastFMDeserializationError), }; user::set_lastfm_session_key(db, username, &auth_response.session.key.body) } pub fn scrobble<T>(db: &T, username: &str, track: &Path) -> Result<(), errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { let mut scrobbler = Scrobbler::new(LASTFM_API_KEY.into(), LASTFM_API_SECRET.into()); let scrobble = scrobble_from_path(db, track)?; @@ -93,7 +98,8 @@ pub fn scrobble<T>(db: &T, username: &str, track: &Path) -> Result<(), errors::E } pub fn now_playing<T>(db: &T, username: &str, track: &Path) -> Result<(), errors::Error> - where T: ConnectionSource + VFSSource +where + T: ConnectionSource + VFSSource, { let mut scrobbler = Scrobbler::new(LASTFM_API_KEY.into(), LASTFM_API_SECRET.into()); let scrobble = scrobble_from_path(db, track)?; @@ -103,14 +109,15 @@ pub fn now_playing<T>(db: &T, username: &str, track: &Path) -> Result<(), errors Ok(()) } -fn api_request(method: &str, params: &HashMap<String, String>) -> Result<reqwest::Response, reqwest::Error> -{ +fn api_request( + method: &str, + params: &HashMap<String, String>, +) -> Result<reqwest::Response, reqwest::Error> { let mut url = LASTFM_API_ROOT.to_string(); url.push_str("?"); url.push_str(&format!("method={}&", method)); - for (k, v) in params.iter() - { + for (k, v) in params.iter() { url.push_str(&format!("{}={}&", k, v)); } let api_signature = get_signature(method, params); @@ -121,21 +128,18 @@ fn api_request(method: &str, params: &HashMap<String, String>) -> Result<reqwest request.send() } -fn get_signature(method: &str, params: &HashMap<String, String>) -> String -{ +fn get_signature(method: &str, params: &HashMap<String, String>) -> String { let mut signature_data = params.clone(); signature_data.insert("method".to_string(), method.to_string()); let mut param_names = Vec::new(); - for param_name in signature_data.keys() - { + for param_name in signature_data.keys() { param_names.push(param_name); } param_names.sort(); let mut signature = String::new(); - for param_name in param_names - { + for param_name in param_names { signature.push_str((param_name.to_string() + signature_data[param_name].as_str()).as_str()) } diff --git a/src/main.rs b/src/main.rs index a232708..2b190e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,8 +23,8 @@ extern crate mount; extern crate mp3_duration; extern crate params; extern crate rand; -extern crate reqwest; extern crate regex; +extern crate reqwest; extern crate ring; extern crate router; extern crate rustfm_scrobble; @@ -50,25 +50,25 @@ extern crate winapi; #[cfg(unix)] extern crate unix_daemonize; -#[cfg(unix)] -use unix_daemonize::{daemonize_redirect, ChdirMode}; #[cfg(unix)] use std::fs::File; #[cfg(unix)] use std::io::prelude::*; +#[cfg(unix)] +use unix_daemonize::{daemonize_redirect, ChdirMode}; use core::ops::Deref; use errors::*; use getopts::Options; use iron::prelude::*; use mount::Mount; -use staticfile::Static; -use std::path::Path; -use std::sync::{Arc, Mutex}; -use std::sync::mpsc::channel; -use simplelog::{TermLogger, LogLevelFilter}; #[cfg(unix)] use simplelog::SimpleLogger; +use simplelog::{LogLevelFilter, TermLogger}; +use staticfile::Static; +use std::path::Path; +use std::sync::mpsc::channel; +use std::sync::{Arc, Mutex}; mod api; mod config; @@ -79,11 +79,11 @@ mod index; mod lastfm; mod metadata; mod playlist; +mod serve; +mod thumbnails; mod ui; mod user; mod utils; -mod serve; -mod thumbnails; mod vfs; static LOG_CONFIG: simplelog::Config = simplelog::Config { @@ -148,7 +148,6 @@ fn init_log(log_level: LogLevelFilter, _: &getopts::Matches) -> Result<()> { } fn run() -> Result<()> { - // Parse CLI options let args: Vec<String> = std::env::args().collect(); let mut options = Options::new(); @@ -156,15 +155,19 @@ fn run() -> Result<()> { options.optopt("p", "port", "set polaris to run on a custom port", "PORT"); options.optopt("d", "database", "set the path to index database", "FILE"); options.optopt("w", "web", "set the path to web client files", "DIRECTORY"); - options.optopt("l", - "log", - "set the log level to a value between 0 (off) and 3 (debug)", - "LEVEL"); + options.optopt( + "l", + "log", + "set the log level to a value between 0 (off) and 3 (debug)", + "LEVEL", + ); #[cfg(unix)] - options.optflag("f", - "foreground", - "run polaris in the foreground instead of daemonizing"); + options.optflag( + "f", + "foreground", + "run polaris in the foreground instead of daemonizing", + ); options.optflag("h", "help", "print this help menu"); @@ -214,14 +217,16 @@ fn run() -> Result<()> { let index_sender = Arc::new(Mutex::new(index_sender)); let db_ref = db.clone(); std::thread::spawn(move || { - let db = db_ref.deref(); - index::update_loop(db, index_receiver); - }); + let db = db_ref.deref(); + index::update_loop(db, index_receiver); + }); // Trigger auto-indexing let db_ref = db.clone(); let sender_ref = index_sender.clone(); - std::thread::spawn(move || { index::self_trigger(db_ref.deref(), sender_ref); }); + std::thread::spawn(move || { + index::self_trigger(db_ref.deref(), sender_ref); + }); // Mount API let prefix_url = config.prefix_url.unwrap_or("".to_string()); @@ -258,7 +263,9 @@ fn run() -> Result<()> { // Start DDNS updates let db_ref = db.clone(); - std::thread::spawn(move || { ddns::run(db_ref.deref()); }); + std::thread::spawn(move || { + ddns::run(db_ref.deref()); + }); // Run UI ui::run(); diff --git a/src/metadata.rs b/src/metadata.rs index 99cfc44..57bf7cc 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -45,21 +45,22 @@ fn read_id3(path: &Path) -> Result<SongTags> { let title = tag.title().map(|s| s.to_string()); let disc_number = tag.disc(); let track_number = tag.track(); - let year = tag.year() + let year = tag + .year() .map(|y| y as i32) .or(tag.date_released().and_then(|d| Some(d.year))) .or(tag.date_recorded().and_then(|d| Some(d.year))); Ok(SongTags { - artist: artist, - album_artist: album_artist, - album: album, - title: title, - duration: duration, - disc_number: disc_number, - track_number: track_number, - year: year, - }) + artist: artist, + album_artist: album_artist, + album: album, + title: title, + duration: duration, + disc_number: disc_number, + track_number: track_number, + year: year, + }) } fn read_ape_string(item: &ape::Item) -> Option<String> { @@ -100,19 +101,18 @@ fn read_ape(path: &Path) -> Result<SongTags> { let disc_number = tag.item("Disc").and_then(read_ape_x_of_y); let track_number = tag.item("Track").and_then(read_ape_x_of_y); Ok(SongTags { - artist: artist, - album_artist: album_artist, - album: album, - title: title, - duration: None, - disc_number: disc_number, - track_number: track_number, - year: year, - }) + artist: artist, + album_artist: album_artist, + album: album, + title: title, + duration: None, + disc_number: disc_number, + track_number: track_number, + year: year, + }) } fn read_vorbis(path: &Path) -> Result<SongTags> { - let file = fs::File::open(path)?; let source = OggStreamReader::new(file)?; @@ -159,15 +159,15 @@ fn read_flac(path: &Path) -> Result<SongTags> { }; Ok(SongTags { - artist: vorbis.artist().map(|v| v[0].clone()), - album_artist: vorbis.album_artist().map(|v| v[0].clone()), - album: vorbis.album().map(|v| v[0].clone()), - title: vorbis.title().map(|v| v[0].clone()), - duration: duration, - disc_number: disc_number, - track_number: vorbis.track(), - year: year, - }) + artist: vorbis.artist().map(|v| v[0].clone()), + album_artist: vorbis.album_artist().map(|v| v[0].clone()), + album: vorbis.album().map(|v| v[0].clone()), + title: vorbis.title().map(|v| v[0].clone()), + duration: duration, + disc_number: disc_number, + track_number: vorbis.track(), + year: year, + }) } #[test] @@ -192,6 +192,8 @@ fn test_read_metadata() { }; assert_eq!(read(Path::new("test/sample.mp3")).unwrap(), mp3_sample_tag); assert_eq!(read(Path::new("test/sample.ogg")).unwrap(), sample_tags); - assert_eq!(read(Path::new("test/sample.flac")).unwrap(), - flac_sample_tag); + assert_eq!( + read(Path::new("test/sample.flac")).unwrap(), + flac_sample_tag + ); } diff --git a/src/playlist.rs b/src/playlist.rs index 162d8b2..7c1f5d0 100644 --- a/src/playlist.rs +++ b/src/playlist.rs @@ -5,6 +5,7 @@ use diesel::prelude::*; use diesel::BelongingToDsl; use diesel::types::*; use std::path::Path; + #[cfg(test)] use db; use db::ConnectionSource; diff --git a/src/serve.rs b/src/serve.rs index b27a7cd..f40e17c 100644 --- a/src/serve.rs +++ b/src/serve.rs @@ -1,19 +1,19 @@ -use std::cmp; -use std::fs::{self, File}; -use std::io::{self, Read, Seek, SeekFrom, Write}; -use std::path::Path; -use iron::headers::{AcceptRanges, ByteRangeSpec, ContentLength, ContentRange, ContentRangeSpec, - Range, RangeUnit}; +use iron::headers::{ + AcceptRanges, ByteRangeSpec, ContentLength, ContentRange, ContentRangeSpec, Range, RangeUnit, +}; use iron::modifier::Modifier; use iron::modifiers::Header; use iron::prelude::*; use iron::response::WriteBody; use iron::status::{self, Status}; +use std::cmp; +use std::fs::{self, File}; +use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::path::Path; use errors::{Error, ErrorKind}; pub fn deliver(path: &Path, range_header: Option<&Range>) -> IronResult<Response> { - match fs::metadata(path) { Ok(meta) => meta, Err(e) => { @@ -31,18 +31,20 @@ pub fn deliver(path: &Path, range_header: Option<&Range>) -> IronResult<Response match range_header { None => Ok(Response::with((status::Ok, path, accept_range_header))), - Some(range) => { - match range { - Range::Bytes(vec_range) => { - if let Ok(partial_file) = PartialFile::from_path(path, vec_range) { - Ok(Response::with((status::Ok, partial_file, accept_range_header))) - } else { - Err(Error::from(ErrorKind::FileNotFound).into()) - } + Some(range) => match range { + Range::Bytes(vec_range) => { + if let Ok(partial_file) = PartialFile::from_path(path, vec_range) { + Ok(Response::with(( + status::Ok, + partial_file, + accept_range_header, + ))) + } else { + Err(Error::from(ErrorKind::FileNotFound).into()) } - _ => Ok(Response::with(status::RangeNotSatisfiable)), } - } + _ => Ok(Response::with(status::RangeNotSatisfiable)), + }, } } @@ -78,7 +80,8 @@ impl From<Vec<ByteRangeSpec>> for PartialFileRange { impl PartialFile { pub fn new<Range>(file: File, range: Range) -> PartialFile - where Range: Into<PartialFileRange> + where + Range: Into<PartialFileRange>, { let range = range.into(); PartialFile { @@ -88,14 +91,14 @@ impl PartialFile { } pub fn from_path<P: AsRef<Path>, Range>(path: P, range: Range) -> Result<PartialFile, io::Error> - where Range: Into<PartialFileRange> + where + Range: Into<PartialFileRange>, { let file = File::open(path.as_ref())?; Ok(Self::new(file, range)) } } - impl Modifier<Response> for PartialFile { fn modify(self, res: &mut Response) { use self::PartialFileRange::*; @@ -124,13 +127,12 @@ impl Modifier<Response> for PartialFile { } } (_, None) => None, - }; if let Some(range) = range { let content_range = ContentRange(ContentRangeSpec::Bytes { - range: Some(range), - instance_length: file_length, - }); + range: Some(range), + instance_length: file_length, + }); let content_len = range.1 - range.0 + 1; res.headers.set(ContentLength(content_len)); res.headers.set(content_range); @@ -143,11 +145,10 @@ impl Modifier<Response> for PartialFile { res.body = Some(Box::new(partial_content)); } else { if let Some(file_length) = file_length { - res.headers - .set(ContentRange(ContentRangeSpec::Bytes { - range: None, - instance_length: Some(file_length), - })); + res.headers.set(ContentRange(ContentRangeSpec::Bytes { + range: None, + instance_length: Some(file_length), + })); }; res.status = Some(Status::RangeNotSatisfiable); } diff --git a/src/thumbnails.rs b/src/thumbnails.rs index bd353d8..4ddceb5 100644 --- a/src/thumbnails.rs +++ b/src/thumbnails.rs @@ -1,8 +1,8 @@ use image; +use image::FilterType; use image::GenericImage; use image::ImageBuffer; use image::ImageFormat; -use image::FilterType; use std::cmp; use std::collections::hash_map::DefaultHasher; use std::fs::{DirBuilder, File}; @@ -23,7 +23,6 @@ fn hash(path: &Path, dimension: u32) -> u64 { } pub fn get_thumbnail(real_path: &Path, max_dimension: u32) -> Result<PathBuf> { - let mut out_path = utils::get_data_root()?; out_path.push(THUMBNAILS_PATH); @@ -46,9 +45,11 @@ pub fn get_thumbnail(real_path: &Path, max_dimension: u32) -> Result<PathBuf> { source_image.resize(out_dimension, out_dimension, FilterType::Lanczos3); let (scaled_width, scaled_height) = scaled_image.dimensions(); let mut final_image = ImageBuffer::new(out_dimension, out_dimension); - final_image.copy_from(&scaled_image, - (out_dimension - scaled_width) / 2, - (out_dimension - scaled_height) / 2); + final_image.copy_from( + &scaled_image, + (out_dimension - scaled_width) / 2, + (out_dimension - scaled_height) / 2, + ); final_image.save(&out_path)?; } else { let mut out_file = File::create(&out_path)?; diff --git a/src/ui/headless.rs b/src/ui/headless.rs index e25d493..8e2c979 100644 --- a/src/ui/headless.rs +++ b/src/ui/headless.rs @@ -1,5 +1,5 @@ -use std::time; use std::thread; +use std::time; pub fn run() { info!("Starting up UI (headless)"); diff --git a/src/ui/windows.rs b/src/ui/windows.rs index 05c28e0..2bbfaee 100644 --- a/src/ui/windows.rs +++ b/src/ui/windows.rs @@ -3,9 +3,9 @@ use std::ffi::OsStr; use std::os::windows::ffi::OsStrExt; use uuid; use winapi; -use winapi::um::{shellapi, winuser}; -use winapi::shared::minwindef::{DWORD, LOWORD, UINT, WPARAM, LPARAM, LRESULT}; +use winapi::shared::minwindef::{DWORD, LOWORD, LPARAM, LRESULT, UINT, WPARAM}; use winapi::shared::windef::HWND; +use winapi::um::{shellapi, winuser}; const IDI_POLARIS_TRAY: isize = 0x102; const UID_NOTIFICATION_ICON: u32 = 0; @@ -33,12 +33,15 @@ impl ToWin for uuid::Uuid { fn to_win(&self) -> Self::Out { let bytes = self.as_bytes(); - let end = [bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], - bytes[15]]; + let end = [ + bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], + ]; winapi::shared::guiddef::GUID { - Data1: ((bytes[0] as u32) << 24 | (bytes[1] as u32) << 16 | (bytes[2] as u32) << 8 | - (bytes[3] as u32)), + Data1: ((bytes[0] as u32) << 24 + | (bytes[1] as u32) << 16 + | (bytes[2] as u32) << 8 + | (bytes[3] as u32)), Data2: ((bytes[4] as u16) << 8 | (bytes[5] as u16)), Data3: ((bytes[6] as u16) << 8 | (bytes[7] as u16)), Data4: end, @@ -55,7 +58,6 @@ impl Constructible for shellapi::NOTIFYICONDATAW { type Out = shellapi::NOTIFYICONDATAW; fn new() -> Self::Out { - let mut version_union: shellapi::NOTIFYICONDATAW_u = unsafe { std::mem::zeroed() }; unsafe { let version = version_union.uVersion_mut(); @@ -83,7 +85,6 @@ impl Constructible for shellapi::NOTIFYICONDATAW { } fn create_window() -> Option<HWND> { - let class_name = "Polaris-class".to_win(); let window_name = "Polaris-window".to_win(); @@ -107,18 +108,20 @@ fn create_window() -> Option<HWND> { return None; } - let window_handle = winuser::CreateWindowExW(0, - atom as winapi::shared::ntdef::LPCWSTR, - window_name.as_ptr(), - winuser::WS_DISABLED, - 0, - 0, - 0, - 0, - winuser::GetDesktopWindow(), - std::ptr::null_mut(), - std::ptr::null_mut(), - std::ptr::null_mut()); + let window_handle = winuser::CreateWindowExW( + 0, + atom as winapi::shared::ntdef::LPCWSTR, + window_name.as_ptr(), + winuser::WS_DISABLED, + 0, + 0, + 0, + 0, + winuser::GetDesktopWindow(), + std::ptr::null_mut(), + std::ptr::null_mut(), + std::ptr::null_mut(), + ); if window_handle.is_null() { return None; @@ -129,7 +132,6 @@ fn create_window() -> Option<HWND> { } fn add_notification_icon(window: HWND) { - let mut tooltip = [0 as winapi::um::winnt::WCHAR; 128]; for (&x, p) in "Polaris".to_win().iter().zip(tooltip.iter_mut()) { *p = x; @@ -173,24 +175,28 @@ fn open_notification_context_menu(window: HWND) { if context_menu.is_null() { return; } - winuser::InsertMenuW(context_menu, - 0, - winuser::MF_STRING, - MESSAGE_NOTIFICATION_ICON_QUIT as usize, - quit_string.as_ptr()); + winuser::InsertMenuW( + context_menu, + 0, + winuser::MF_STRING, + MESSAGE_NOTIFICATION_ICON_QUIT as usize, + quit_string.as_ptr(), + ); let mut cursor_position = winapi::shared::windef::POINT { x: 0, y: 0 }; winuser::GetCursorPos(&mut cursor_position); winuser::SetForegroundWindow(window); let flags = winuser::TPM_RIGHTALIGN | winuser::TPM_BOTTOMALIGN | winuser::TPM_RIGHTBUTTON; - winuser::TrackPopupMenu(context_menu, - flags, - cursor_position.x, - cursor_position.y, - 0, - window, - std::ptr::null_mut()); + winuser::TrackPopupMenu( + context_menu, + flags, + cursor_position.x, + cursor_position.y, + 0, + window, + std::ptr::null_mut(), + ); winuser::PostMessageW(window, 0, 0, 0); info!("Closing notification context menu"); @@ -224,8 +230,10 @@ pub fn run() { unsafe { status = winuser::GetMessageW(&mut message, std::ptr::null_mut(), 0, 0); if status == -1 { - panic!("GetMessageW error: {}", - winapi::um::errhandlingapi::GetLastError()); + panic!( + "GetMessageW error: {}", + winapi::um::errhandlingapi::GetLastError() + ); } if status == 0 { break; @@ -236,34 +244,30 @@ pub fn run() { } } -pub unsafe extern "system" fn window_proc(window: HWND, - msg: UINT, - w_param: WPARAM, - l_param: LPARAM) - -> LRESULT { +pub unsafe extern "system" fn window_proc( + window: HWND, + msg: UINT, + w_param: WPARAM, + l_param: LPARAM, +) -> LRESULT { match msg { - winuser::WM_CREATE => { add_notification_icon(window); } - MESSAGE_NOTIFICATION_ICON => { - match LOWORD(l_param as DWORD) as u32 { - winuser::WM_RBUTTONUP => { - open_notification_context_menu(window); - } - _ => (), + MESSAGE_NOTIFICATION_ICON => match LOWORD(l_param as DWORD) as u32 { + winuser::WM_RBUTTONUP => { + open_notification_context_menu(window); } - } + _ => (), + }, - winuser::WM_COMMAND => { - match LOWORD(w_param as DWORD) as u32 { - MESSAGE_NOTIFICATION_ICON_QUIT => { - quit(window); - } - _ => (), + winuser::WM_COMMAND => match LOWORD(w_param as DWORD) as u32 { + MESSAGE_NOTIFICATION_ICON_QUIT => { + quit(window); } - } + _ => (), + }, winuser::WM_DESTROY => { remove_notification_icon(window); diff --git a/src/user.rs b/src/user.rs index 394d3f9..d798897 100644 --- a/src/user.rs +++ b/src/user.rs @@ -4,12 +4,12 @@ use diesel::prelude::*; use rand; use ring::{digest, pbkdf2}; -use db::ConnectionSource; use db::users; +use db::ConnectionSource; use errors::*; #[derive(Debug, Insertable, Queryable)] -#[table_name="users"] +#[table_name = "users"] pub struct User { pub name: String, pub password_salt: Vec<u8>, @@ -37,35 +37,41 @@ impl User { pub fn hash_password(salt: &Vec<u8>, password: &str) -> Vec<u8> { let mut hash: PasswordHash = [0; CREDENTIAL_LEN]; - pbkdf2::derive(DIGEST_ALG, - HASH_ITERATIONS, - salt, - password.as_bytes(), - &mut hash); + pbkdf2::derive( + DIGEST_ALG, + HASH_ITERATIONS, + salt, + password.as_bytes(), + &mut hash, + ); hash.to_vec() } -fn verify_password(password_hash: &Vec<u8>, - password_salt: &Vec<u8>, - attempted_password: &str) - -> bool { - pbkdf2::verify(DIGEST_ALG, - HASH_ITERATIONS, - password_salt, - attempted_password.as_bytes(), - password_hash) - .is_ok() +fn verify_password( + password_hash: &Vec<u8>, + password_salt: &Vec<u8>, + attempted_password: &str, +) -> bool { + pbkdf2::verify( + DIGEST_ALG, + HASH_ITERATIONS, + password_salt, + attempted_password.as_bytes(), + password_hash, + ).is_ok() } pub fn auth<T>(db: &T, username: &str, password: &str) -> Result<bool> - where T: ConnectionSource +where + T: ConnectionSource, { use db::users::dsl::*; let connection = db.get_connection(); match users - .select((password_hash, password_salt)) - .filter(name.eq(username)) - .get_result(connection.deref()) { + .select((password_hash, password_salt)) + .filter(name.eq(username)) + .get_result(connection.deref()) + { Err(diesel::result::Error::NotFound) => Ok(false), Ok((hash, salt)) => Ok(verify_password(&hash, &salt, password)), Err(e) => Err(e.into()), @@ -73,7 +79,8 @@ pub fn auth<T>(db: &T, username: &str, password: &str) -> Result<bool> } pub fn count<T>(db: &T) -> Result<i64> - where T: ConnectionSource +where + T: ConnectionSource, { use db::users::dsl::*; let connection = db.get_connection(); @@ -82,7 +89,8 @@ pub fn count<T>(db: &T) -> Result<i64> } pub fn is_admin<T>(db: &T, username: &str) -> Result<bool> - where T: ConnectionSource +where + T: ConnectionSource, { use db::users::dsl::*; let connection = db.get_connection(); @@ -94,7 +102,8 @@ pub fn is_admin<T>(db: &T, username: &str) -> Result<bool> } pub fn set_lastfm_session_key<T>(db: &T, username: &str, token: &str) -> Result<()> - where T: ConnectionSource +where + T: ConnectionSource, { use db::users::dsl::*; let connection = db.get_connection(); @@ -105,7 +114,8 @@ pub fn set_lastfm_session_key<T>(db: &T, username: &str, token: &str) -> Result< } pub fn get_lastfm_session_key<T>(db: &T, username: &str) -> Result<String> - where T: ConnectionSource +where + T: ConnectionSource, { use db::users::dsl::*; let connection = db.get_connection(); diff --git a/src/utils.rs b/src/utils.rs index 3cc34ac..184b240 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,6 @@ -use app_dirs::{AppDataType, AppInfo, app_root}; -use std::path::{Path, PathBuf}; +use app_dirs::{app_root, AppDataType, AppInfo}; use std::fs; +use std::path::{Path, PathBuf}; use errors::*; @@ -18,8 +18,7 @@ const APP_INFO: AppInfo = AppInfo { pub fn get_data_root() -> Result<PathBuf> { if let Ok(root) = app_root(AppDataType::UserData, &APP_INFO) { - fs::create_dir_all(&root) - .chain_err(|| format!("opening user data: {}", root.display()))?; + fs::create_dir_all(&root).chain_err(|| format!("opening user data: {}", root.display()))?; return Ok(root); } bail!("Could not retrieve data directory root"); @@ -55,10 +54,14 @@ pub fn get_audio_format(path: &Path) -> Option<AudioFormat> { #[test] fn test_get_audio_format() { - assert_eq!(get_audio_format(Path::new("animals/🐷/my🐖file.jpg")), - None); - assert_eq!(get_audio_format(Path::new("animals/🐷/my🐖file.flac")), - Some(AudioFormat::FLAC)); + assert_eq!( + get_audio_format(Path::new("animals/🐷/my🐖file.jpg")), + None + ); + assert_eq!( + get_audio_format(Path::new("animals/🐷/my🐖file.flac")), + Some(AudioFormat::FLAC) + ); } pub fn is_song(path: &Path) -> bool { diff --git a/src/vfs.rs b/src/vfs.rs index e537202..6ab395e 100644 --- a/src/vfs.rs +++ b/src/vfs.rs @@ -1,11 +1,11 @@ use core::ops::Deref; use diesel::prelude::*; use std::collections::HashMap; -use std::path::PathBuf; use std::path::Path; +use std::path::PathBuf; -use db::{ConnectionSource, DB}; use db::mount_points; +use db::{ConnectionSource, DB}; use errors::*; pub trait VFSSource { @@ -28,7 +28,7 @@ impl VFSSource for DB { } #[derive(Clone, Debug, Deserialize, Insertable, PartialEq, Queryable, Serialize)] -#[table_name="mount_points"] +#[table_name = "mount_points"] pub struct MountPoint { pub source: String, pub name: String, @@ -40,7 +40,9 @@ pub struct VFS { impl VFS { pub fn new() -> VFS { - VFS { mount_points: HashMap::new() } + VFS { + mount_points: HashMap::new(), + } } pub fn mount(&mut self, real_path: &Path, name: &str) -> Result<()> { @@ -55,10 +57,10 @@ impl VFS { Ok(p) => { let mount_path = Path::new(&name); return if p.components().count() == 0 { - Ok(mount_path.to_path_buf()) - } else { - Ok(mount_path.join(p)) - }; + Ok(mount_path.to_path_buf()) + } else { + Ok(mount_path.join(p)) + }; } Err(_) => (), } @@ -72,10 +74,10 @@ impl VFS { match virtual_path.strip_prefix(mount_path) { Ok(p) => { return if p.components().count() == 0 { - Ok(target.clone()) - } else { - Ok(target.join(p)) - }; + Ok(target.clone()) + } else { + Ok(target.join(p)) + }; } Err(_) => (), }