feat!: distinguish URLs and hosts

BREAKING CHANGE: the configuration for Bitmagnet and Ntfy has changed.
Instead of `host`, they now use `url`.
This commit is contained in:
Marc Plano-Lesay 2025-05-22 21:57:51 +10:00
parent 01fecffc90
commit bb32cfdf97
Signed by: kernald
GPG key ID: 66A41B08CC62A6CF
10 changed files with 59 additions and 50 deletions

View file

@ -50,13 +50,13 @@ download_dir = "/downloads" # Optional
# BitMagnet configuration # BitMagnet configuration
[bitmagnet] [bitmagnet]
enable = true enable = true
host = "http://localhost:3333" url = "http://localhost:3333"
# Ntfy configuration # Ntfy configuration
[ntfy] [ntfy]
enable = true enable = true
topic = "reddit-magnet" topic = "reddit-magnet"
host = "https://ntfy.sh" url = "https://ntfy.sh"
username = "username" # Optional username = "username" # Optional
password = "password" # Optional password = "password" # Optional

View file

@ -20,12 +20,12 @@ impl BitmagnetClient {
return Err(eyre!("Bitmagnet action is disabled")); return Err(eyre!("Bitmagnet action is disabled"));
} }
let url_str = &config.host;
let base_url = Url::parse(url_str).wrap_err_with(|| format!("Invalid URL: {}", url_str))?;
let client = Client::new(); let client = Client::new();
Ok(BitmagnetClient { client, base_url }) Ok(BitmagnetClient {
client,
base_url: config.url.clone(),
})
} }
/// Submit a magnet link to Bitmagnet /// Submit a magnet link to Bitmagnet

View file

