Skip to content

Commit

Permalink
dev: database-local settings
Browse files Browse the repository at this point in the history
  • Loading branch information
da2ce7 committed Feb 10, 2023
1 parent 70773ca commit 8fb6d05
Show file tree
Hide file tree
Showing 19 changed files with 391 additions and 325 deletions.
7 changes: 4 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"[rust]": {
"editor.formatOnSave": true
},
"rust-analyzer.checkOnSave.command": "clippy",
"rust-analyzer.checkOnSave.allTargets": true,
"rust-analyzer.checkOnSave.extraArgs": ["--","-W","clippy::pedantic"],
"rust-analyzer.checkOnSave": true,
"rust-analyzer.check.allTargets": true,
"rust-analyzer.check.command": "clippy",
"rust-analyzer.check.extraArgs": ["--","-W","clippy::pedantic"],
}
32 changes: 32 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ uuid = { version = "1", features = ["v4"] }
axum = "0.6.1"
axum-server = { version = "0.4.4", features = ["tls-rustls"] }

derive_builder = "0.12"


[dev-dependencies]
mockall = "0.11"
Expand Down
4 changes: 2 additions & 2 deletions src/apis/resources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ impl TryFrom<(&String, &Service)> for ApiServiceSettings {
display_name: String);

Ok(Self {
id: value.0.to_owned(),
id: value.0.clone(),
enabled: value.1.enabled.unwrap(),
display_name: value.1.display_name.to_owned().unwrap(),
display_name: value.1.display_name.clone().unwrap(),
socket: value.1.get_socket()?,
access_tokens: value.1.get_api_tokens()?,
})
Expand Down
18 changes: 7 additions & 11 deletions src/databases/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ use serde::{Deserialize, Serialize};

use super::error::Error;
use super::mysql::Mysql;
use super::settings::Settings;
use super::sqlite::Sqlite;
use super::{Builder, Database};

