From e1934a8e928ae58535e11c045b124ab8c789d298 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Mon, 30 Nov 2020 20:27:39 -0800 Subject: [PATCH] Cleaned up startup code (#104) --- src/config.rs | 2 - src/db/mod.rs | 12 +- src/index/mod.rs | 61 +++---- src/main.rs | 274 ++++++++++---------------------- src/options.rs | 86 ++++++++++ src/service/constants.rs | 5 - src/service/dto.rs | 6 + src/service/mod.rs | 121 +++++++++++++- src/service/rocket/api.rs | 13 +- src/service/rocket/mod.rs | 45 +++++- src/service/rocket/server.rs | 78 --------- src/service/rocket/test.rs | 49 ++---- src/service/test/admin.rs | 12 +- src/service/test/auth.rs | 22 +-- src/service/test/collection.rs | 32 ++-- src/service/test/media.rs | 16 +- src/service/test/mod.rs | 4 +- src/service/test/playlist.rs | 22 +-- src/service/test/preferences.rs | 10 +- src/service/test/settings.rs | 16 +- src/service/test/swagger.rs | 4 +- src/service/test/web.rs | 4 +- src/thumbnails.rs | 23 ++- 23 files changed, 474 insertions(+), 443 deletions(-) create mode 100644 src/options.rs delete mode 100644 src/service/constants.rs delete mode 100644 src/service/rocket/server.rs diff --git a/src/config.rs b/src/config.rs index b470bdc..63902b3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,7 +2,6 @@ use anyhow::*; use core::ops::Deref; use diesel; use diesel::prelude::*; -use log::info; use regex::Regex; use serde::{Deserialize, Serialize}; use std::fs; @@ -61,7 +60,6 @@ impl Config { } pub fn parse_toml_file(path: &path::Path) -> Result { - info!("Config file path: {}", path.to_string_lossy()); let mut config_file = fs::File::open(path)?; let mut config_file_content = String::new(); config_file.read_to_string(&mut config_file_content)?; diff --git a/src/db/mod.rs b/src/db/mod.rs index 855636c..0a8d260 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -3,7 +3,7 @@ use diesel::r2d2::{self, ConnectionManager, PooledConnection}; use diesel::sqlite::SqliteConnection; use diesel::RunQueryDsl; use diesel_migrations; -use std::path::Path; +use std::path::{Path, PathBuf}; mod schema; @@ -16,6 +16,7 @@ embed_migrations!("migrations"); #[derive(Clone)] pub struct DB { pool: r2d2::Pool>, + location: PathBuf, } #[derive(Debug)] @@ -45,11 +46,18 @@ impl DB { let pool = diesel::r2d2::Pool::builder() .connection_customizer(Box::new(ConnectionCustomizer {})) .build(manager)?; - let db = DB { pool: pool }; + let db = DB { + pool: pool, + location: path.to_owned(), + }; db.migrate_up()?; Ok(db) } + pub fn location(&self) -> &Path { + &self.location + } + pub fn connect(&self) -> Result>> { self.pool.get().map_err(Error::new) } diff --git a/src/index/mod.rs b/src/index/mod.rs index a793748..56a57ee 100644 --- a/src/index/mod.rs +++ b/src/index/mod.rs @@ -22,46 +22,6 @@ pub use self::query::*; pub use self::types::*; pub use self::update::*; -pub fn builder(db: DB) -> IndexBuilder { - IndexBuilder { - db: db, - periodic_updates: true, - } -} - -pub struct IndexBuilder { - db: DB, - periodic_updates: bool, -} - -impl IndexBuilder { - pub fn periodic_updates(mut self, enabled: bool) -> IndexBuilder { - self.periodic_updates = enabled; - self - } - - pub fn build(self) -> Index { - let index = Index { - pending_reindex: Arc::new((Mutex::new(false), Condvar::new())), - db: self.db.clone(), - }; - - let commands_index = index.clone(); - std::thread::spawn(move || { - commands_index.process_commands(); - }); - - if self.periodic_updates { - let auto_index = index.clone(); - std::thread::spawn(move || { - auto_index.automatic_reindex(); - }); - } - - index - } -} - #[derive(Clone)] pub struct Index { db: DB, @@ -69,6 +29,20 @@ pub struct Index { } impl Index { + pub fn new(db: DB) -> Self { + let index = Self { + pending_reindex: Arc::new((Mutex::new(false), Condvar::new())), + db, + }; + + let commands_index = index.clone(); + std::thread::spawn(move || { + commands_index.process_commands(); + }); + + index + } + pub fn trigger_reindex(&self) { let (lock, cvar) = &*self.pending_reindex; let mut pending_reindex = lock.lock().unwrap(); @@ -76,6 +50,13 @@ impl Index { cvar.notify_one(); } + pub fn begin_periodic_updates(&self) { + let auto_index = self.clone(); + std::thread::spawn(move || { + auto_index.automatic_reindex(); + }); + } + fn process_commands(&self) { loop { { diff --git a/src/main.rs b/src/main.rs index 57b2a55..904b075 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,57 +9,45 @@ extern crate diesel_migrations; #[macro_use] extern crate flamer; -#[cfg(unix)] -use log::error; -#[cfg(unix)] -use sd_notify::{self, NotifyState}; -#[cfg(unix)] -use std::io::prelude::*; -#[cfg(unix)] -use unix_daemonize::{daemonize_redirect, ChdirMode}; - use anyhow::*; -use getopts::Options; -use log::info; +use log::{error, info}; use simplelog::{LevelFilter, SimpleLogger, TermLogger, TerminalMode}; -use std::fs; -use std::path::PathBuf; +mod artwork; mod config; mod db; mod ddns; mod index; mod lastfm; +mod options; mod playlist; mod service; - -mod artwork; mod thumbnails; mod ui; mod user; mod utils; mod vfs; -fn log_config() -> simplelog::Config { - simplelog::ConfigBuilder::new() - .set_location_level(LevelFilter::Error) - .build() -} - #[cfg(unix)] -fn daemonize(options: &getopts::Matches) -> Result<()> { - if options.opt_present("f") { +fn daemonize( + foreground: bool, + pid_file_path: &Option, + log_file_path: &Option, +) -> Result<()> { + use std::fs; + use std::io::Write; + use std::path::PathBuf; + use unix_daemonize::{daemonize_redirect, ChdirMode}; + + if foreground { return Ok(()); } - let log_path = options - .opt_str("log") - .map(PathBuf::from) - .unwrap_or_else(|| { - let mut path = PathBuf::from(option_env!("POLARIS_LOG_DIR").unwrap_or(".")); - path.push("polaris.log"); - path - }); + let log_path = log_file_path.clone().unwrap_or_else(|| { + let mut path = PathBuf::from(option_env!("POLARIS_LOG_DIR").unwrap_or(".")); + path.push("polaris.log"); + path + }); fs::create_dir_all(&log_path.parent().unwrap())?; let pid = match daemonize_redirect(Some(&log_path), Some(&log_path), ChdirMode::NoChdir) { @@ -67,14 +55,11 @@ fn daemonize(options: &getopts::Matches) -> Result<()> { Err(e) => bail!("Daemonize error: {:#?}", e), }; - let pid_path = options - .opt_str("pid") - .map(PathBuf::from) - .unwrap_or_else(|| { - let mut path = PathBuf::from(option_env!("POLARIS_PID_DIR").unwrap_or(".")); - path.push("polaris.pid"); - path - }); + let pid_path = pid_file_path.clone().unwrap_or_else(|| { + let mut path = PathBuf::from(option_env!("POLARIS_PID_DIR").unwrap_or(".")); + path.push("polaris.pid"); + path + }); fs::create_dir_all(&pid_path.parent().unwrap())?; let mut file = fs::File::create(pid_path)?; @@ -82,36 +67,10 @@ fn daemonize(options: &getopts::Matches) -> Result<()> { Ok(()) } -#[cfg(unix)] -fn init_log(log_level: LevelFilter, options: &getopts::Matches) -> Result<()> { - if options.opt_present("f") { - if let Err(e) = TermLogger::init(log_level, log_config(), TerminalMode::Stdout) { - println!("Error starting terminal logger: {}", e); - } else { - return Ok(()); - } - } - - if let Err(e) = SimpleLogger::init(log_level, log_config()) { - bail!("Error starting simple logger: {}", e); - } - Ok(()) -} - -#[cfg(windows)] -fn init_log(log_level: LevelFilter, _: &getopts::Matches) -> Result<()> { - if TermLogger::init(log_level, log_config(), TerminalMode::Stdout).is_err() { - if let Err(e) = SimpleLogger::init(log_level, log_config()) { - bail!("Error starting simple logger: {}", e); - } - }; - Ok(()) -} - #[cfg(unix)] fn notify_ready() { if let Ok(true) = sd_notify::booted() { - if let Err(e) = sd_notify::notify(true, &[NotifyState::Ready]) { + if let Err(e) = sd_notify::notify(true, &[sd_notify::NotifyState::Ready]) { error!("Unable to send ready notification: {}", e); } } @@ -120,151 +79,94 @@ fn notify_ready() { #[cfg(not(unix))] fn notify_ready() {} +fn init_logging(cli_options: &options::CLIOptions) -> Result<()> { + let log_level = cli_options.log_level.unwrap_or(LevelFilter::Info); + let log_config = simplelog::ConfigBuilder::new() + .set_location_level(LevelFilter::Error) + .build(); + + #[cfg(unix)] + let prefer_term_logger = cli_options.foreground; + + #[cfg(not(unix))] + let prefer_term_logger = true; + + if prefer_term_logger { + match TermLogger::init(log_level, log_config.clone(), TerminalMode::Stdout) { + Ok(_) => return Ok(()), + Err(e) => error!("Error starting terminal logger: {}", e), + } + } + SimpleLogger::init(log_level, log_config)?; + Ok(()) +} + fn main() -> Result<()> { // Parse CLI options let args: Vec = std::env::args().collect(); - let mut options = Options::new(); - options.optopt("c", "config", "set the configuration file", "FILE"); - 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("s", "swagger", "set the path to swagger files", "DIRECTORY"); - options.optopt( - "", - "cache", - "set the directory to use as cache", - "DIRECTORY", - ); - options.optopt("", "log", "set the path to the log file", "FILE"); - options.optopt("", "pid", "set the path to the pid file", "FILE"); - options.optopt( - "", - "log-level", - "set the log level to a value between 0 (off) and 3 (debug)", - "LEVEL", - ); + let options_manager = options::OptionsManager::new(); + let cli_options = options_manager.parse(&args[1..])?; - #[cfg(unix)] - options.optflag( - "f", - "foreground", - "run polaris in the foreground instead of daemonizing", - ); - - options.optflag("h", "help", "print this help menu"); - - let matches = options.parse(&args[1..])?; - - if matches.opt_present("h") { + if cli_options.show_help { let program = args[0].clone(); let brief = format!("Usage: {} [options]", program); - print!("{}", options.usage(&brief)); + print!("{}", options_manager.usage(&brief)); return Ok(()); } - let log_level = match matches.opt_str("log-level").as_ref().map(String::as_ref) { - Some("0") => LevelFilter::Off, - Some("1") => LevelFilter::Error, - Some("2") => LevelFilter::Info, - Some("3") => LevelFilter::Debug, - _ => LevelFilter::Info, - }; - - init_log(log_level, &matches)?; - #[cfg(unix)] - daemonize(&matches)?; + daemonize( + cli_options.foreground, + &cli_options.pid_file_path, + &cli_options.log_file_path, + )?; - // Init DB - let db_path = matches.opt_str("d").map(PathBuf::from).unwrap_or_else(|| { - let mut path = PathBuf::from(option_env!("POLARIS_DB_DIR").unwrap_or(".")); - path.push("db.sqlite"); - path - }); - fs::create_dir_all(&db_path.parent().unwrap())?; - info!("Database file path is {}", db_path.display()); - let db = db::DB::new(&db_path)?; + init_logging(&cli_options)?; - // Parse config - if let Some(config_path) = matches.opt_str("c").map(PathBuf::from) { - let config = config::parse_toml_file(&config_path)?; - info!("Applying configuration from {}", config_path.display()); - config::amend(&db, &config)?; + // Create service context + let mut context_builder = service::ContextBuilder::new(); + if let Some(port) = cli_options.port { + context_builder = context_builder.port(port); + } + if let Some(path) = cli_options.config_file_path { + info!("Config file location is {:#?}", path); + context_builder = context_builder.config_file_path(path); + } + if let Some(path) = cli_options.database_file_path { + context_builder = context_builder.database_file_path(path); + } + if let Some(path) = cli_options.web_dir_path { + context_builder = context_builder.web_dir_path(path); + } + if let Some(path) = cli_options.swagger_dir_path { + context_builder = context_builder.swagger_dir_path(path); + } + if let Some(path) = cli_options.cache_dir_path { + context_builder = context_builder.cache_dir_path(path); } - let auth_secret = config::get_auth_secret(&db)?; - // Locate web client files - let web_dir_path = match matches - .opt_str("w") - .or(option_env!("POLARIS_WEB_DIR").map(String::from)) - { - Some(s) => PathBuf::from(s), - None => [".", "web"].iter().collect(), - }; - fs::create_dir_all(&web_dir_path)?; - info!("Static files location is {}", web_dir_path.display()); - - // Locate swagger files - let swagger_dir_path = match matches - .opt_str("s") - .or(option_env!("POLARIS_SWAGGER_DIR").map(String::from)) - { - Some(s) => PathBuf::from(s), - None => [".", "docs", "swagger"].iter().collect(), - }; - fs::create_dir_all(&swagger_dir_path)?; - info!("Swagger files location is {}", swagger_dir_path.display()); - - // Initialize thumbnails manager - let mut thumbnails_path = PathBuf::from( - matches - .opt_str("cache") - .or(option_env!("POLARIS_CACHE_DIR").map(String::from)) - .unwrap_or(".".to_owned()), + let context = context_builder.build()?; + info!("Database file location is {:#?}", context.db.location()); + info!("Web client files location is {:#?}", context.web_dir_path); + info!("Swagger files location is {:#?}", context.swagger_dir_path); + info!( + "Thumbnails files location is {:#?}", + context.thumbnails_manager.get_directory() ); - thumbnails_path.push("thumbnails"); - fs::create_dir_all(&thumbnails_path)?; - info!("Thumbnails location is {}", thumbnails_path.display()); - let thumbnails_manager = thumbnails::ThumbnailsManager::new(&thumbnails_path); - // Endpoints - let api_url = "/api"; - let swagger_url = "/swagger"; - let web_url = "/"; - info!("Mounting API on {}", api_url); - info!("Mounting web client files on {}", web_url); - info!("Mounting swagger files on {}", swagger_url); - - // Init index - let index = index::builder(db.clone()).periodic_updates(true).build(); + // Begin collection scans + context.index.begin_periodic_updates(); // Start DDNS updates - let db_ddns = db.clone(); + let db_ddns = context.db.clone(); std::thread::spawn(move || { ddns::run(&db_ddns); }); // Start server info!("Starting up server"); - let port: u16 = matches - .opt_str("p") - .unwrap_or_else(|| "5050".to_owned()) - .parse() - .with_context(|| "Invalid port number")?; - let db_server = db.clone(); std::thread::spawn(move || { - let _ = service::server::run( - port, - &auth_secret, - api_url, - web_url, - &web_dir_path, - swagger_url, - &swagger_dir_path, - db_server, - index, - thumbnails_manager, - ); + let _ = service::run(context); }); // Send readiness notification diff --git a/src/options.rs b/src/options.rs new file mode 100644 index 0000000..c422b0a --- /dev/null +++ b/src/options.rs @@ -0,0 +1,86 @@ +use anyhow::Result; +use simplelog::LevelFilter; +use std::path::PathBuf; + +pub struct CLIOptions { + pub show_help: bool, + #[cfg(unix)] + pub foreground: bool, + pub log_file_path: Option, + pub pid_file_path: Option, + pub config_file_path: Option, + pub database_file_path: Option, + pub cache_dir_path: Option, + pub web_dir_path: Option, + pub swagger_dir_path: Option, + pub port: Option, + pub log_level: Option, +} + +pub struct OptionsManager { + protocol: getopts::Options, +} + +impl OptionsManager { + pub fn new() -> Self { + Self { + protocol: get_options(), + } + } + + pub fn parse(&self, input: &[String]) -> Result { + let matches = self.protocol.parse(input)?; + + Ok(CLIOptions { + show_help: matches.opt_present("h"), + #[cfg(unix)] + foreground: matches.opt_present("f"), + log_file_path: matches.opt_str("log").map(PathBuf::from), + pid_file_path: matches.opt_str("pid").map(PathBuf::from), + config_file_path: matches.opt_str("c").map(PathBuf::from), + database_file_path: matches.opt_str("d").map(PathBuf::from), + cache_dir_path: matches.opt_str("cache").map(PathBuf::from), + web_dir_path: matches.opt_str("w").map(PathBuf::from), + swagger_dir_path: matches.opt_str("s").map(PathBuf::from), + port: matches.opt_str("p").and_then(|p| p.parse().ok()), + log_level: matches.opt_str("log-level").and_then(|l| l.parse().ok()), + }) + } + + pub fn usage(&self, brief: &str) -> String { + self.protocol.usage(brief) + } +} + +fn get_options() -> getopts::Options { + let mut options = getopts::Options::new(); + options.optopt("c", "config", "set the configuration file", "FILE"); + 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("s", "swagger", "set the path to swagger files", "DIRECTORY"); + options.optopt( + "", + "cache", + "set the directory to use as cache", + "DIRECTORY", + ); + options.optopt("", "log", "set the path to the log file", "FILE"); + options.optopt("", "pid", "set the path to the pid file", "FILE"); + options.optopt( + "", + "log-level", + "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("h", "help", "print this help menu"); + options +} diff --git a/src/service/constants.rs b/src/service/constants.rs deleted file mode 100644 index c9cc5d1..0000000 --- a/src/service/constants.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub const API_MAJOR_VERSION: i32 = 5; -pub const API_MINOR_VERSION: i32 = 0; -pub const COOKIE_SESSION: &str = "session"; -pub const COOKIE_USERNAME: &str = "username"; -pub const COOKIE_ADMIN: &str = "admin"; diff --git a/src/service/dto.rs b/src/service/dto.rs index 124e6c7..847f316 100644 --- a/src/service/dto.rs +++ b/src/service/dto.rs @@ -1,5 +1,11 @@ use serde::{Deserialize, Serialize}; +pub const API_MAJOR_VERSION: i32 = 5; +pub const API_MINOR_VERSION: i32 = 0; +pub const COOKIE_SESSION: &str = "session"; +pub const COOKIE_USERNAME: &str = "username"; +pub const COOKIE_ADMIN: &str = "admin"; + #[derive(PartialEq, Debug, Serialize, Deserialize)] pub struct Version { pub major: i32, diff --git a/src/service/mod.rs b/src/service/mod.rs index e975016..39ed4cf 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -1,4 +1,11 @@ -mod constants; +use crate::db::DB; +use crate::index::Index; +use crate::thumbnails::ThumbnailsManager; +use std::fs; +use std::path::PathBuf; + +use crate::config; + mod dto; mod error; @@ -9,3 +16,115 @@ mod test; mod rocket; #[cfg(feature = "service-rocket")] pub use self::rocket::*; + +pub struct Context { + pub port: u16, + pub auth_secret: Vec, + pub web_dir_path: PathBuf, + pub swagger_dir_path: PathBuf, + pub web_url: String, + pub swagger_url: String, + pub api_url: String, + pub db: DB, + pub index: Index, + pub thumbnails_manager: ThumbnailsManager, +} + +pub struct ContextBuilder { + port: Option, + config_file_path: Option, + database_file_path: Option, + web_dir_path: Option, + swagger_dir_path: Option, + cache_dir_path: Option, +} + +impl ContextBuilder { + pub fn new() -> Self { + Self { + port: None, + config_file_path: None, + database_file_path: None, + web_dir_path: None, + swagger_dir_path: None, + cache_dir_path: None, + } + } + + pub fn build(self) -> anyhow::Result { + let db_path = self.database_file_path.unwrap_or_else(|| { + let mut path = PathBuf::from(option_env!("POLARIS_DB_DIR").unwrap_or(".")); + path.push("db.sqlite"); + path + }); + fs::create_dir_all(&db_path.parent().unwrap())?; + let db = DB::new(&db_path)?; + + if let Some(config_path) = self.config_file_path { + let config = config::parse_toml_file(&config_path)?; + config::amend(&db, &config)?; + } + let auth_secret = config::get_auth_secret(&db)?; + + let web_dir_path = self + .web_dir_path + .or(option_env!("POLARIS_WEB_DIR").map(PathBuf::from)) + .unwrap_or([".", "web"].iter().collect()); + fs::create_dir_all(&web_dir_path)?; + + let swagger_dir_path = self + .swagger_dir_path + .or(option_env!("POLARIS_SWAGGER_DIR").map(PathBuf::from)) + .unwrap_or([".", "docs", "swagger"].iter().collect()); + fs::create_dir_all(&swagger_dir_path)?; + + let mut thumbnails_dir_path = self + .cache_dir_path + .or(option_env!("POLARIS_CACHE_DIR").map(PathBuf::from)) + .unwrap_or(PathBuf::from(".").to_owned()); + thumbnails_dir_path.push("thumbnails"); + + Ok(Context { + port: self.port.unwrap_or(5050), + auth_secret, + api_url: "/api".to_owned(), + swagger_url: "/swagger".to_owned(), + web_url: "/".to_owned(), + web_dir_path, + swagger_dir_path, + thumbnails_manager: ThumbnailsManager::new(thumbnails_dir_path), + index: Index::new(db.clone()), + db, + }) + } + + pub fn port(mut self, port: u16) -> Self { + self.port = Some(port); + self + } + + pub fn config_file_path(mut self, path: PathBuf) -> Self { + self.config_file_path = Some(path); + self + } + + pub fn database_file_path(mut self, path: PathBuf) -> Self { + self.database_file_path = Some(path); + self + } + + pub fn web_dir_path(mut self, path: PathBuf) -> Self { + self.web_dir_path = Some(path); + self + } + + pub fn swagger_dir_path(mut self, path: PathBuf) -> Self { + self.swagger_dir_path = Some(path); + self + } + + pub fn cache_dir_path(mut self, path: PathBuf) -> Self { + self.cache_dir_path = Some(path); + self + } +} diff --git a/src/service/rocket/api.rs b/src/service/rocket/api.rs index e15cdfe..727b180 100644 --- a/src/service/rocket/api.rs +++ b/src/service/rocket/api.rs @@ -18,7 +18,6 @@ use crate::db::DB; use crate::index::{self, Index, QueryError}; use crate::lastfm; use crate::playlist::{self, PlaylistError}; -use crate::service::constants::*; use crate::service::dto; use crate::service::error::APIError; use crate::thumbnails::{ThumbnailOptions, ThumbnailsManager}; @@ -96,20 +95,20 @@ struct Auth { fn add_session_cookies(cookies: &mut Cookies, username: &str, is_admin: bool) -> () { let duration = Duration::days(1); - let session_cookie = Cookie::build(COOKIE_SESSION, username.to_owned()) + let session_cookie = Cookie::build(dto::COOKIE_SESSION, username.to_owned()) .same_site(rocket::http::SameSite::Lax) .http_only(true) .max_age(duration) .finish(); - let username_cookie = Cookie::build(COOKIE_USERNAME, username.to_owned()) + let username_cookie = Cookie::build(dto::COOKIE_USERNAME, username.to_owned()) .same_site(rocket::http::SameSite::Lax) .http_only(false) .max_age(duration) .path("/") .finish(); - let is_admin_cookie = Cookie::build(COOKIE_ADMIN, format!("{}", is_admin)) + let is_admin_cookie = Cookie::build(dto::COOKIE_ADMIN, format!("{}", is_admin)) .same_site(rocket::http::SameSite::Lax) .http_only(false) .max_age(duration) @@ -131,7 +130,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for Auth { _ => return Outcome::Failure((Status::InternalServerError, ())), }; - if let Some(u) = cookies.get_private(COOKIE_SESSION) { + if let Some(u) = cookies.get_private(dto::COOKIE_SESSION) { let exists = match user::exists(db.deref().deref(), u.value()) { Ok(e) => e, Err(_) => return Outcome::Failure((Status::InternalServerError, ())), @@ -217,8 +216,8 @@ impl From for PathBuf { #[get("/version")] fn version() -> Json { let current_version = dto::Version { - major: API_MAJOR_VERSION, - minor: API_MINOR_VERSION, + major: dto::API_MAJOR_VERSION, + minor: dto::API_MINOR_VERSION, }; Json(current_version) } diff --git a/src/service/rocket/mod.rs b/src/service/rocket/mod.rs index 10fbc8d..2f3fd36 100644 --- a/src/service/rocket/mod.rs +++ b/src/service/rocket/mod.rs @@ -1,7 +1,48 @@ +use anyhow::*; +use rocket; +use rocket::config::{Environment, LoggingLevel}; +use rocket_contrib::serve::{Options, StaticFiles}; + +use crate::service; + mod api; mod serve; -pub mod server; - #[cfg(test)] pub mod test; + +pub fn get_server(context: service::Context) -> Result { + let mut config = rocket::Config::build(Environment::Production) + .log_level(LoggingLevel::Normal) + .port(context.port) + .keep_alive(0) + .finalize()?; + + let encoded = base64::encode(&context.auth_secret); + config.set_secret_key(encoded)?; + + let swagger_routes_rank = 0; + let web_routes_rank = swagger_routes_rank + 1; + let static_file_options = Options::Index | Options::NormalizeDirs; + + Ok(rocket::custom(config) + .manage(context.db) + .manage(context.index) + .manage(context.thumbnails_manager) + .mount(&context.api_url, api::get_routes()) + .mount( + &context.swagger_url, + StaticFiles::new(context.swagger_dir_path, static_file_options) + .rank(swagger_routes_rank), + ) + .mount( + &context.web_url, + StaticFiles::new(context.web_dir_path, static_file_options).rank(web_routes_rank), + )) +} + +pub fn run(context: service::Context) -> Result<()> { + let server = get_server(context)?; + server.launch(); + Ok(()) +} diff --git a/src/service/rocket/server.rs b/src/service/rocket/server.rs deleted file mode 100644 index 5388a83..0000000 --- a/src/service/rocket/server.rs +++ /dev/null @@ -1,78 +0,0 @@ -use anyhow::*; -use rocket; -use rocket::config::{Environment, LoggingLevel}; -use rocket_contrib::serve::{Options, StaticFiles}; -use std::path::Path; - -use super::api; -use crate::db::DB; -use crate::index::Index; -use crate::thumbnails::ThumbnailsManager; - -pub fn get_server( - port: u16, - auth_secret: &[u8], - api_url: &str, - web_url: &str, - web_dir_path: &Path, - swagger_url: &str, - swagger_dir_path: &Path, - db: DB, - command_sender: Index, - thumbnails_manager: ThumbnailsManager, -) -> Result { - let mut config = rocket::Config::build(Environment::Production) - .log_level(LoggingLevel::Normal) - .port(port) - .keep_alive(0) - .finalize()?; - - let encoded = base64::encode(auth_secret); - config.set_secret_key(encoded)?; - - let swagger_routes_rank = 0; - let web_routes_rank = swagger_routes_rank + 1; - let static_file_options = Options::Index | Options::NormalizeDirs; - - Ok(rocket::custom(config) - .manage(db) - .manage(command_sender) - .manage(thumbnails_manager) - .mount(&api_url, api::get_routes()) - .mount( - &swagger_url, - StaticFiles::new(swagger_dir_path, static_file_options).rank(swagger_routes_rank), - ) - .mount( - &web_url, - StaticFiles::new(web_dir_path, static_file_options).rank(web_routes_rank), - )) -} - -pub fn run( - port: u16, - auth_secret: &[u8], - api_url: &str, - web_url: &str, - web_dir_path: &Path, - swagger_url: &str, - swagger_dir_path: &Path, - db: DB, - command_sender: Index, - thumbnails_manager: ThumbnailsManager, -) -> Result<()> { - let server = get_server( - port, - auth_secret, - api_url, - web_url, - web_dir_path, - swagger_url, - swagger_dir_path, - db, - command_sender, - thumbnails_manager, - )?; - server.launch(); - Ok(()) -} diff --git a/src/service/rocket/test.rs b/src/service/rocket/test.rs index 9fdd438..98b20fc 100644 --- a/src/service/rocket/test.rs +++ b/src/service/rocket/test.rs @@ -4,13 +4,10 @@ use rocket::local::{Client, LocalResponse}; use serde::de::DeserializeOwned; use serde::Serialize; use std::fs; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; -use super::server; -use crate::db::DB; -use crate::index; +use crate::service; use crate::service::test::{protocol, TestService}; -use crate::thumbnails::ThumbnailsManager; pub struct RocketTestService { client: Client, @@ -62,44 +59,24 @@ impl RocketTestService { } impl TestService for RocketTestService { - fn new(unique_db_name: &str) -> Self { - let mut db_path = PathBuf::new(); - db_path.push("test-output"); + fn new(test_name: &str) -> Self { + let mut db_path: PathBuf = ["test-output", test_name].iter().collect(); fs::create_dir_all(&db_path).unwrap(); + db_path.push("db.sqlite"); - db_path.push(format!("{}.sqlite", unique_db_name)); if db_path.exists() { fs::remove_file(&db_path).unwrap(); } - let db = DB::new(&db_path).unwrap(); + let context = service::ContextBuilder::new() + .database_file_path(db_path) + .web_dir_path(Path::new("web").into()) + .swagger_dir_path(["docs", "swagger"].iter().collect()) + .cache_dir_path(["test-output", test_name].iter().collect()) + .build() + .unwrap(); - let web_dir_path = PathBuf::from("web"); - let mut swagger_dir_path = PathBuf::from("docs"); - swagger_dir_path.push("swagger"); - let index = index::builder(db.clone()).periodic_updates(false).build(); - - let mut thumbnails_path = PathBuf::new(); - thumbnails_path.push("test-output"); - thumbnails_path.push("thumbnails"); - thumbnails_path.push(unique_db_name); - let thumbnails_manager = ThumbnailsManager::new(thumbnails_path.as_path()); - - let auth_secret: [u8; 32] = [0; 32]; - - let server = server::get_server( - 5050, - &auth_secret, - "/api", - "/", - &web_dir_path, - "/swagger", - &swagger_dir_path, - db, - index, - thumbnails_manager, - ) - .unwrap(); + let server = service::get_server(context).unwrap(); let client = Client::new(server).unwrap(); let request_builder = protocol::RequestBuilder::new(); RocketTestService { diff --git a/src/service/test/admin.rs b/src/service/test/admin.rs index 3a008f5..8dd0a43 100644 --- a/src/service/test/admin.rs +++ b/src/service/test/admin.rs @@ -3,11 +3,11 @@ use http::StatusCode; use crate::index; use crate::service::dto; use crate::service::test::{ServiceType, TestService}; -use crate::unique_db_name; +use crate::test_name; #[test] fn test_returns_api_version() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().version(); let response = service.fetch_json::<_, dto::Version>(&request); assert_eq!(response.status(), StatusCode::OK); @@ -15,7 +15,7 @@ fn test_returns_api_version() { #[test] fn test_initial_setup_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().initial_setup(); { let response = service.fetch_json::<_, dto::InitialSetup>(&request); @@ -44,7 +44,7 @@ fn test_initial_setup_golden_path() { #[test] fn test_trigger_index_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); @@ -63,7 +63,7 @@ fn test_trigger_index_golden_path() { #[test] fn test_trigger_index_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); let request = service.request_builder().trigger_index(); let response = service.fetch(&request); @@ -72,7 +72,7 @@ fn test_trigger_index_requires_auth() { #[test] fn test_trigger_index_requires_admin() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); let request = service.request_builder().trigger_index(); diff --git a/src/service/test/auth.rs b/src/service/test/auth.rs index d995499..8c82841 100644 --- a/src/service/test/auth.rs +++ b/src/service/test/auth.rs @@ -2,9 +2,9 @@ use cookie::Cookie; use headers::{self, HeaderMapExt}; use http::{Response, StatusCode}; -use crate::service::constants::*; +use crate::service::dto; use crate::service::test::{constants::*, ServiceType, TestService}; -use crate::unique_db_name; +use crate::test_name; fn validate_cookies(response: &Response) { let cookies: Vec = response @@ -13,14 +13,14 @@ fn validate_cookies(response: &Response) { .iter() .map(|c| Cookie::parse(c.to_str().unwrap()).unwrap()) .collect(); - assert!(cookies.iter().any(|c| c.name() == COOKIE_SESSION)); - assert!(cookies.iter().any(|c| c.name() == COOKIE_USERNAME)); - assert!(cookies.iter().any(|c| c.name() == COOKIE_ADMIN)); + assert!(cookies.iter().any(|c| c.name() == dto::COOKIE_SESSION)); + assert!(cookies.iter().any(|c| c.name() == dto::COOKIE_USERNAME)); + assert!(cookies.iter().any(|c| c.name() == dto::COOKIE_ADMIN)); } #[test] fn test_login_rejects_bad_username() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); let request = service.request_builder().login("garbage", TEST_PASSWORD); @@ -30,7 +30,7 @@ fn test_login_rejects_bad_username() { #[test] fn test_login_rejects_bad_password() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); let request = service.request_builder().login(TEST_USERNAME, "garbage"); @@ -40,7 +40,7 @@ fn test_login_rejects_bad_password() { #[test] fn test_login_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); let request = service @@ -54,7 +54,7 @@ fn test_login_golden_path() { #[test] fn test_authentication_via_http_header_rejects_bad_username() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); let mut request = service.request_builder().random(); @@ -67,7 +67,7 @@ fn test_authentication_via_http_header_rejects_bad_username() { #[test] fn test_authentication_via_http_header_rejects_bad_password() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); let mut request = service.request_builder().random(); @@ -80,7 +80,7 @@ fn test_authentication_via_http_header_rejects_bad_password() { #[test] fn test_authentication_via_http_header_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); let mut request = service.request_builder().random(); diff --git a/src/service/test/collection.rs b/src/service/test/collection.rs index 5aede1b..f994e8f 100644 --- a/src/service/test/collection.rs +++ b/src/service/test/collection.rs @@ -3,11 +3,11 @@ use std::path::{Path, PathBuf}; use crate::index; use crate::service::test::{constants::*, ServiceType, TestService}; -use crate::unique_db_name; +use crate::test_name; #[test] fn test_browse_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().browse(&PathBuf::new()); let response = service.fetch(&request); assert_eq!(response.status(), StatusCode::UNAUTHORIZED); @@ -15,7 +15,7 @@ fn test_browse_requires_auth() { #[test] fn test_browse_root() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); service.index(); @@ -30,7 +30,7 @@ fn test_browse_root() { #[test] fn test_browse_directory() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); service.index(); @@ -46,7 +46,7 @@ fn test_browse_directory() { #[test] fn test_browse_bad_directory() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); @@ -58,7 +58,7 @@ fn test_browse_bad_directory() { #[test] fn test_flatten_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().flatten(&PathBuf::new()); let response = service.fetch(&request); assert_eq!(response.status(), StatusCode::UNAUTHORIZED); @@ -66,7 +66,7 @@ fn test_flatten_requires_auth() { #[test] fn test_flatten_root() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); service.index(); @@ -81,7 +81,7 @@ fn test_flatten_root() { #[test] fn test_flatten_directory() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); service.index(); @@ -98,7 +98,7 @@ fn test_flatten_directory() { #[test] fn test_flatten_bad_directory() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); @@ -110,7 +110,7 @@ fn test_flatten_bad_directory() { #[test] fn test_random_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().random(); let response = service.fetch(&request); assert_eq!(response.status(), StatusCode::UNAUTHORIZED); @@ -118,7 +118,7 @@ fn test_random_requires_auth() { #[test] fn test_random() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); service.index(); @@ -133,7 +133,7 @@ fn test_random() { #[test] fn test_recent_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().recent(); let response = service.fetch(&request); assert_eq!(response.status(), StatusCode::UNAUTHORIZED); @@ -141,7 +141,7 @@ fn test_recent_requires_auth() { #[test] fn test_recent() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); service.index(); @@ -156,7 +156,7 @@ fn test_recent() { #[test] fn test_search_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().search(""); let response = service.fetch(&request); assert_eq!(response.status(), StatusCode::UNAUTHORIZED); @@ -164,7 +164,7 @@ fn test_search_requires_auth() { #[test] fn test_search_without_query() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); @@ -175,7 +175,7 @@ fn test_search_without_query() { #[test] fn test_search_with_query() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); service.index(); diff --git a/src/service/test/media.rs b/src/service/test/media.rs index 81c7a92..3ca3065 100644 --- a/src/service/test/media.rs +++ b/src/service/test/media.rs @@ -2,11 +2,11 @@ use http::{header, HeaderValue, StatusCode}; use std::path::PathBuf; use crate::service::test::{constants::*, ServiceType, TestService}; -use crate::unique_db_name; +use crate::test_name; #[test] fn test_audio_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let path: PathBuf = [TEST_MOUNT_NAME, "Khemmis", "Hunted", "02 - Candlelight.mp3"] .iter() @@ -19,7 +19,7 @@ fn test_audio_requires_auth() { #[test] fn test_audio_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); service.index(); @@ -37,7 +37,7 @@ fn test_audio_golden_path() { #[test] fn test_audio_partial_content() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); service.index(); @@ -65,7 +65,7 @@ fn test_audio_partial_content() { #[test] fn test_audio_bad_path_returns_not_found() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); @@ -78,7 +78,7 @@ fn test_audio_bad_path_returns_not_found() { #[test] fn test_thumbnail_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let path: PathBuf = [TEST_MOUNT_NAME, "Khemmis", "Hunted", "Folder.jpg"] .iter() @@ -92,7 +92,7 @@ fn test_thumbnail_requires_auth() { #[test] fn test_thumbnail_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); service.index(); @@ -110,7 +110,7 @@ fn test_thumbnail_golden_path() { #[test] fn test_thumbnail_bad_path_returns_not_found() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); diff --git a/src/service/test/mod.rs b/src/service/test/mod.rs index 615cead..7306be0 100644 --- a/src/service/test/mod.rs +++ b/src/service/test/mod.rs @@ -24,7 +24,7 @@ use crate::{config, index, vfs}; pub use crate::service::rocket::test::ServiceType; #[macro_export] -macro_rules! unique_db_name { +macro_rules! test_name { () => {{ let file_name = file!(); let file_name = file_name.replace("/", "-"); @@ -34,7 +34,7 @@ macro_rules! unique_db_name { } pub trait TestService { - fn new(unique_db_name: &str) -> Self; + fn new(test_name: &str) -> Self; fn request_builder(&self) -> &protocol::RequestBuilder; fn fetch(&mut self, request: &Request) -> Response<()>; fn fetch_bytes(&mut self, request: &Request) -> Response>; diff --git a/src/service/test/playlist.rs b/src/service/test/playlist.rs index ef12d5a..a9945c2 100644 --- a/src/service/test/playlist.rs +++ b/src/service/test/playlist.rs @@ -3,11 +3,11 @@ use http::StatusCode; use crate::index; use crate::service::dto; use crate::service::test::{constants::*, ServiceType, TestService}; -use crate::unique_db_name; +use crate::test_name; #[test] fn test_list_playlists_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().playlists(); let response = service.fetch(&request); assert_eq!(response.status(), StatusCode::UNAUTHORIZED); @@ -15,7 +15,7 @@ fn test_list_playlists_requires_auth() { #[test] fn test_list_playlists_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); let request = service.request_builder().playlists(); @@ -25,7 +25,7 @@ fn test_list_playlists_golden_path() { #[test] fn test_save_playlist_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let my_playlist = dto::SavePlaylistInput { tracks: Vec::new() }; let request = service .request_builder() @@ -36,7 +36,7 @@ fn test_save_playlist_requires_auth() { #[test] fn test_save_playlist_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); @@ -50,7 +50,7 @@ fn test_save_playlist_golden_path() { #[test] fn test_get_playlist_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().read_playlist(TEST_PLAYLIST_NAME); let response = service.fetch(&request); assert_eq!(response.status(), StatusCode::UNAUTHORIZED); @@ -58,7 +58,7 @@ fn test_get_playlist_requires_auth() { #[test] fn test_get_playlist_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); @@ -78,7 +78,7 @@ fn test_get_playlist_golden_path() { #[test] fn test_get_playlist_bad_name_returns_not_found() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); @@ -89,7 +89,7 @@ fn test_get_playlist_bad_name_returns_not_found() { #[test] fn test_delete_playlist_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service .request_builder() .delete_playlist(TEST_PLAYLIST_NAME); @@ -99,7 +99,7 @@ fn test_delete_playlist_requires_auth() { #[test] fn test_delete_playlist_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); @@ -121,7 +121,7 @@ fn test_delete_playlist_golden_path() { #[test] fn test_delete_playlist_bad_name_returns_not_found() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); diff --git a/src/service/test/preferences.rs b/src/service/test/preferences.rs index fd0183a..7176992 100644 --- a/src/service/test/preferences.rs +++ b/src/service/test/preferences.rs @@ -2,11 +2,11 @@ use http::StatusCode; use crate::config; use crate::service::test::{ServiceType, TestService}; -use crate::unique_db_name; +use crate::test_name; #[test] fn test_get_preferences_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().get_preferences(); let response = service.fetch(&request); assert_eq!(response.status(), StatusCode::UNAUTHORIZED); @@ -14,7 +14,7 @@ fn test_get_preferences_requires_auth() { #[test] fn test_get_preferences_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); @@ -25,7 +25,7 @@ fn test_get_preferences_golden_path() { #[test] fn test_put_preferences_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service .request_builder() .put_preferences(config::Preferences::default()); @@ -35,7 +35,7 @@ fn test_put_preferences_requires_auth() { #[test] fn test_put_preferences_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); diff --git a/src/service/test/settings.rs b/src/service/test/settings.rs index aaded6b..92f5785 100644 --- a/src/service/test/settings.rs +++ b/src/service/test/settings.rs @@ -2,11 +2,11 @@ use http::StatusCode; use crate::config; use crate::service::test::{constants::*, ServiceType, TestService}; -use crate::unique_db_name; +use crate::test_name; #[test] fn test_get_settings_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); let request = service.request_builder().get_settings(); @@ -16,7 +16,7 @@ fn test_get_settings_requires_auth() { #[test] fn test_get_settings_requires_admin() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); @@ -27,7 +27,7 @@ fn test_get_settings_requires_admin() { #[test] fn test_get_settings_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); @@ -38,7 +38,7 @@ fn test_get_settings_golden_path() { #[test] fn test_put_settings_requires_auth() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); let request = service .request_builder() @@ -49,7 +49,7 @@ fn test_put_settings_requires_auth() { #[test] fn test_put_settings_requires_admin() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login(); let request = service @@ -61,7 +61,7 @@ fn test_put_settings_requires_admin() { #[test] fn test_put_settings_golden_path() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); @@ -74,7 +74,7 @@ fn test_put_settings_golden_path() { #[test] fn test_put_settings_cannot_unadmin_self() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); service.complete_initial_setup(); service.login_admin(); diff --git a/src/service/test/swagger.rs b/src/service/test/swagger.rs index ef23126..0bb94c6 100644 --- a/src/service/test/swagger.rs +++ b/src/service/test/swagger.rs @@ -1,11 +1,11 @@ use http::StatusCode; use crate::service::test::{ServiceType, TestService}; -use crate::unique_db_name; +use crate::test_name; #[test] fn test_swagger_can_get_index() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().swagger_index(); let response = service.fetch_bytes(&request); assert_eq!(response.status(), StatusCode::OK); diff --git a/src/service/test/web.rs b/src/service/test/web.rs index e8ac9fe..fcdd0fb 100644 --- a/src/service/test/web.rs +++ b/src/service/test/web.rs @@ -1,9 +1,9 @@ use crate::service::test::{ServiceType, TestService}; -use crate::unique_db_name; +use crate::test_name; #[test] fn test_web_can_get_index() { - let mut service = ServiceType::new(&unique_db_name!()); + let mut service = ServiceType::new(&test_name!()); let request = service.request_builder().web_index(); let _response = service.fetch_bytes(&request); } diff --git a/src/thumbnails.rs b/src/thumbnails.rs index a2a64a7..9259b09 100644 --- a/src/thumbnails.rs +++ b/src/thumbnails.rs @@ -3,23 +3,27 @@ use image::imageops::FilterType; use image::{DynamicImage, GenericImage, GenericImageView, ImageBuffer, ImageOutputFormat}; use std::cmp; use std::collections::hash_map::DefaultHasher; -use std::fs::{DirBuilder, File}; +use std::fs::{self, File}; use std::hash::{Hash, Hasher}; use std::path::*; use crate::artwork; pub struct ThumbnailsManager { - thumbnails_path: PathBuf, + thumbnails_dir_path: PathBuf, } impl ThumbnailsManager { - pub fn new(thumbnails_path: &Path) -> ThumbnailsManager { + pub fn new(thumbnails_dir_path: PathBuf) -> ThumbnailsManager { ThumbnailsManager { - thumbnails_path: thumbnails_path.to_owned(), + thumbnails_dir_path, } } + pub fn get_directory(&self) -> &Path { + &self.thumbnails_dir_path + } + pub fn get_thumbnail( &self, image_path: &Path, @@ -31,20 +35,13 @@ impl ThumbnailsManager { } } - fn create_thumbnails_directory(&self) -> Result<()> { - let mut dir_builder = DirBuilder::new(); - dir_builder.recursive(true); - dir_builder.create(self.thumbnails_path.as_path())?; - Ok(()) - } - fn get_thumbnail_path( &self, image_path: &Path, thumbnailoptions: &ThumbnailOptions, ) -> PathBuf { let hash = hash(image_path, thumbnailoptions); - let mut thumbnail_path = self.thumbnails_path.clone(); + let mut thumbnail_path = self.thumbnails_dir_path.clone(); thumbnail_path.push(format!("{}.jpg", hash.to_string())); thumbnail_path } @@ -70,7 +67,7 @@ impl ThumbnailsManager { let thumbnail = generate_thumbnail(image_path, thumbnailoptions)?; let quality = 80; - self.create_thumbnails_directory()?; + fs::create_dir_all(&self.thumbnails_dir_path)?; let path = self.get_thumbnail_path(image_path, thumbnailoptions); let mut out_file = File::create(&path)?; thumbnail.write_to(&mut out_file, ImageOutputFormat::Jpeg(quality))?;