Added DDNS broadcasting

This commit is contained in:
Antoine Gersant 2016-09-23 00:41:49 -07:00
parent aadbe34fd4
commit 3923229834
7 changed files with 148 additions and 7 deletions

1
Cargo.lock generated
View file

@ -2,6 +2,7 @@
name = "polaris"
version = "0.1.0"
dependencies = [
"hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)",
"id3 0.1.10 (git+https://github.com/jameshurst/rust-id3)",
"iron 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (git+https://github.com/retep998/winapi-rs)",

View file

@ -7,6 +7,7 @@ authors = ["Antoine Gersant <antoine.gersant@lesforges.org>"]
ui = []
[dependencies]
hyper = "0.9.10"
id3 = { git = "https://github.com/jameshurst/rust-id3" }
iron = "0.4.0"
mount = "0.2.1"

View file

@ -6,4 +6,9 @@ source = 'M:/Music/Genres/'
[[users]]
name = 'agersant'
password = 'test'
password = 'test'
[ydns]
host = 'your_hostname.ydns.eu'
username = 'your_username'
password = 'your_ydns_password'

View file

@ -202,7 +202,7 @@ pub enum CollectionFile {
pub struct Collection {
vfs: Vfs,
users: Vec<User>,
album_art_pattern: Regex,
album_art_pattern: Option<Regex>,
}
impl Collection {
@ -210,7 +210,7 @@ impl Collection {
Collection {
vfs: Vfs::new(),
users: Vec::new(),
album_art_pattern: Regex::new("^Folder\\.png$").unwrap(),
album_art_pattern: None,
}
}
@ -294,6 +294,11 @@ impl Collection {
}
fn get_album_art(&self, real_path: &Path) -> Result<Option<PathBuf>, PError> {
let pattern = match self.album_art_pattern {
Some(ref p) => p,
None => return Ok(None),
};
let mut real_dir = real_path;
if real_dir.is_file() {
real_dir = try!(real_dir.parent().ok_or(PError::AlbumArtSearchError));
@ -311,7 +316,7 @@ impl Collection {
None => return false,
Some(r) => r,
};
self.album_art_pattern.is_match(file_name)
pattern.is_match(file_name)
});
match album_art {

View file

@ -6,6 +6,7 @@ use std::path;
use toml;
use collection::User;
use ddns::DDNSConfig;
use vfs::MountDir;
const CONFIG_MOUNT_DIRS: &'static str = "mount_dirs";
@ -15,6 +16,10 @@ const CONFIG_USERS: &'static str = "users";
const CONFIG_USER_NAME: &'static str = "name";
const CONFIG_USER_PASSWORD: &'static str = "password";
const CONFIG_ALBUM_ART_PATTERN: &'static str = "album_art_pattern";
const CONFIG_DDNS: &'static str = "ydns";
const CONFIG_DDNS_HOST: &'static str = "host";
const CONFIG_DDNS_USERNAME: &'static str = "username";
const CONFIG_DDNS_PASSWORD: &'static str = "password";
#[derive(Debug)]
pub enum ConfigError {
@ -24,6 +29,7 @@ pub enum ConfigError {
AlbumArtPatternParseError,
UsersParseError,
MountDirsParseError,
DDNSParseError,
}
impl From<io::Error> for ConfigError {
@ -41,7 +47,8 @@ impl From<regex::Error> for ConfigError {
pub struct Config {
pub mount_dirs: Vec<MountDir>,
pub users: Vec<User>,
pub album_art_pattern: regex::Regex,
pub album_art_pattern: Option<regex::Regex>,
pub ddns: Option<DDNSConfig>,
}
impl Config {
@ -55,12 +62,14 @@ impl Config {
let mut config = Config {
mount_dirs: Vec::new(),
users: Vec::new(),
album_art_pattern: regex::Regex::new("^Folder\\.png$").unwrap(),
album_art_pattern: None,
ddns: None,
};
try!(config.parse_mount_points(&parsed_config));
try!(config.parse_users(&parsed_config));
try!(config.parse_album_art_pattern(&parsed_config));
try!(config.parse_ddns(&parsed_config));
Ok(config)
}
@ -74,7 +83,7 @@ impl Config {
&toml::Value::String(ref s) => s,
_ => return Err(ConfigError::AlbumArtPatternParseError),
};
self.album_art_pattern = try!(regex::Regex::new(pattern));
self.album_art_pattern = Some(try!(regex::Regex::new(pattern)));
Ok(())
}
@ -152,4 +161,30 @@ impl Config {
Ok(())
}
fn parse_ddns(&mut self, source: &toml::Table) -> Result<(), ConfigError> {
let ddns = match source.get(CONFIG_DDNS) {
Some(s) => s,
None => return Ok(()),
};
let ddns = match ddns {
&toml::Value::Table(ref a) => a,
_ => return Err(ConfigError::DDNSParseError),
};
let host = try!(ddns.get(CONFIG_DDNS_HOST).ok_or(ConfigError::DDNSParseError)).as_str();
let username = try!(ddns.get(CONFIG_DDNS_USERNAME).ok_or(ConfigError::DDNSParseError)).as_str();
let password = try!(ddns.get(CONFIG_DDNS_PASSWORD).ok_or(ConfigError::DDNSParseError)).as_str();
let host = try!(host.ok_or(ConfigError::DDNSParseError));
let username = try!(username.ok_or(ConfigError::DDNSParseError));
let password = try!(password.ok_or(ConfigError::DDNSParseError));
self.ddns = Some(DDNSConfig {
host: host.to_owned(),
username: username.to_owned(),
password: password.to_owned(),
});
Ok(())
}
}

78
src/ddns.rs Normal file
View file

@ -0,0 +1,78 @@
use hyper;
use hyper::client::Client;
use hyper::header::{Authorization, Basic };
use std::io;
use std::io::Read;
use std::thread;
use std::time;
#[derive(Debug, Clone)]
pub struct DDNSConfig {
pub host: String,
pub username: String,
pub password: String,
}
#[derive(Debug)]
enum DDNSError {
IoError(io::Error),
HyperError(hyper::Error),
UpdateError(hyper::status::StatusCode),
}
impl From<io::Error> for DDNSError {
fn from(err: io::Error) -> DDNSError {
DDNSError::IoError(err)
}
}
impl From<hyper::Error> for DDNSError {
fn from(err: hyper::Error) -> DDNSError {
DDNSError::HyperError(err)
}
}
const MY_IP_API_URL: &'static str = "http://api.ipify.org";
const DDNS_UPDATE_URL: &'static str = "http://ydns.io/api/v1/update/";
fn get_my_ip() -> Result<String, DDNSError> {
let client = Client::new();
let mut res = try!(client.get(MY_IP_API_URL).send());
let mut buf = String::new();
try!(res.read_to_string(&mut buf));
Ok(buf)
}
fn update_my_ip(ip: &String, config: &DDNSConfig) -> Result<(), DDNSError> {
let client = Client::new();
let url = DDNS_UPDATE_URL;
let host = &config.host;
let full_url = format!("{}?host={}&ip={}", url, host, ip);
let auth_header = Authorization(Basic {
username: config.username.clone(),
password: Some(config.password.to_owned())
});
let res = try!(client.get(full_url.as_str()).header(auth_header).send());
match res.status {
hyper::status::StatusCode::Ok => Ok(()),
s => Err(DDNSError::UpdateError(s)),
}
}
pub fn run(config: DDNSConfig) {
loop {
let my_ip_res = get_my_ip();
if let Ok(my_ip) = my_ip_res {
match update_my_ip(&my_ip, &config) {
Err(e) => println!("Dynamic DNS Error: {:?}", e),
Ok(_) => (),
};
}
else
{
println!("Dynamic DNS Error: could not retrieve our own IP address");
}
thread::sleep(time::Duration::from_secs(60 * 30));
}
}

View file

@ -1,4 +1,5 @@
extern crate core;
extern crate hyper;
extern crate id3;
extern crate iron;
extern crate mount;
@ -32,15 +33,18 @@ use staticfile::Static;
mod api;
mod collection;
mod config;
mod ddns;
mod error;
mod ui;
mod vfs;
fn main() {
// Parse config
let config_file = Path::new("Polaris.toml");
let config = config::Config::parse(&config_file).unwrap();
// Start server
println!("Starting up server");
let mut api_chain;
{
@ -64,6 +68,18 @@ fn main() {
mount.mount("/", Static::new(Path::new("web")));
let mut server = Iron::new(mount).http(("0.0.0.0", 5050)).unwrap();
// Start DDNS updates
match config.ddns {
Some(ref ddns_config) => {
let ddns_config = ddns_config.clone();
std::thread::spawn(|| {
ddns::run(ddns_config);
});
},
None => (),
};
// Run UI
ui::run();
println!("Shutting down server");