#[derive(Serialize, Deserialize, Hash, PartialEq, PartialOrd, Ord, Eq, Copy, Debug, Clone)]
#[derive(Default, Serialize, Deserialize, Hash, PartialEq, PartialOrd, Ord, Eq, Copy, Debug, Clone)]
pub enum Driver {
#[default]
Sqlite3,
MySQL,
}
Expand All @@ -17,10 +19,10 @@ impl Driver {
/// # Errors
///
/// This function will return an error if unable to connect to the database.
pub fn build(&self, db_path: &str) -> Result<Box<dyn Database>, Error> {
let database = match self {
Driver::Sqlite3 => Builder::<Sqlite>::build(db_path),
Driver::MySQL => Builder::<Mysql>::build(db_path),
pub fn build(settings: &Settings) -> Result<Box<dyn Database>, Error> {
let database = match settings.driver {
Driver::Sqlite3 => Builder::<Sqlite>::build(settings),
Driver::MySQL => Builder::<Mysql>::build(settings),
}?;

database.create_database_tables().expect("Could not create database tables.");
Expand All @@ -37,9 +39,3 @@ impl std::fmt::Display for Driver {
}
}
}

impl Default for Driver {
fn default() -> Self {
Driver::Sqlite3
}
}
15 changes: 15 additions & 0 deletions src/databases/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::sync::Arc;
use r2d2_mysql::mysql::UrlError;

use super::driver::Driver;
use super::settings::Settings;
use crate::located_error::{Located, LocatedError};

#[derive(thiserror::Error, Debug, Clone)]
Expand Down Expand Up @@ -44,6 +45,20 @@ pub enum Error {
source: LocatedError<'static, r2d2::Error>,
driver: Driver,
},

#[error("Failed to convert to driver settings, expected: {expected}, actual {actual}, settings: {settings:?}, {location}")]
WrongDriver {
location: &'static Location<'static>,
expected: Driver,
actual: Driver,
settings: Settings,
},

#[error("Failed to get required felid from settings: {felid}, {location}")]
MissingFelid {
location: &'static Location<'static>,
felid: String,
},
}

impl From<r2d2_sqlite::rusqlite::Error> for Error {
Expand Down
8 changes: 5 additions & 3 deletions src/databases/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
pub mod driver;
pub mod error;
pub mod mysql;
pub mod settings;
pub mod sqlite;

use std::marker::PhantomData;

use async_trait::async_trait;

use self::error::Error;
use self::settings::Settings;
use crate::protocol::info_hash::InfoHash;
use crate::tracker::auth;

Expand All @@ -27,8 +29,8 @@ where
/// # Errors
///
/// Will return `r2d2::Error` if `db_path` is not able to create a database.
pub(self) fn build(db_path: &str) -> Result<Box<dyn Database>, Error> {
Ok(Box::new(T::new(db_path)?))
pub(self) fn build(settings: &Settings) -> Result<Box<dyn Database>, Error> {
Ok(Box::new(T::new(settings)?))
}
}

Expand All @@ -39,7 +41,7 @@ pub trait Database: Sync + Send {
/// # Errors
///
/// Will return `r2d2::Error` if `db_path` is not able to create a database.
fn new(db_path: &str) -> Result<Self, Error>
fn new(settings: &Settings) -> Result<Self, Error>
where
Self: std::marker::Sized;

Expand Down
28 changes: 5 additions & 23 deletions src/databases/mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,19 @@ use r2d2_mysql::mysql::{params, Opts, OptsBuilder};
use r2d2_mysql::MysqlConnectionManager;

use super::driver::Driver;
use super::settings;
use crate::databases::{Database, Error};
use crate::errors::settings::DatabaseSettingsError;
use crate::protocol::common::AUTH_KEY_LENGTH;
use crate::protocol::info_hash::InfoHash;
use crate::settings::DatabaseSettings;
use crate::tracker::auth;

const DRIVER: Driver = Driver::MySQL;

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct MySqlDatabaseSettings {
pub struct Settings {
pub connection_url: String,
}

impl TryFrom<&DatabaseSettings> for MySqlDatabaseSettings {
type Error = DatabaseSettingsError;

fn try_from(value: &DatabaseSettings) -> Result<Self, Self::Error> {
match value.get_driver()? {
Driver::MySQL => Ok(MySqlDatabaseSettings {
connection_url: value.get_my_sql_connection_url()?,
}),
driver => Err(DatabaseSettingsError::WrongDriver {
field: "driver".to_string(),
expected: Driver::MySQL,
actual: driver,
data: value.to_owned(),
}),
}
}
}

pub struct Mysql {
pool: Pool<MysqlConnectionManager>,
}
Expand All @@ -50,8 +31,9 @@ impl Database for Mysql {
/// # Errors
///
/// Will return `r2d2::Error` if `db_path` is not able to create `MySQL` database.
fn new(db_path: &str) -> Result<Self, Error> {
let opts = Opts::from_url(db_path)?;
fn new(settings: &settings::Settings) -> Result<Self, Error> {
let mysql_settings = settings.get_mysql_settings()?;
let opts = Opts::from_url(mysql_settings.connection_url.as_str())?;
let builder = OptsBuilder::from_opts(opts);
let manager = MysqlConnectionManager::new(builder);
let pool = r2d2::Pool::builder().build(manager).map_err(|e| (e, DRIVER))?;
Expand Down
141 changes: 141 additions & 0 deletions src/databases/settings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use std::panic::Location;
use std::path::Path;

use derive_builder::Builder;
use serde::{Deserialize, Serialize};

use super::driver::Driver::{self, Sqlite3};
use super::driver::{self};
use super::error::Error;
use super::{mysql, sqlite};

#[derive(Builder, Default, Serialize, Deserialize, PartialEq, PartialOrd, Ord, Eq, Debug, Clone, Hash)]
#[builder(default, pattern = "immutable")]
pub struct Settings {
#[builder(default = "driver::Driver::default()")]
pub driver: driver::Driver,
#[builder(default = "self.sql_lite_path_default()")]
sql_lite_3_db_file_path: Option<Box<Path>>,
my_sql_connection_url: Option<String>,
}

impl SettingsBuilder {
// Private helper method that will set the default database path if the database is Sqlite.
#[allow(clippy::unused_self)]
fn sql_lite_path_default(&self) -> Option<Box<Path>> {
if let Sqlite3 = driver::Driver::default() {
Some(Path::new("data.db").into())
} else {
None
}
}
}

impl Settings {
/// Returns the check of this [`Settings`].
///
/// # Errors
///
/// This function will return an error if unable to transform into a definite database setting.
pub fn check(&self) -> Result<(), Error> {
match self.driver {
Driver::Sqlite3 => {
sqlite::Settings::try_from(self)?;
}
Driver::MySQL => {
mysql::Settings::try_from(self)?;
}
}

Ok(())
}

pub fn get_sqlite_settings(&self) -> Result<sqlite::Settings, Error> {
sqlite::Settings::try_from(self)
}

pub fn get_mysql_settings(&self) -> Result<mysql::Settings, Error> {
mysql::Settings::try_from(self)
}
}

#[derive(PartialEq, PartialOrd, Ord, Eq, Debug, Clone, Hash)]
pub struct OldConfig {
pub db_driver: driver::Driver,
pub db_path: String,
}

impl TryFrom<&OldConfig> for Settings {
type Error = Error;

fn try_from(value: &OldConfig) -> Result<Self, Self::Error> {
Ok(match value.db_driver {
Driver::Sqlite3 => SettingsBuilder::default()
.driver(Driver::Sqlite3)
.sql_lite_3_db_file_path(Some(Path::new(&value.db_path).into()))
.build()
.unwrap(),
Driver::MySQL => SettingsBuilder::default()
.driver(Driver::MySQL)
.my_sql_connection_url(Some(value.db_path.clone()))
.build()
.unwrap(),
})
}
}

impl TryFrom<&Settings> for sqlite::Settings {
type Error = Error;

fn try_from(value: &Settings) -> Result<Self, Self::Error> {
Ok(Self {
database_file_path: match value.driver {
Driver::Sqlite3 => match &value.sql_lite_3_db_file_path {
Some(path) => path.clone(),
None => {
return Err(Error::MissingFelid {
location: Location::caller(),
felid: "sql_lite_3_db_file_path".to_string(),
})
}
},
driver => {
return Err(Error::WrongDriver {
location: Location::caller(),
expected: Driver::Sqlite3,
actual: driver,
settings: value.clone(),
})
}
},
})
}
}

impl TryFrom<&Settings> for mysql::Settings {
type Error = Error;

fn try_from(value: &Settings) -> Result<Self, Self::Error> {
Ok(Self {
connection_url: match value.driver {
Driver::MySQL => match &value.my_sql_connection_url {
Some(url) => url.clone(),
None => {
return Err(Error::MissingFelid {
location: Location::caller(),
felid: "my_sql_connection_url".to_string(),
})
}
},
driver => {
return Err(Error::WrongDriver {
location: Location::caller(),
expected: Driver::MySQL,
actual: driver,
settings: value.clone(),
})
}
},
})
}
}
Loading

0 comments on commit 8fb6d05

Please sign in to comment.