From 4a0bcf394ecbb4421f5e76faea3c630455b4952e Mon Sep 17 00:00:00 2001 From: lifegpc Date: Sun, 18 Sep 2022 07:28:52 +0000 Subject: [PATCH] Update --- src/db/config.rs | 81 +++++++++++++++++++++++++++++++++++++++++- src/db/mod.rs | 24 ++++++++++++- src/db/sqlite/db.rs | 40 +++++++++++++++++++++ src/db/sqlite/error.rs | 4 ++- src/db/sqlite/mod.rs | 2 ++ src/db/traits.rs | 2 +- src/opthelper.rs | 12 +++++++ src/server/context.rs | 7 ++++ src/settings_list.rs | 4 +++ 9 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 src/db/sqlite/db.rs diff --git a/src/db/config.rs b/src/db/config.rs index bb78062..4c5117c 100644 --- a/src/db/config.rs +++ b/src/db/config.rs @@ -1,7 +1,86 @@ -pub struct PixivDownloaderDbConfig {} +use crate::ext::try_err::TryErr; +use crate::gettext; +use json::JsonValue; + +#[cfg(feature = "db_sqlite")] +pub struct PixivDownloaderSqliteConfig { + /// The path of database file + pub path: String, +} + +impl Default for PixivDownloaderSqliteConfig { + fn default() -> Self { + Self { + path: "pixiv_downloader.db".to_string(), + } + } +} + +pub enum PixivDownloaderDbConfig { + #[cfg(feature = "db_sqlite")] + Sqlite(PixivDownloaderSqliteConfig), + #[allow(dead_code)] + /// No default config is provided + None, +} + +#[derive(Debug)] +pub enum PixivDownloaderDbConfigError { + UnkonwnDbType, + MissingField(String), +} + +impl std::fmt::Display for PixivDownloaderDbConfigError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::UnkonwnDbType => write!(f, "{}", gettext("Unknown database type.")), + Self::MissingField(s) => write!(f, "{} {}", gettext("Missing field:"), s), + } + } +} + +impl PixivDownloaderDbConfig { + pub fn is_none(&self) -> bool { + matches!(self, Self::None) + } + + pub fn new(value: &JsonValue) -> Result { + let db_type = value["type"] + .as_str() + .try_err(PixivDownloaderDbConfigError::UnkonwnDbType)?; + match db_type { + #[cfg(feature = "db_sqlite")] + "sqlite" => { + let path = + value["path"] + .as_str() + .try_err(PixivDownloaderDbConfigError::MissingField( + "path".to_string(), + ))?; + Ok(Self::Sqlite(PixivDownloaderSqliteConfig { + path: path.to_string(), + })) + } + _ => Err(PixivDownloaderDbConfigError::UnkonwnDbType), + } + } +} impl AsRef for PixivDownloaderDbConfig { fn as_ref(&self) -> &PixivDownloaderDbConfig { self } } + +impl Default for PixivDownloaderDbConfig { + fn default() -> Self { + #[cfg(feature = "db_sqlite")] + return Self::Sqlite(PixivDownloaderSqliteConfig::default()); + #[cfg(not(feature = "db_sqlite"))] + return Self::None; + } +} + +pub fn check_db_config(value: &JsonValue) -> bool { + PixivDownloaderDbConfig::new(value).is_ok() +} diff --git a/src/db/mod.rs b/src/db/mod.rs index 1ff5ae4..6286d35 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -3,12 +3,17 @@ pub mod config; pub mod sqlite; pub mod traits; +pub use config::check_db_config; pub use config::PixivDownloaderDbConfig; #[cfg(feature = "db_sqlite")] -pub use sqlite::SqliteError; +pub use config::PixivDownloaderSqliteConfig; +#[cfg(feature = "db_sqlite")] +pub use sqlite::{PixivDownloaderSqlite, SqliteError}; pub use traits::PixivDownloaderDb; pub type PixivDownloaderDbError = Box; +use crate::{get_helper, gettext}; + #[cfg(feature = "db_sqlite")] impl From for PixivDownloaderDbError { fn from(e: SqliteError) -> Self { @@ -18,3 +23,20 @@ impl From for PixivDownloaderDbError { #[cfg(not(feature = "db_sqlite"))] compile_error!("No database backend is enabled."); + +/// Open the database +pub fn open_database() -> Result, PixivDownloaderDbError> { + let cfg = get_helper().db(); + if cfg.is_none() { + return Err(Box::new(String::from(gettext( + "No database configuration provided.", + )))); + } + #[cfg(feature = "db_sqlite")] + { + if matches!(cfg, PixivDownloaderDbConfig::Sqlite(_)) { + return Ok(Box::new(PixivDownloaderSqlite::new(&cfg)?)); + } + } + Err(Box::new(String::from(gettext("Unknown database type.")))) +} diff --git a/src/db/sqlite/db.rs b/src/db/sqlite/db.rs new file mode 100644 index 0000000..4444d88 --- /dev/null +++ b/src/db/sqlite/db.rs @@ -0,0 +1,40 @@ +use super::super::{ + PixivDownloaderDb, PixivDownloaderDbConfig, PixivDownloaderDbError, PixivDownloaderSqliteConfig, +}; +use super::SqliteError; +use rusqlite::{Connection, OpenFlags}; +use std::sync::Mutex; + +pub struct PixivDownloaderSqlite { + db: Mutex, +} + +impl PixivDownloaderSqlite { + fn _new(cfg: &PixivDownloaderSqliteConfig) -> Result { + let con = Connection::open_with_flags( + &cfg.path, + OpenFlags::SQLITE_OPEN_READ_WRITE + | OpenFlags::SQLITE_OPEN_FULL_MUTEX + | OpenFlags::SQLITE_OPEN_CREATE + | OpenFlags::SQLITE_OPEN_URI, + )?; + Ok(Self { + db: Mutex::new(con), + }) + } +} + +impl PixivDownloaderDb for PixivDownloaderSqlite { + #[allow(unreachable_patterns)] + fn new + ?Sized>( + cfg: &R, + ) -> Result { + match cfg.as_ref() { + PixivDownloaderDbConfig::Sqlite(cfg) => { + let db = Self::_new(cfg)?; + Ok(db) + } + _ => panic!("Config mismatched."), + } + } +} diff --git a/src/db/sqlite/error.rs b/src/db/sqlite/error.rs index 039396f..2cb144d 100644 --- a/src/db/sqlite/error.rs +++ b/src/db/sqlite/error.rs @@ -1,2 +1,4 @@ #[derive(derive_more::Display, derive_more::From)] -pub enum SqliteError {} +pub enum SqliteError { + DbError(rusqlite::Error), +} diff --git a/src/db/sqlite/mod.rs b/src/db/sqlite/mod.rs index 7854358..75b7582 100644 --- a/src/db/sqlite/mod.rs +++ b/src/db/sqlite/mod.rs @@ -1,3 +1,5 @@ +pub mod db; pub mod error; +pub use db::PixivDownloaderSqlite; pub use error::SqliteError; diff --git a/src/db/traits.rs b/src/db/traits.rs index aaebf43..29136c8 100644 --- a/src/db/traits.rs +++ b/src/db/traits.rs @@ -7,5 +7,5 @@ pub trait PixivDownloaderDb { cfg: &R, ) -> Result where - Self: Sized; + Self: Sized + Send + Sync; } diff --git a/src/opthelper.rs b/src/opthelper.rs index e5dd5f1..3802233 100644 --- a/src/opthelper.rs +++ b/src/opthelper.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "db")] +use crate::db::PixivDownloaderDbConfig; use crate::ext::json::FromJson; use crate::ext::replace::ReplaceWith2; use crate::ext::rw_lock::GetRwLock; @@ -73,6 +75,16 @@ impl OptHelper { self._cors_entries.get_ref().clone() } + #[cfg(feature = "db")] + /// Return the config of the database + pub fn db(&self) -> PixivDownloaderDbConfig { + if self.settings.get_ref().have("db") { + PixivDownloaderDbConfig::new(&self.settings.get_ref().get("db").unwrap()).unwrap() + } else { + PixivDownloaderDbConfig::default() + } + } + /// Whether to download multiple posts/artworks at the same time. pub fn download_multiple_posts(&self) -> bool { match self.opt.get_ref().download_multiple_posts { diff --git a/src/server/context.rs b/src/server/context.rs index cd3c390..a3ab330 100644 --- a/src/server/context.rs +++ b/src/server/context.rs @@ -1,14 +1,21 @@ use super::cors::CorsContext; +use crate::db::{open_database, PixivDownloaderDb}; +use crate::gettext; use std::default::Default; pub struct ServerContext { pub cors: CorsContext, + pub db: Box, } impl Default for ServerContext { fn default() -> Self { Self { cors: CorsContext::default(), + db: match open_database() { + Ok(db) => db, + Err(e) => panic!("{} {}", gettext("Failed to open database:"), e), + }, } } } diff --git a/src/settings_list.rs b/src/settings_list.rs index ff00731..f31b20f 100644 --- a/src/settings_list.rs +++ b/src/settings_list.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "db")] +use crate::db::check_db_config; use crate::ext::json::FromJson; use crate::ext::use_or_not::UseOrNot; use crate::gettext; @@ -49,6 +51,8 @@ pub fn get_settings_list() -> Vec { SettingDes::new("force-yuv420p", gettext("Force yuv420p as output pixel format when converting ugoira(GIF) to video."), JsonValueType::Boolean, None).unwrap(), #[cfg(feature = "ugoira")] SettingDes::new("x264-profile", gettext("The x264 profile when converting ugoira(GIF) to video."), JsonValueType::Str, Some(check_x264_profile)).unwrap(), + #[cfg(feature = "db")] + SettingDes::new("db", gettext("Database settings."), JsonValueType::Object, Some(check_db_config)).unwrap(), ] }