@ -1,12 +1,12 @@
use crate::app::Enableable; use crate::app::Enableable;
use crate::config::types::Host;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url;
/// Configuration for the Bitmagnet action /// Configuration for the Bitmagnet action
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BitmagnetConfig { pub struct BitmagnetConfig {
pub enable: bool, pub enable: bool,
pub host: Host, pub url: Url,
} }
impl Enableable for BitmagnetConfig { impl Enableable for BitmagnetConfig {

View file

@ -1,14 +1,9 @@
use crate::actions::bitmagnet::BitmagnetConfig; use crate::actions::bitmagnet::BitmagnetConfig;
use crate::config::Validate; use crate::config::Validate;
use crate::errors::{self};
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use url::Url;
impl Validate for BitmagnetConfig { impl Validate for BitmagnetConfig {
fn validate(&self) -> Result<()> { fn validate(&self) -> Result<()> {
Url::parse(&self.host.to_string())
.map_err(|e| errors::config_error(e, &format!("Invalid URL format: {}", self.host)))?;
Ok(()) Ok(())
} }
} }
@ -16,12 +11,12 @@ impl Validate for BitmagnetConfig {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::config::types::Host; use url::Url;
fn create_valid_config() -> Result<BitmagnetConfig> { fn create_valid_config() -> Result<BitmagnetConfig> {
Ok(BitmagnetConfig { Ok(BitmagnetConfig {
enable: true, enable: true,
host: Host::try_new("http://localhost:8080")?, url: Url::parse("http://localhost:8080")?,
}) })
} }
@ -36,13 +31,8 @@ mod tests {
#[test] #[test]
fn test_invalid_url() -> Result<()> { fn test_invalid_url() -> Result<()> {
let config = BitmagnetConfig { // This test is no longer needed as the Url type handles validation
enable: true, // and will not allow invalid URLs to be created
host: Host::try_new("not a url")?,
};
assert!(config.validate().is_err());
Ok(()) Ok(())
} }
} }

View file

@ -1,6 +1,6 @@
[bitmagnet] [bitmagnet]
enable = true enable = true
host = "http://localhost:8080" url = "http://localhost:8080"
[transmission] [transmission]
enable = false enable = false
@ -13,7 +13,7 @@ download_dir = "/downloads"
[ntfy] [ntfy]
enable = true enable = true
topic = "reddit-magnet" topic = "reddit-magnet"
host = "https://ntfy.sh" url = "https://ntfy.sh"
priority = "default" priority = "default"
[sources.movies] [sources.movies]
@ -25,4 +25,4 @@ tags = ["movies", "hd"]
username = "tv_shows_fan" username = "tv_shows_fan"
title_filter = "S\\d{2}E\\d{2}" title_filter = "S\\d{2}E\\d{2}"
imdb_id = "tt1234567" imdb_id = "tt1234567"
tags = ["tv", "series"] tags = ["tv", "series"]

View file

@ -151,9 +151,9 @@ pub fn get_db_path(args: &Args) -> Result<PathBuf> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::config::types::Host;
use insta::assert_debug_snapshot; use insta::assert_debug_snapshot;
use std::path::Path; use std::path::Path;
use url::Url;
/// Helper function to create a valid configuration for testing /// Helper function to create a valid configuration for testing
fn create_valid_config() -> Result<Config> { fn create_valid_config() -> Result<Config> {
@ -171,7 +171,7 @@ mod tests {
Ok(Config { Ok(Config {
bitmagnet: Some(BitmagnetConfig { bitmagnet: Some(BitmagnetConfig {
enable: true, enable: true,
host: Host::try_new("http://localhost:8080")?, url: Url::parse("http://localhost:8080")?,
}), }),
transmission: None, transmission: None,
ntfy: None, ntfy: None,

View file

@ -1,15 +1,28 @@
--- ---
source: src/config/lib.rs source: src/config/lib.rs
assertion_line: 247
expression: config expression: config
--- ---
Config { Config {
bitmagnet: Some( bitmagnet: Some(
BitmagnetConfig { BitmagnetConfig {
enable: true, enable: true,
host: Host( url: Url {
"http://localhost:8080", scheme: "http",
), cannot_be_a_base: false,
username: "",
password: None,
host: Some(
Domain(
"localhost",
),
),
port: Some(
8080,
),
path: "/",
query: None,
fragment: None,
},
}, },
), ),
transmission: Some( transmission: Some(
@ -35,9 +48,21 @@ Config {
ntfy: Some( ntfy: Some(
NtfyConfig { NtfyConfig {
enable: true, enable: true,
host: Host( url: Url {
"https://ntfy.sh", scheme: "https",
), cannot_be_a_base: false,
username: "",
password: None,
host: Some(
Domain(
"ntfy.sh",
),
),
port: None,
path: "/",
query: None,
fragment: None,
},
username: None, username: None,
password: None, password: None,
topic: Topic( topic: Topic(

View file

@ -1,6 +1,7 @@
use crate::app::Enableable; use crate::app::Enableable;
use crate::config::types::{Host, Password, Topic, Username}; use crate::config::types::{Password, Topic, Username};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url;
/// Configuration for the ntfy notification service /// Configuration for the ntfy notification service
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -9,8 +10,8 @@ pub struct NtfyConfig {
#[serde(default)] #[serde(default)]
pub enable: bool, pub enable: bool,
/// The host URL of the ntfy server /// The URL of the ntfy server
pub host: Host, pub url: Url,
/// The username for authentication (optional) /// The username for authentication (optional)
#[serde(default)] #[serde(default)]

View file

@ -17,7 +17,7 @@ pub struct NtfyNotification {
impl NtfyNotification { impl NtfyNotification {
/// Create a new NtfyNotification instance /// Create a new NtfyNotification instance
pub fn new(config: NtfyConfig) -> Result<Self> { pub fn new(config: NtfyConfig) -> Result<Self> {
let mut builder = dispatcher::builder(config.host.as_str()); let mut builder = dispatcher::builder(config.url.as_str());
// Add authentication if provided // Add authentication if provided
if let (Some(username), Some(password)) = (&config.username, &config.password) { if let (Some(username), Some(password)) = (&config.username, &config.password) {

View file

@ -2,14 +2,9 @@ use crate::config::Validate;
use crate::errors::{self}; use crate::errors::{self};
use crate::notifications::ntfy::NtfyConfig; use crate::notifications::ntfy::NtfyConfig;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use url::Url;
impl Validate for NtfyConfig { impl Validate for NtfyConfig {
fn validate(&self) -> Result<()> { fn validate(&self) -> Result<()> {
// Validate URL format
Url::parse(&self.host.to_string())
.map_err(|e| errors::config_error(e, &format!("Invalid URL format: {}", self.host)))?;
match (self.username.as_ref(), self.password.as_ref()) { match (self.username.as_ref(), self.password.as_ref()) {
(Some(_), None) => { (Some(_), None) => {
return Err(errors::config_error( return Err(errors::config_error(
@ -33,12 +28,13 @@ impl Validate for NtfyConfig {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::config::types::{Host, Password, Topic, Username}; use crate::config::types::{Password, Topic, Username};
use url::Url;
fn create_valid_config() -> Result<NtfyConfig> { fn create_valid_config() -> Result<NtfyConfig> {
Ok(NtfyConfig { Ok(NtfyConfig {
enable: true, enable: true,
host: Host::try_new("https://ntfy.sh")?, url: Url::parse("https://ntfy.sh")?,
username: None, username: None,
password: None, password: None,
topic: Topic::try_new("my-topic")?, topic: Topic::try_new("my-topic")?,
@ -56,11 +52,8 @@ mod tests {
#[test] #[test]
fn test_invalid_url() -> Result<()> { fn test_invalid_url() -> Result<()> {
let mut invalid_config = create_valid_config()?; // This test is no longer needed as the Url type handles validation
invalid_config.host = Host::try_new("not a url")?; // and will not allow invalid URLs to be created
assert!(invalid_config.validate().is_err());
Ok(()) Ok(())
} }