diff --git a/.gitignore b/.gitignore index 53eaa21..aea6017 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target **/*.rs.bk +rsddns.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0b6c93a..0b69456 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,7 +4,7 @@ stages: - deploy tests: - image: rust:1.29-stretch + image: rust:1.30-stretch stage: test script: - cargo test @@ -12,7 +12,7 @@ tests: - docker debug: - image: rust:1.29-stretch + image: rust:1.30-stretch stage: build script: - cargo build @@ -24,7 +24,7 @@ debug: - docker release: - image: rust:1.29-stretch + image: rust:1.30-stretch stage: build script: - cargo build --release diff --git a/rsddns-example.yml b/rsddns-example.yml new file mode 100644 index 0000000..1797bde --- /dev/null +++ b/rsddns-example.yml @@ -0,0 +1,16 @@ +--- +server: + host: localhost + port: 8080 + workers: 4 +cloudflare: + key: somekeyblahblahblahimakey + domains: + - domain: something.com + zone_id: blahblahchangemeimakey +ddns: + domains: + - domain: something.com + subdomains: + - ddns +--- \ No newline at end of file diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..9f43d9a --- /dev/null +++ b/src/config.rs @@ -0,0 +1,138 @@ +use yaml_rust::{Yaml, YamlLoader}; +use std::error::Error; +use std::fmt; + +pub struct ServerConfig { + pub host: String, + pub port: i64, + pub workers: i64, +} + +pub struct CloudflareDomainConfig { + pub domain: String, + pub zone_id: String, +} + +pub struct CloudflareConfig { + pub domains: Vec, + pub key: String, +} + +pub struct DDNSDomain { + pub domain: String, + pub subdomains: Vec, +} + +pub struct DDNSConfig { + pub domains: Vec +} + +pub struct Config { + pub server: ServerConfig, + pub cloudflare: CloudflareConfig, + pub ddns: DDNSConfig, +} + +fn get_default_config() -> Config { + Config { + server: ServerConfig { + host: String::from("localhost"), + port: 8080, + workers: 4 + }, + cloudflare: CloudflareConfig { + key: String::from("IAmNotAKey"), + domains: vec![ + CloudflareDomainConfig { + domain: String::from("IAmNotADomain.com"), + zone_id: String::from("IAmNotAZoneID") + } + ] + }, + ddns: DDNSConfig { + domains: vec![ + DDNSDomain { + domain: String::from("IAmNotADomain.com"), + subdomains: vec![ + String::from("ddns") + ] + } + ] + } + } +} + +#[derive(Debug)] +pub struct ConfigError; + +impl Error for ConfigError {} + +impl fmt::Display for ConfigError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Configuration Error") + } +} + +fn create_server_config_from_yaml(yaml: &Yaml) -> Result { + Result::Ok(ServerConfig { + host: String::from(yaml["host"].as_str().unwrap()), + port: yaml["port"].as_i64().unwrap(), + workers: yaml["workers"].as_i64().unwrap(), + }) +} + +fn create_cloudflare_domain_config_from_yaml(yaml: &Yaml) -> Result { + Result::Ok(CloudflareDomainConfig { + domain: String::from(yaml["domain"].as_str().unwrap()), + zone_id: String::from(yaml["zone_id"].as_str().unwrap()), + }) +} + +fn create_cloudflare_config_from_yaml(yaml: &Yaml) -> Result { + Result::Ok(CloudflareConfig { + key: String::from(yaml["key"].as_str().unwrap()), + domains: yaml["domains"].as_vec().unwrap().into_iter().map(|y| create_cloudflare_domain_config_from_yaml(&y).unwrap()).collect(), + }) +} + +fn create_ddns_domain_config_from_yaml(yaml: &Yaml) -> Result { + Result::Ok(DDNSDomain { + domain: String::from(yaml["domain"].as_str().unwrap()), + subdomains: yaml["subdomains"].as_vec().unwrap().into_iter().map(|y| String::from(y.as_str().unwrap())).collect(), + }) +} + +fn create_ddns_config_from_yaml(yaml: &Yaml) -> Result { + Result::Ok(DDNSConfig { + domains: yaml["domains"].as_vec().unwrap().into_iter().map(|y| create_ddns_domain_config_from_yaml(&y).unwrap()).collect() + }) +} + +fn create_config_from_yaml(config_yaml: Vec) -> Result { + let config = &config_yaml[0]; + let server_config = match create_server_config_from_yaml(&config["server"]) { + Ok(v) => v, + Err(e) => return Result::Err(e) + }; + let cloudflare_config = match create_cloudflare_config_from_yaml(&config["cloudflare"]) { + Ok(v) => v, + Err(e) => return Result::Err(e) + }; + let ddns_config = match create_ddns_config_from_yaml(&config["ddns"]) { + Ok(v) => v, + Err(e) => return Result::Err(e) + }; + Result::Ok(Config { + server: server_config, + cloudflare: cloudflare_config, + ddns: ddns_config, + }) +} + +pub fn load_config(path: &str) -> Result { + let yaml_load = YamlLoader::load_from_str(path); + match yaml_load { + Ok(config_yaml) => create_config_from_yaml(config_yaml), + Err(_e) => Result::Err(ConfigError{}) + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 33f8576..fbd01da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,10 +10,12 @@ extern crate env_logger; extern crate futures; extern crate num_cpus; extern crate serde; +extern crate yaml_rust; use clap::{App, Arg}; mod server; +mod config; const VERSION: &'static str = env!("CARGO_PKG_VERSION"); @@ -27,7 +29,7 @@ fn main() { let args = App::new("Dynamic DNS Server") .version(VERSION) .author("Drew Short ") - .about("Recieve DDNS requests and update cloudflare subdomains") + .about("Receive DDNS requests and update associated cloudflare subdomains") .args(&[ Arg::with_name("config") .short("c") @@ -59,8 +61,9 @@ fn main() { ]) .get_matches(); - let config: &str = args.value_of("config").unwrap_or("/etc/rsddns/rsddns.yml"); - let host: &str = args.value_of("host").unwrap_or("localhost"); + let config_path: &str = args.value_of("config").unwrap_or("/etc/rsddns/rsddns.yml"); + let config = config::load_config(config_path).unwrap(); + let host: &str = args.value_of("host").unwrap_or(&config.server.host); let port: i32 = args .value_of("port") .unwrap() @@ -73,7 +76,7 @@ fn main() { info!( "Starting server on {}:{} with workers={} and config {}", - host, port, workers, config + host, port, workers, config_path ); actix_web::server::new(|| server::router::create())