Skip to content

Commit

Permalink
feat: [torrust#114] add new config section api
Browse files Browse the repository at this point in the history
```toml
[api]
default_torrent_page_size = 10
max_torrent_page_size = 30
```

With pagination options for torrents.
  • Loading branch information
josecelano committed May 8, 2023
1 parent 41b6000 commit 4764825
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 58 deletions.
2 changes: 1 addition & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
/bin/
/config-idx-back.local.toml
/config-tracker.local.toml
/config.local.toml
/config.toml
/config.toml.local
/cspell.json
/data_v2.db*
/data.db
Expand Down
2 changes: 1 addition & 1 deletion bin/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Generate the default settings file if it does not exist
if ! [ -f "./config.toml" ]; then
cp ./config.toml.local ./config.toml
cp ./config.local.toml ./config.toml
fi

# Generate storage directory if it does not exist
Expand Down
5 changes: 5 additions & 0 deletions config-idx-back.local.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@ capacity = 128000000
entry_size_limit = 4000000
user_quota_period_seconds = 3600
user_quota_bytes = 64000000

[api]
default_torrent_page_size = 10
max_torrent_page_size = 30

4 changes: 4 additions & 0 deletions config.toml.local → config.local.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,7 @@ capacity = 128000000
entry_size_limit = 4000000
user_quota_period_seconds = 3600
user_quota_bytes = 64000000

[api]
default_torrent_page_size = 10
max_torrent_page_size = 30
51 changes: 30 additions & 21 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,25 @@ pub struct ImageCache {
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TorrustConfig {
pub struct Api {
pub default_torrent_page_size: u8,
pub max_torrent_page_size: u8,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfiguration {
pub website: Website,
pub tracker: Tracker,
pub net: Network,
pub auth: Auth,
pub database: Database,
pub mail: Mail,
pub image_cache: ImageCache,
pub api: Api,
}

impl TorrustConfig {
pub fn default() -> Self {
impl Default for AppConfiguration {
fn default() -> Self {
Self {
website: Website {
name: "Torrust".to_string(),
Expand Down Expand Up @@ -121,9 +128,9 @@ impl TorrustConfig {
email_verification_enabled: false,
from: "example@email.com".to_string(),
reply_to: "noreply@email.com".to_string(),
username: "".to_string(),
password: "".to_string(),
server: "".to_string(),
username: String::new(),
password: String::new(),
server: String::new(),
port: 25,
},
image_cache: ImageCache {
Expand All @@ -133,22 +140,28 @@ impl TorrustConfig {
user_quota_period_seconds: 3600,
user_quota_bytes: 64_000_000,
},
api: Api {
default_torrent_page_size: 10,
max_torrent_page_size: 30,
},
}
}
}

#[derive(Debug)]
pub struct Configuration {
pub settings: RwLock<TorrustConfig>,
pub settings: RwLock<AppConfiguration>,
}

impl Configuration {
pub fn default() -> Configuration {
Configuration {
settings: RwLock::new(TorrustConfig::default()),
impl Default for Configuration {
fn default() -> Self {
Self {
settings: RwLock::new(AppConfiguration::default()),
}
}
}

impl Configuration {
/// Loads the configuration from the configuration file.
pub async fn load_from_file(config_path: &str) -> Result<Configuration, ConfigError> {
let config_builder = Config::builder();
Expand All @@ -168,7 +181,7 @@ impl Configuration {
));
}

let torrust_config: TorrustConfig = match config.try_deserialize() {
let torrust_config: AppConfiguration = match config.try_deserialize() {
Ok(data) => Ok(data),
Err(e) => Err(ConfigError::Message(format!("Errors while processing config: {}.", e))),
}?;
Expand All @@ -191,16 +204,14 @@ impl Configuration {
let config_builder = Config::builder()
.add_source(File::from_str(&config_toml, FileFormat::Toml))
.build()?;
let torrust_config: TorrustConfig = config_builder.try_deserialize()?;
let torrust_config: AppConfiguration = config_builder.try_deserialize()?;
Ok(Configuration {
settings: RwLock::new(torrust_config),
})
}
Err(_) => {
return Err(ConfigError::Message(
"Unable to load configuration from the configuration environment variable.".to_string(),
))
}
Err(_) => Err(ConfigError::Message(
"Unable to load configuration from the configuration environment variable.".to_string(),
)),
}
}

Expand All @@ -215,7 +226,7 @@ impl Configuration {
Ok(())
}

pub async fn update_settings(&self, new_settings: TorrustConfig, config_path: &str) -> Result<(), ()> {
pub async fn update_settings(&self, new_settings: AppConfiguration, config_path: &str) -> Result<(), ()> {
let mut settings = self.settings.write().await;
*settings = new_settings;

Expand All @@ -225,9 +236,7 @@ impl Configuration {

Ok(())
}
}

impl Configuration {
pub async fn get_public(&self) -> ConfigurationPublic {
let settings_lock = self.settings.read().await;

Expand Down
4 changes: 2 additions & 2 deletions src/databases/mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ impl Database for MysqlDatabase {
categories: &Option<Vec<String>>,
sort: &Sorting,
offset: u64,
page_size: u8,
limit: u8,
) -> Result<TorrentsResponse, DatabaseError> {
let title = match search {
None => "%".to_string(),
Expand Down Expand Up @@ -365,7 +365,7 @@ impl Database for MysqlDatabase {
let res: Vec<TorrentListing> = sqlx::query_as::<_, TorrentListing>(&query_string)
.bind(title)
.bind(offset as i64)
.bind(page_size)
.bind(limit)
.fetch_all(&self.pool)
.await
.map_err(|_| DatabaseError::Error)?;
Expand Down
4 changes: 2 additions & 2 deletions src/databases/sqlite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ impl Database for SqliteDatabase {
categories: &Option<Vec<String>>,
sort: &Sorting,
offset: u64,
page_size: u8,
limit: u8,
) -> Result<TorrentsResponse, DatabaseError> {
let title = match search {
None => "%".to_string(),
Expand Down Expand Up @@ -360,7 +360,7 @@ impl Database for SqliteDatabase {
let res: Vec<TorrentListing> = sqlx::query_as::<_, TorrentListing>(&query_string)
.bind(title)
.bind(offset as i64)
.bind(page_size)
.bind(limit)
.fetch_all(&self.pool)
.await
.map_err(|_| DatabaseError::Error)?;
Expand Down
6 changes: 3 additions & 3 deletions src/routes/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use actix_web::{web, HttpRequest, HttpResponse, Responder};

use crate::bootstrap::config::ENV_VAR_DEFAULT_CONFIG_PATH;
use crate::common::WebAppData;
use crate::config::TorrustConfig;
use crate::config::AppConfiguration;
use crate::errors::{ServiceError, ServiceResult};
use crate::models::response::OkResponse;

Expand All @@ -28,7 +28,7 @@ pub async fn get_settings(req: HttpRequest, app_data: WebAppData) -> ServiceResu
return Err(ServiceError::Unauthorized);
}

let settings: tokio::sync::RwLockReadGuard<TorrustConfig> = app_data.cfg.settings.read().await;
let settings: tokio::sync::RwLockReadGuard<AppConfiguration> = app_data.cfg.settings.read().await;

Ok(HttpResponse::Ok().json(OkResponse { data: &*settings }))
}
Expand All @@ -49,7 +49,7 @@ pub async fn get_site_name(app_data: WebAppData) -> ServiceResult<impl Responder

pub async fn update_settings(
req: HttpRequest,
payload: web::Json<TorrustConfig>,
payload: web::Json<AppConfiguration>,
app_data: WebAppData,
) -> ServiceResult<impl Responder> {
// check for user
Expand Down
18 changes: 7 additions & 11 deletions src/routes/torrent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,14 +328,18 @@ pub async fn delete_torrent_handler(req: HttpRequest, app_data: WebAppData) -> S
///
/// Returns a `ServiceError::DatabaseError` if the database query fails.
pub async fn get_torrents_handler(params: Query<TorrentSearch>, app_data: WebAppData) -> ServiceResult<impl Responder> {
let settings = app_data.cfg.settings.read().await;

let sort = params.sort.unwrap_or(Sorting::UploadedDesc);

let page = params.page.unwrap_or(0);

let page_size = params.page_size.unwrap_or(default_page_size());
let page_size = params.page_size.unwrap_or(settings.api.default_torrent_page_size);

let page_size = if page_size > max_torrent_page_size() {
max_torrent_page_size()
// Guard that page size does not exceed the maximum
let max_torrent_page_size = settings.api.max_torrent_page_size;
let page_size = if page_size > max_torrent_page_size {
max_torrent_page_size
} else {
page_size
};
Expand All @@ -352,14 +356,6 @@ pub async fn get_torrents_handler(params: Query<TorrentSearch>, app_data: WebApp
Ok(HttpResponse::Ok().json(OkResponse { data: torrents_response }))
}

fn max_torrent_page_size() -> u8 {
30
}

fn default_page_size() -> u8 {
10
}

fn get_torrent_infohash_from_request(req: &HttpRequest) -> Result<InfoHash, ServiceError> {
match req.match_info().get("info_hash") {
None => Err(ServiceError::BadRequest),
Expand Down
36 changes: 27 additions & 9 deletions tests/common/contexts/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ pub mod responses;

use serde::{Deserialize, Serialize};
use torrust_index_backend::config::{
Auth as DomainAuth, Database as DomainDatabase, ImageCache as DomainImageCache, Mail as DomainMail, Network as DomainNetwork,
TorrustConfig as DomainSettings, Tracker as DomainTracker, Website as DomainWebsite,
Api as DomainApi, AppConfiguration as DomainSettings, Auth as DomainAuth, Database as DomainDatabase,
ImageCache as DomainImageCache, Mail as DomainMail, Network as DomainNetwork, Tracker as DomainTracker,
Website as DomainWebsite,
};

#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
Expand All @@ -16,6 +17,7 @@ pub struct Settings {
pub database: Database,
pub mail: Mail,
pub image_cache: ImageCache,
pub api: Api,
}

#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
Expand Down Expand Up @@ -72,6 +74,12 @@ pub struct ImageCache {
pub user_quota_bytes: usize,
}

#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
pub struct Api {
pub default_torrent_page_size: u8,
pub max_torrent_page_size: u8,
}

impl From<DomainSettings> for Settings {
fn from(settings: DomainSettings) -> Self {
Settings {
Expand All @@ -82,19 +90,20 @@ impl From<DomainSettings> for Settings {
database: Database::from(settings.database),
mail: Mail::from(settings.mail),
image_cache: ImageCache::from(settings.image_cache),
api: Api::from(settings.api),
}
}
}

impl From<DomainWebsite> for Website {
fn from(website: DomainWebsite) -> Self {
Website { name: website.name }
Self { name: website.name }
}
}

impl From<DomainTracker> for Tracker {
fn from(tracker: DomainTracker) -> Self {
Tracker {
Self {
url: tracker.url,
mode: format!("{:?}", tracker.mode),
api_url: tracker.api_url,
Expand All @@ -106,7 +115,7 @@ impl From<DomainTracker> for Tracker {

impl From<DomainNetwork> for Network {
fn from(net: DomainNetwork) -> Self {
Network {
Self {
port: net.port,
base_url: net.base_url,
}
Expand All @@ -115,7 +124,7 @@ impl From<DomainNetwork> for Network {

impl From<DomainAuth> for Auth {
fn from(auth: DomainAuth) -> Self {
Auth {
Self {
email_on_signup: format!("{:?}", auth.email_on_signup),
min_password_length: auth.min_password_length,
max_password_length: auth.max_password_length,
Expand All @@ -126,7 +135,7 @@ impl From<DomainAuth> for Auth {

impl From<DomainDatabase> for Database {
fn from(database: DomainDatabase) -> Self {
Database {
Self {
connect_url: database.connect_url,
torrent_info_update_interval: database.torrent_info_update_interval,
}
Expand All @@ -135,7 +144,7 @@ impl From<DomainDatabase> for Database {

impl From<DomainMail> for Mail {
fn from(mail: DomainMail) -> Self {
Mail {
Self {
email_verification_enabled: mail.email_verification_enabled,
from: mail.from,
reply_to: mail.reply_to,
Expand All @@ -149,7 +158,7 @@ impl From<DomainMail> for Mail {

impl From<DomainImageCache> for ImageCache {
fn from(image_cache: DomainImageCache) -> Self {
ImageCache {
Self {
max_request_timeout_ms: image_cache.max_request_timeout_ms,
capacity: image_cache.capacity,
entry_size_limit: image_cache.entry_size_limit,
Expand All @@ -158,3 +167,12 @@ impl From<DomainImageCache> for ImageCache {
}
}
}

impl From<DomainApi> for Api {
fn from(api: DomainApi) -> Self {
Self {
default_torrent_page_size: api.default_torrent_page_size,
max_torrent_page_size: api.max_torrent_page_size,
}
}
}
Loading

0 comments on commit 4764825

Please sign in to comment.