Skip to content

Commit

Permalink
Refactor config
Browse files Browse the repository at this point in the history
  • Loading branch information
Nic0w committed Oct 10, 2024
1 parent 076a4ff commit e190519
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 111 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dlnaproxy"
version = "0.3.1"
version = "0.3.2"
authors = ["Nic0w"]
edition = "2021"

Expand Down
119 changes: 119 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use anyhow::{anyhow, Context, Result};
use std::{
fs,
net::{SocketAddr, ToSocketAddrs as _},
time,
};

use reqwest::Url;
use serde::Deserialize;

use crate::CommandLineConf;

#[derive(Deserialize)]
struct RawConfig {
description_url: Option<String>,
period: Option<u64>,
proxy: Option<String>,
verbose: Option<u8>,
iface: Option<String>,
}

pub struct Config {
pub description_url: Url,
pub period: time::Duration,
pub proxy: Option<SocketAddr>,
pub broadcast_iface: Option<String>,
pub verbose: log::LevelFilter,
}

impl TryFrom<CommandLineConf> for Config {
type Error = anyhow::Error;

fn try_from(conf: CommandLineConf) -> std::result::Result<Self, Self::Error> {
get_config(conf)
}
}

fn get_config(args: CommandLineConf) -> Result<Config> {
println!("{:?}", args);

let config_as_file = args
.config
.map(|file| fs::read_to_string(file).context("Could not open/read config file."))
.transpose()?;

let (description_url, period, proxy, broadcast_iface, verbose) =
if let Some(config_file) = config_as_file {
let raw_config: RawConfig =
toml::from_str(&config_file).context("failed to parse config file.")?;

let desc_url = raw_config
.description_url
.ok_or(anyhow!("Missing description URL"))
.and_then(|s| Url::parse(&s).context("Bad description URL."))?;

let period = raw_config.period;

let proxy: Option<SocketAddr> = raw_config
.proxy
.as_deref()
.map(str::parse)
.transpose()
.context("Bad proxy address")?;

(
desc_url,
period,
proxy,
raw_config.iface,
raw_config.verbose,
)
} else {
(
args.description_url
.ok_or(anyhow!("Missing description URL"))?,
args.interval,
args.proxy,
args.iface,
Some(args.verbose),
)
};

let period = period.or(Some(895)).map(time::Duration::from_secs).unwrap();

let verbose = verbose.map_or(log::LevelFilter::Warn, |v| match v {
0 => log::LevelFilter::Warn,
1 => log::LevelFilter::Info,
2 => log::LevelFilter::Debug,
_ => log::LevelFilter::Trace,
});

Ok(Config {
description_url,
proxy,
period,
broadcast_iface,
verbose,
})
}

pub fn sockaddr_from_url(url: &Url) -> SocketAddr {
let host = url.host().expect("Unsupported URL.");

let port: u16 = url
.port_or_known_default()
.expect("Unknown port or scheme.");

let address = format!("{}:{}", host, port);

let addresses: Vec<SocketAddr> = address
.to_socket_addrs()
.expect("Couldn't resolve or build socket address from submitted URL.")
.collect();

addresses
.first()
.expect("No valid socket address.")
.to_owned()
}
116 changes: 6 additions & 110 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,21 @@
mod config;
mod ssdp;
mod tcp_proxy;

use std::{
fs,
net::{SocketAddr, ToSocketAddrs},
path::PathBuf,
time,
};
use std::{net::SocketAddr, path::PathBuf, time};

use serde::Deserialize;
use config::Config;

use reqwest::Url;

use anyhow::{anyhow, Context, Result};
use anyhow::Result;
use clap::{ArgAction, Parser};
use log::{debug, trace};
use ssdp::main_task;

use crate::ssdp::SSDPManager;
use crate::tcp_proxy::TCPProxy;

#[derive(Deserialize)]
struct RawConfig {
description_url: Option<String>,
period: Option<u64>,
proxy: Option<String>,
verbose: Option<u8>,
iface: Option<String>,
}

struct Config {
description_url: Url,
period: time::Duration,
proxy: Option<SocketAddr>,
broadcast_iface: Option<String>,
verbose: log::LevelFilter,
}

/// Broadcast ssdp:alive messages on the local network's multicast SSDP channel on behalf of a remote DLNA server.
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
Expand Down Expand Up @@ -70,14 +49,14 @@ struct CommandLineConf {
async fn main() -> Result<()> {
let args = CommandLineConf::parse();

let config = get_config(args)?;
let config = Config::try_from(args)?;

init_logging(config.verbose);

let mut url = config.description_url;

let _tcp_proxy_thread = if let Some(proxy_addr) = config.proxy {
let server_addr = sockaddr_from_url(&url);
let server_addr = config::sockaddr_from_url(&url);

url.set_ip_host(proxy_addr.ip()).unwrap();
url.set_port(Some(proxy_addr.port())).unwrap();
Expand Down Expand Up @@ -109,89 +88,6 @@ async fn main() -> Result<()> {
Ok(())
}

fn get_config(args: CommandLineConf) -> Result<Config> {
println!("{:?}", args);

let config_as_file = args
.config
.map(|file| fs::read_to_string(file).context("Could not open/read config file."))
.transpose()?;

let (description_url, period, proxy, broadcast_iface, verbose) =
if let Some(config_file) = config_as_file {
let raw_config: RawConfig =
toml::from_str(&config_file).context("failed to parse config file.")?;

let desc_url = raw_config
.description_url
.ok_or(anyhow!("Missing description URL"))
.and_then(|s| Url::parse(&s).context("Bad description URL."))?;

let period = raw_config.period;

let proxy: Option<SocketAddr> = raw_config
.proxy
.as_deref()
.map(str::parse)
.transpose()
.context("Bad proxy address")?;

(
desc_url,
period,
proxy,
raw_config.iface,
raw_config.verbose,
)
} else {
(
args.description_url
.ok_or(anyhow!("Missing description URL"))?,
args.interval,
args.proxy,
args.iface,
Some(args.verbose),
)
};

let period = period.or(Some(895)).map(time::Duration::from_secs).unwrap();

let verbose = verbose.map_or(log::LevelFilter::Warn, |v| match v {
0 => log::LevelFilter::Warn,
1 => log::LevelFilter::Info,
2 => log::LevelFilter::Debug,
_ => log::LevelFilter::Trace,
});

Ok(Config {
description_url,
proxy,
period,
broadcast_iface,
verbose,
})
}

fn sockaddr_from_url(url: &Url) -> SocketAddr {
let host = url.host().expect("Unsupported URL.");

let port: u16 = url
.port_or_known_default()
.expect("Unknown port or scheme.");

let address = format!("{}:{}", host, port);

let addresses: Vec<SocketAddr> = address
.to_socket_addrs()
.expect("Couldn't resolve or build socket address from submitted URL.")
.collect();

addresses
.first()
.expect("No valid socket address.")
.to_owned()
}

fn init_logging(verbosity: log::LevelFilter) -> log::LevelFilter {
fern::Dispatch::new().
format(|out, message, record| {
Expand Down

0 comments on commit e190519

Please sign in to comment.