Skip to content

Commit 8fb6d05

Browse files
committed
dev: database-local settings
1 parent 70773ca commit 8fb6d05

File tree

19 files changed

+391
-325
lines changed

19 files changed

+391
-325
lines changed

.vscode/settings.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"[rust]": {
33
"editor.formatOnSave": true
44
},
5-
"rust-analyzer.checkOnSave.command": "clippy",
6-
"rust-analyzer.checkOnSave.allTargets": true,
7-
"rust-analyzer.checkOnSave.extraArgs": ["--","-W","clippy::pedantic"],
5+
"rust-analyzer.checkOnSave": true,
6+
"rust-analyzer.check.allTargets": true,
7+
"rust-analyzer.check.command": "clippy",
8+
"rust-analyzer.check.extraArgs": ["--","-W","clippy::pedantic"],
89
}

Cargo.lock

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ uuid = { version = "1", features = ["v4"] }
6161
axum = "0.6.1"
6262
axum-server = { version = "0.4.4", features = ["tls-rustls"] }
6363

64+
derive_builder = "0.12"
65+
6466

6567
[dev-dependencies]
6668
mockall = "0.11"

src/apis/resources/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ impl TryFrom<(&String, &Service)> for ApiServiceSettings {
5757
display_name: String);
5858

5959
Ok(Self {
60-
id: value.0.to_owned(),
60+
id: value.0.clone(),
6161
enabled: value.1.enabled.unwrap(),
62-
display_name: value.1.display_name.to_owned().unwrap(),
62+
display_name: value.1.display_name.clone().unwrap(),
6363
socket: value.1.get_socket()?,
6464
access_tokens: value.1.get_api_tokens()?,
6565
})

src/databases/driver.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ use serde::{Deserialize, Serialize};
22

33
use super::error::Error;
44
use super::mysql::Mysql;
5+
use super::settings::Settings;
56
use super::sqlite::Sqlite;
67
use super::{Builder, Database};
78

