mirror of
https://github.com/agersant/polaris
synced 2025-03-02 06:17:10 +00:00
Added DDNS broadcasting
This commit is contained in:
parent
aadbe34fd4
commit
3923229834
7 changed files with 148 additions and 7 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2,6 +2,7 @@
|
||||||
name = "polaris"
|
name = "polaris"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
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)",
|
"id3 0.1.10 (git+https://github.com/jameshurst/rust-id3)",
|
||||||
"iron 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"kernel32-sys 0.2.2 (git+https://github.com/retep998/winapi-rs)",
|
||||||
|
|
|
@ -7,6 +7,7 @@ authors = ["Antoine Gersant <antoine.gersant@lesforges.org>"]
|
||||||
ui = []
|
ui = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
hyper = "0.9.10"
|
||||||
id3 = { git = "https://github.com/jameshurst/rust-id3" }
|
id3 = { git = "https://github.com/jameshurst/rust-id3" }
|
||||||
iron = "0.4.0"
|
iron = "0.4.0"
|
||||||
mount = "0.2.1"
|
mount = "0.2.1"
|
||||||
|
|
|
@ -6,4 +6,9 @@ source = 'M:/Music/Genres/'
|
||||||
|
|
||||||
[[users]]
|
[[users]]
|
||||||
name = 'agersant'
|
name = 'agersant'
|
||||||
password = 'test'
|
password = 'test'
|
||||||
|
|
||||||
|
[ydns]
|
||||||
|
host = 'your_hostname.ydns.eu'
|
||||||
|
username = 'your_username'
|
||||||
|
password = 'your_ydns_password'
|
||||||
|
|
|
@ -202,7 +202,7 @@ pub enum CollectionFile {
|
||||||
pub struct Collection {
|
pub struct Collection {
|
||||||
vfs: Vfs,
|
vfs: Vfs,
|
||||||
users: Vec<User>,
|
users: Vec<User>,
|
||||||
album_art_pattern: Regex,
|
album_art_pattern: Option<Regex>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Collection {
|
impl Collection {
|
||||||
|
@ -210,7 +210,7 @@ impl Collection {
|
||||||
Collection {
|
Collection {
|
||||||
vfs: Vfs::new(),
|
vfs: Vfs::new(),
|
||||||
users: Vec::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> {
|
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;
|
let mut real_dir = real_path;
|
||||||
if real_dir.is_file() {
|
if real_dir.is_file() {
|
||||||
real_dir = try!(real_dir.parent().ok_or(PError::AlbumArtSearchError));
|
real_dir = try!(real_dir.parent().ok_or(PError::AlbumArtSearchError));
|
||||||
|
@ -311,7 +316,7 @@ impl Collection {
|
||||||
None => return false,
|
None => return false,
|
||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
};
|
};
|
||||||
self.album_art_pattern.is_match(file_name)
|
pattern.is_match(file_name)
|
||||||
});
|
});
|
||||||
|
|
||||||
match album_art {
|
match album_art {
|
||||||
|
|
|
@ -6,6 +6,7 @@ use std::path;
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
use collection::User;
|
use collection::User;
|
||||||
|
use ddns::DDNSConfig;
|
||||||
use vfs::MountDir;
|
use vfs::MountDir;
|
||||||
|
|
||||||
const CONFIG_MOUNT_DIRS: &'static str = "mount_dirs";
|
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_NAME: &'static str = "name";
|
||||||
const CONFIG_USER_PASSWORD: &'static str = "password";
|
const CONFIG_USER_PASSWORD: &'static str = "password";
|
||||||
const CONFIG_ALBUM_ART_PATTERN: &'static str = "album_art_pattern";
|
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)]
|
#[derive(Debug)]
|
||||||
pub enum ConfigError {
|
pub enum ConfigError {
|
||||||
|
@ -24,6 +29,7 @@ pub enum ConfigError {
|
||||||
AlbumArtPatternParseError,
|
AlbumArtPatternParseError,
|
||||||
UsersParseError,
|
UsersParseError,
|
||||||
MountDirsParseError,
|
MountDirsParseError,
|
||||||
|
DDNSParseError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for ConfigError {
|
impl From<io::Error> for ConfigError {
|
||||||
|
@ -41,7 +47,8 @@ impl From<regex::Error> for ConfigError {
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub mount_dirs: Vec<MountDir>,
|
pub mount_dirs: Vec<MountDir>,
|
||||||
pub users: Vec<User>,
|
pub users: Vec<User>,
|
||||||
pub album_art_pattern: regex::Regex,
|
pub album_art_pattern: Option<regex::Regex>,
|
||||||
|
pub ddns: Option<DDNSConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
@ -55,12 +62,14 @@ impl Config {
|
||||||
let mut config = Config {
|
let mut config = Config {
|
||||||
mount_dirs: Vec::new(),
|
mount_dirs: Vec::new(),
|
||||||
users: 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_mount_points(&parsed_config));
|
||||||
try!(config.parse_users(&parsed_config));
|
try!(config.parse_users(&parsed_config));
|
||||||
try!(config.parse_album_art_pattern(&parsed_config));
|
try!(config.parse_album_art_pattern(&parsed_config));
|
||||||
|
try!(config.parse_ddns(&parsed_config));
|
||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
@ -74,7 +83,7 @@ impl Config {
|
||||||
&toml::Value::String(ref s) => s,
|
&toml::Value::String(ref s) => s,
|
||||||
_ => return Err(ConfigError::AlbumArtPatternParseError),
|
_ => return Err(ConfigError::AlbumArtPatternParseError),
|
||||||
};
|
};
|
||||||
self.album_art_pattern = try!(regex::Regex::new(pattern));
|
self.album_art_pattern = Some(try!(regex::Regex::new(pattern)));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,4 +161,30 @@ impl Config {
|
||||||
|
|
||||||
Ok(())
|
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
78
src/ddns.rs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
16
src/main.rs
16
src/main.rs
|
@ -1,4 +1,5 @@
|
||||||
extern crate core;
|
extern crate core;
|
||||||
|
extern crate hyper;
|
||||||
extern crate id3;
|
extern crate id3;
|
||||||
extern crate iron;
|
extern crate iron;
|
||||||
extern crate mount;
|
extern crate mount;
|
||||||
|
@ -32,15 +33,18 @@ use staticfile::Static;
|
||||||
mod api;
|
mod api;
|
||||||
mod collection;
|
mod collection;
|
||||||
mod config;
|
mod config;
|
||||||
|
mod ddns;
|
||||||
mod error;
|
mod error;
|
||||||
mod ui;
|
mod ui;
|
||||||
mod vfs;
|
mod vfs;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
|
// Parse config
|
||||||
let config_file = Path::new("Polaris.toml");
|
let config_file = Path::new("Polaris.toml");
|
||||||
let config = config::Config::parse(&config_file).unwrap();
|
let config = config::Config::parse(&config_file).unwrap();
|
||||||
|
|
||||||
|
// Start server
|
||||||
println!("Starting up server");
|
println!("Starting up server");
|
||||||
let mut api_chain;
|
let mut api_chain;
|
||||||
{
|
{
|
||||||
|
@ -64,6 +68,18 @@ fn main() {
|
||||||
mount.mount("/", Static::new(Path::new("web")));
|
mount.mount("/", Static::new(Path::new("web")));
|
||||||
let mut server = Iron::new(mount).http(("0.0.0.0", 5050)).unwrap();
|
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();
|
ui::run();
|
||||||
|
|
||||||
println!("Shutting down server");
|
println!("Shutting down server");
|
||||||
|
|
Loading…
Add table
Reference in a new issue