8-
#[derive(Serialize, Deserialize, Hash, PartialEq, PartialOrd, Ord, Eq, Copy, Debug, Clone)]
9+
#[derive(Default, Serialize, Deserialize, Hash, PartialEq, PartialOrd, Ord, Eq, Copy, Debug, Clone)]
910
pub enum Driver {
11+
#[default]
1012
Sqlite3,
1113
MySQL,
1214
}
@@ -17,10 +19,10 @@ impl Driver {
1719
/// # Errors
1820
///
1921
/// This function will return an error if unable to connect to the database.
20-
pub fn build(&self, db_path: &str) -> Result<Box<dyn Database>, Error> {
21-
let database = match self {
22-
Driver::Sqlite3 => Builder::<Sqlite>::build(db_path),
23-
Driver::MySQL => Builder::<Mysql>::build(db_path),
22+
pub fn build(settings: &Settings) -> Result<Box<dyn Database>, Error> {
23+
let database = match settings.driver {
24+
Driver::Sqlite3 => Builder::<Sqlite>::build(settings),
25+
Driver::MySQL => Builder::<Mysql>::build(settings),
2426
}?;
2527

2628
database.create_database_tables().expect("Could not create database tables.");
@@ -37,9 +39,3 @@ impl std::fmt::Display for Driver {
3739
}
3840
}
3941
}
40-
41-
impl Default for Driver {
42-
fn default() -> Self {
43-
Driver::Sqlite3
44-
}
45-
}

src/databases/error.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::sync::Arc;
44
use r2d2_mysql::mysql::UrlError;
55

66
use super::driver::Driver;
7+
use super::settings::Settings;
78
use crate::located_error::{Located, LocatedError};
89

910
#[derive(thiserror::Error, Debug, Clone)]
@@ -44,6 +45,20 @@ pub enum Error {
4445
source: LocatedError<'static, r2d2::Error>,
4546
driver: Driver,
4647
},
48+
49+
#[error("Failed to convert to driver settings, expected: {expected}, actual {actual}, settings: {settings:?}, {location}")]
50+
WrongDriver {
51+
location: &'static Location<'static>,
52+
expected: Driver,
53+
actual: Driver,
54+
settings: Settings,
55+
},
56+
57+
#[error("Failed to get required felid from settings: {felid}, {location}")]
58+
MissingFelid {
59+
location: &'static Location<'static>,
60+
felid: String,
61+
},
4762
}
4863

4964
impl From<r2d2_sqlite::rusqlite::Error> for Error {

src/databases/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
pub mod driver;
22
pub mod error;
33
pub mod mysql;
4+
pub mod settings;
45
pub mod sqlite;
56

67
use std::marker::PhantomData;
78

89
use async_trait::async_trait;
910

1011
use self::error::Error;
12+
use self::settings::Settings;
1113
use crate::protocol::info_hash::InfoHash;
1214
use crate::tracker::auth;
1315

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

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

src/databases/mysql.rs

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,38 +9,19 @@ use r2d2_mysql::mysql::{params, Opts, OptsBuilder};
99
use r2d2_mysql::MysqlConnectionManager;
1010

1111
use super::driver::Driver;
12+
use super::settings;
1213
use crate::databases::{Database, Error};
13-
use crate::errors::settings::DatabaseSettingsError;
1414
use crate::protocol::common::AUTH_KEY_LENGTH;
1515
use crate::protocol::info_hash::InfoHash;
16-
use crate::settings::DatabaseSettings;
1716
use crate::tracker::auth;
1817

1918
const DRIVER: Driver = Driver::MySQL;
2019

2120
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
22-
pub struct MySqlDatabaseSettings {
21+
pub struct Settings {
2322
pub connection_url: String,
2423
}
2524

26-
impl TryFrom<&DatabaseSettings> for MySqlDatabaseSettings {
27-
type Error = DatabaseSettingsError;
28-
29-
fn try_from(value: &DatabaseSettings) -> Result<Self, Self::Error> {
30-
match value.get_driver()? {
31-
Driver::MySQL => Ok(MySqlDatabaseSettings {
32-
connection_url: value.get_my_sql_connection_url()?,
33-
}),
34-
driver => Err(DatabaseSettingsError::WrongDriver {
35-
field: "driver".to_string(),
36-
expected: Driver::MySQL,
37-
actual: driver,
38-
data: value.to_owned(),
39-
}),
40-
}
41-
}
42-
}
43-
4425
pub struct Mysql {
4526
pool: Pool<MysqlConnectionManager>,
4627
}
@@ -50,8 +31,9 @@ impl Database for Mysql {
5031
/// # Errors
5132
///
5233
/// Will return `r2d2::Error` if `db_path` is not able to create `MySQL` database.
53-
fn new(db_path: &str) -> Result<Self, Error> {
54-
let opts = Opts::from_url(db_path)?;
34+
fn new(settings: &settings::Settings) -> Result<Self, Error> {
35+
let mysql_settings = settings.get_mysql_settings()?;
36+
let opts = Opts::from_url(mysql_settings.connection_url.as_str())?;
5537
let builder = OptsBuilder::from_opts(opts);
5638
let manager = MysqlConnectionManager::new(builder);
5739
let pool = r2d2::Pool::builder().build(manager).map_err(|e| (e, DRIVER))?;

src/databases/settings.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
use std::panic::Location;
2+
use std::path::Path;
3+
4+
use derive_builder::Builder;
5+
use serde::{Deserialize, Serialize};
6+
7+
use super::driver::Driver::{self, Sqlite3};
8+
use super::driver::{self};
9+
use super::error::Error;
10+
use super::{mysql, sqlite};
11+
12+
#[derive(Builder, Default, Serialize, Deserialize, PartialEq, PartialOrd, Ord, Eq, Debug, Clone, Hash)]
13+
#[builder(default, pattern = "immutable")]
14+
pub struct Settings {
15+
#[builder(default = "driver::Driver::default()")]
16+
pub driver: driver::Driver,
17+
#[builder(default = "self.sql_lite_path_default()")]
18+
sql_lite_3_db_file_path: Option<Box<Path>>,
19+
my_sql_connection_url: Option<String>,
20+
}
21+
22+
impl SettingsBuilder {
23+
// Private helper method that will set the default database path if the database is Sqlite.
24+
#[allow(clippy::unused_self)]
25+
fn sql_lite_path_default(&self) -> Option<Box<Path>> {
26+
if let Sqlite3 = driver::Driver::default() {
27+
Some(Path::new("data.db").into())
28+
} else {
29+
None
30+
}
31+
}
32+
}
33+
34+
impl Settings {
35+
/// Returns the check of this [`Settings`].
36+
///
37+
/// # Errors
38+
///
39+
/// This function will return an error if unable to transform into a definite database setting.
40+
pub fn check(&self) -> Result<(), Error> {
41+
match self.driver {
42+
Driver::Sqlite3 => {
43+
sqlite::Settings::try_from(self)?;
44+
}
45+
Driver::MySQL => {
46+
mysql::Settings::try_from(self)?;
47+
}
48+
}
49+
50+
Ok(())
51+
}
52+
53+
pub fn get_sqlite_settings(&self) -> Result<sqlite::Settings, Error> {
54+
sqlite::Settings::try_from(self)
55+
}
56+
57+
pub fn get_mysql_settings(&self) -> Result<mysql::Settings, Error> {
58+
mysql::Settings::try_from(self)
59+
}
60+
}
61+
62+
#[derive(PartialEq, PartialOrd, Ord, Eq, Debug, Clone, Hash)]
63+
pub struct OldConfig {
64+
pub db_driver: driver::Driver,
65+
pub db_path: String,
66+
}
67+
68+
impl TryFrom<&OldConfig> for Settings {
69+
type Error = Error;
70+
71+
fn try_from(value: &OldConfig) -> Result<Self, Self::Error> {
72+
Ok(match value.db_driver {
73+
Driver::Sqlite3 => SettingsBuilder::default()
74+
.driver(Driver::Sqlite3)
75+
.sql_lite_3_db_file_path(Some(Path::new(&value.db_path).into()))
76+
.build()
77+
.unwrap(),
78+
Driver::MySQL => SettingsBuilder::default()
79+
.driver(Driver::MySQL)
80+
.my_sql_connection_url(Some(value.db_path.clone()))
81+
.build()
82+
.unwrap(),
83+
})
84+
}
85+
}
86+
87+
impl TryFrom<&Settings> for sqlite::Settings {
88+
type Error = Error;
89+
90+
fn try_from(value: &Settings) -> Result<Self, Self::Error> {
91+
Ok(Self {
92+
database_file_path: match value.driver {
93+
Driver::Sqlite3 => match &value.sql_lite_3_db_file_path {
94+
Some(path) => path.clone(),
95+
None => {
96+
return Err(Error::MissingFelid {
97+
location: Location::caller(),
98+
felid: "sql_lite_3_db_file_path".to_string(),
99+
})
100+
}
101+
},
102+
driver => {
103+
return Err(Error::WrongDriver {
104+
location: Location::caller(),
105+
expected: Driver::Sqlite3,
106+
actual: driver,
107+
settings: value.clone(),
108+
})
109+
}
110+
},
111+
})
112+
}
113+
}
114+
115+
impl TryFrom<&Settings> for mysql::Settings {
116+
type Error = Error;
117+
118+
fn try_from(value: &Settings) -> Result<Self, Self::Error> {
119+
Ok(Self {
120+
connection_url: match value.driver {
121+
Driver::MySQL => match &value.my_sql_connection_url {
122+
Some(url) => url.clone(),
123+
None => {
124+
return Err(Error::MissingFelid {
125+
location: Location::caller(),
126+
felid: "my_sql_connection_url".to_string(),
127+
})
128+
}
129+
},
130+
driver => {
131+
return Err(Error::WrongDriver {
132+
location: Location::caller(),
133+
expected: Driver::MySQL,
134+
actual: driver,
135+
settings: value.clone(),
136+
})
137+
}
138+
},
139+
})
140+
}
141+
}

0 commit comments

Comments
 (0)