From 46c01c6c38a98de85a4df5d9d179d7504843dd97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 25 Feb 2019 21:41:06 +0100 Subject: [PATCH] added hot-reload of the config file --- Cargo.lock | 107 ++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/brainz.rs | 52 +++++++++++----- src/config_file.rs | 150 +++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 128 ++++++++++++++++++-------------------- 5 files changed, 353 insertions(+), 85 deletions(-) create mode 100644 src/config_file.rs diff --git a/Cargo.lock b/Cargo.lock index a26ac99..7cc7738 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -473,6 +473,29 @@ name = "indexmap" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "inotify" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "inotify-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "iovec" version = "0.1.2" @@ -598,6 +621,16 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mio-uds" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miow" version = "0.2.1" @@ -925,6 +958,7 @@ version = "0.1.0" dependencies = [ "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mpris 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1257,12 +1291,28 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-sync 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-codec" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1283,6 +1333,16 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio-fs" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio-io" version = "0.1.11" @@ -1310,6 +1370,14 @@ dependencies = [ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio-sync" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio-tcp" version = "0.1.3" @@ -1351,6 +1419,37 @@ dependencies = [ "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio-udp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-uds" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "try-lock" version = "0.2.2" @@ -1562,6 +1661,8 @@ dependencies = [ "checksum ident_case 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9826188e666f2ed92071d2dadef6edc430b11b158b5b2b3f4babbcc891eaaa" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" +"checksum inotify 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24e40d6fd5d64e2082e0c796495c8ef5ad667a96d03e5aaa0becfd9d47bcbfb8" +"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" @@ -1578,6 +1679,7 @@ dependencies = [ "checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425" "checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed" "checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" +"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum mpris 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8a00ae9537d355ab18532a7cf325c7177fb0dcb82851c82228fcaf9815f698d" "checksum native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8e08de0070bbf4c31f452ea2a70db092f36f6f2e4d897adf5674477d488fb2" @@ -1651,13 +1753,18 @@ dependencies = [ "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "e0500b88064f08bebddd0c0bed39e19f5c567a5f30975bee52b0c0d3e2eeb38c" +"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" "checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" "checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" +"checksum tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9cbbc8a3698b7ab652340f46633364f9eaa928ddaaee79d8b8f356dd79a09d" "checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f" "checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f" +"checksum tokio-sync 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c73850a5ad497d73ccfcfc0ffb494a4502d93f35cb475cfeef4fcf2916d26040" "checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" "checksum tokio-threadpool 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c3fd86cb15547d02daa2b21aadaf4e37dee3368df38a526178a5afa3c034d2fb" "checksum tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2910970404ba6fa78c5539126a9ae2045d62e3713041e447f695f41405a120c6" +"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" +"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" diff --git a/Cargo.toml b/Cargo.toml index a881bd9..350de86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,4 @@ failure = "0.1.5" log = "0.4" env_logger = "0.6" regex = "1.1.0" +inotify = "0.7.0" diff --git a/src/brainz.rs b/src/brainz.rs index 1edef54..a5d1daa 100644 --- a/src/brainz.rs +++ b/src/brainz.rs @@ -1,12 +1,12 @@ -use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; use failure::Error; +use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; +use regex::Regex; use std::io::Read; use std::time::Duration; -use regex::Regex; #[derive(Serialize, Deserialize, Debug)] struct MBArtistQueryResult { - created : String, + created: String, count: i32, offset: i32, artists: Option>, @@ -23,22 +23,31 @@ struct MBArtist { id: String, score: i32, name: String, - #[serde(rename="sort-name")] + #[serde(rename = "sort-name")] sort_name: String, - tags: Option> + tags: Option>, } const VERSION: &'static str = env!("CARGO_PKG_VERSION"); -pub fn check_artist(config : &crate::Config, artist : &str) -> Result { +pub fn check_artist(config: &crate::Config, artist: &str) -> Result { let query = utf8_percent_encode(&format!("\"{}\"", artist), DEFAULT_ENCODE_SET).to_string(); - let url = format!("https://musicbrainz.org/ws/2/artist?query={}&fmt=json&inc=tags", query); + let url = format!( + "https://musicbrainz.org/ws/2/artist?query={}&fmt=json&inc=tags", + query + ); - info!("Querying MusicBrainz for artist \"{}\", query URL: {}", artist, url); + info!( + "Querying MusicBrainz for artist \"{}\", query URL: {}", + artist, url + ); let mut resp = String::new(); - let ua = format!("Bad Song Skipper / {v} ( https://git.ondrovo.com/MightyPork/rapblock )", v=VERSION); + let ua = format!( + "Bad Song Skipper / {v} ( https://git.ondrovo.com/MightyPork/rapblock )", + v = VERSION + ); debug!("Using UA: {}", ua); @@ -53,7 +62,7 @@ pub fn check_artist(config : &crate::Config, artist : &str) -> Result Result= {}", result.count, config.artist_min_score); + info!( + "Got {} results, checking where score >= {}", + result.count, config.artist_min_score + ); let artists = result.artists.as_ref().unwrap(); let mut confidence = false; @@ -75,7 +87,7 @@ pub fn check_artist(config : &crate::Config, artist : &str) -> Result = tags.iter().map(|t| &t.name).collect(); - info!("Artist #{} - \"{}\" has tags: {:?}", an+1, a.name, as_vec); + info!("Artist #{} - \"{}\" has tags: {:?}", an + 1, a.name, as_vec); 'tags: for tag in as_vec { if config.whitelist.tag.contains(tag) { info!("+ Whitelisted tag \"{}\"", tag); @@ -87,17 +99,19 @@ pub fn check_artist(config : &crate::Config, artist : &str) -> Result re.is_match(tag), - Err(_) => tag.contains(t) + Err(_) => tag.contains(t), }; if matches { - info!("- Blacklisted tag \"{}\" - due to substring \"{}\"", tag, t); + info!( + "- Blacklisted tag \"{}\" - due to substring \"{}\"", + tag, t + ); blacklisted = true; break 'blacklist; } @@ -113,7 +127,11 @@ pub fn check_artist(config : &crate::Config, artist : &str) -> Result { + is_dummy : bool, + config: T, + path: PathBuf, + inotify: Option, + inotify_buffer: [u8; 1024], +} + +impl ConfigFile +where + T: Default + std::fmt::Debug + DeserializeOwned, +{ + pub fn borrow(&self) -> &T { + &self.config + } + + /// Create a new reloadable config file + /// If loading fails, an error is printed and default values are be used + pub fn new>(path: P) -> Result { + let loaded = Self::load(&path); + if let Err(e) = &loaded { + eprintln!("Config file failed to load/parse: {}", e); + } + + Ok(Self { + is_dummy: false, + config: loaded.unwrap_or(T::default()), + path: path.as_ref().to_owned(), + inotify: Self::setup_inotify(&path), + inotify_buffer: [0; 1024], + }) + } + + /// New without a backing file + #[allow(dead_code)] + pub fn new_from_defaults() -> Self { + Self { + is_dummy: true, + config: T::default(), + path: "".into(), + inotify: None, + inotify_buffer: [0; 1024] + } + } + + /// Try to install inotify + fn setup_inotify>(path: P) -> Option { + let inotify = Inotify::init(); + if let Err(e) = inotify { + eprintln!("Failed to set up inotify for config file reload!\n{}", e); + return None; + } + + let mut inotify = inotify.unwrap(); + let rv = inotify.add_watch(&path, WatchMask::MODIFY | WatchMask::CLOSE); + + match rv { + Err(e) => { + eprintln!("Failed to add inotify watch for config!\n{}", e); + None + } + Ok(_) => Some(inotify), + } + } + + /// Update the config file if needed (there are inotify events) + /// - if inotify failed to init, or an error occurs trying to get events from it, + /// the 'def' value is used (true = reload if unsure) + pub fn update_if_needed(&mut self, def: bool) -> Result { + if self.is_dummy { + debug!("Config is dummy, no path to reload."); + return Ok(false); + } + + let needed = match self.inotify.as_mut() { + Some(ino) => { + let rv = ino.read_events(&mut self.inotify_buffer); + match rv { + Ok(evs) => { + let mut changed = false; + let mut need_reinstall = false; + for ev in evs { + if ev.mask.contains(EventMask::IGNORED) { + debug!("Inotify watcher got removed by OS??"); + changed = true; + need_reinstall = true; + } + if ev.mask.contains(EventMask::MODIFY) { + changed = true; + } + } + if changed { + info!("Config file changes detected, reloading"); + } + if need_reinstall { + debug!("Reinstalling inotify"); + self.inotify = Self::setup_inotify(&self.path); + } + changed + } + _ => { + error!("Failed to get inotify events."); + def + } + } + } + None => def, + }; + + if needed { + self.update()?; + } else { + debug!("Config update not needed."); + } + + Ok(needed) + } + + /// load and parse the config file + fn load>(path: P) -> Result { + info!("Loading config file @ {}", path.as_ref().to_str().unwrap_or("???")); + let file = File::open(&path)?; + let reader = BufReader::new(file); + let val : T = serde_json::from_reader(reader)?; + + debug!("Loaded config:\n{:#?}", val); + + Ok(val) + } + + /// Reload unconditionally + pub fn update(&mut self) -> Result<(), Error> { + if self.is_dummy { + debug!("Config is dummy, no path to reload."); + return Ok(()); + } + + self.config = Self::load(&self.path)?; + Ok(()) + } +} diff --git a/src/main.rs b/src/main.rs index 552b987..6cf9a48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,19 @@ #[macro_use] extern crate serde_derive; //#[macro_use] extern crate lazy_static; #[macro_use] extern crate log; -#[macro_use] extern crate failure; +//#[macro_use] extern crate failure; -mod brainz; - -use mpris::{PlayerFinder,Event}; -use failure::Error; -use std::time::Duration; -use std::collections::HashSet; use std::env; -use std::path::Path; -use std::fs::File; -use std::io::Read; +use crate::config_file::ConfigFile; use std::collections::HashMap; +use mpris::PlayerFinder; +use std::time::Duration; +use mpris::Event; +use std::collections::HashSet; +use failure::Error; + +mod brainz; +mod config_file; #[derive(Serialize, Deserialize, Debug)] #[serde(default)] @@ -35,7 +35,7 @@ impl Default for BlacklistConf { "hip-hop".to_owned(), "hip hop".to_owned(), "hiphop".to_owned(), - "rap".to_owned() + "rap".to_owned(), ], } } @@ -54,7 +54,7 @@ impl Default for WhiteList { fn default() -> Self { Self { tag: vec![], - artist: vec![] + artist: vec![], } } } @@ -71,9 +71,9 @@ pub struct Config { /// Whitelist (overrides blacklist) pub whitelist: WhiteList, /// Min MusicBrainz search score for artist look-up - pub artist_min_score : i32, + pub artist_min_score: i32, /// Max nr of artists to check per track - pub max_artists_per_track : u64, + pub max_artists_per_track: u64, /// Interval in which the daemon probes DBUS for open MPRIS channels pub player_find_interval_ms: u64, /// Delay after a skip or allow, e.g. to prevent infinite skip chain when someone starts a rap playlist @@ -96,71 +96,55 @@ impl Default for Config { player_find_interval_ms: 2500, cooldown_ms: 1000, api_timeout_ms: 2000, - allow_by_default: true + allow_by_default: true, } } } const CONFIG_FILE: &'static str = "rapblock.json"; -fn load_config() -> Result { - let config_file_path = env::current_dir()?.join(CONFIG_FILE); - let buf = read_file(config_file_path)?; - - let config : Config = serde_json::from_str(&buf)?; - - // Validations - match config.logging.as_ref() { - "info" | "debug" | "trace" | "warning" | "error" => (), - _ => bail!("Invalid value for \"logging\""), - }; - - Ok(config) -} - -pub fn read_file>(path: P) -> Result { - let path = path.as_ref(); - let mut file = File::open(path)?; - - let mut buf = String::new(); - file.read_to_string(&mut buf)?; - Ok(buf) -} - fn main() -> Result<(), Error> { - let config = match load_config() { - Ok(c) => c, - Err(e) => { - eprintln!("Could not load config from \"{}\": {}", CONFIG_FILE, e); - Config::default() - } - }; + // let config = match load_config() { + // Ok(c) => c, + // Err(e) => { + // eprintln!("Could not load config from \"{}\": {}", CONFIG_FILE, e); + // Config::default() + // } + // }; - let env = env_logger::Env::default().default_filter_or(&config.logging); - env_logger::Builder::from_env(env).init(); + let config_file_path = env::current_dir()?.join(CONFIG_FILE); + let mut cfg: ConfigFile = config_file::ConfigFile::new(config_file_path)?; - debug!("Loaded config:\n{}", serde_json::to_string_pretty(&config)?); + let env = env_logger::Env::default().default_filter_or(&cfg.borrow().logging); + env_logger::Builder::from_env(env).init(); let mut artist_cache = HashMap::::new(); info!("Waiting for players..."); - 'main_loop: - loop { + 'main_loop: loop { // XXX this picks the first player, which isn't always ideal - see mpris/src/find.rs let player = PlayerFinder::new() .expect("Could not connect to D-Bus") .find_active(); + let _ = cfg.update_if_needed(false); + if let Ok(player) = player { + let config = cfg.borrow(); let player_name = player.bus_name().to_string(); - if !config.allowed_players.is_empty() && !config.allowed_players.contains(&player_name) { + if !config.allowed_players.is_empty() && !config.allowed_players.contains(&player_name) + { debug!("Ignoring player {}", player_name); ::std::thread::sleep(Duration::from_millis(config.player_find_interval_ms)); continue 'main_loop; } - info!("Connected to player: {}{}", player_name, player.unique_name()); + info!( + "Connected to player: {}{}", + player_name, + player.unique_name() + ); let events = player.events(); if events.is_err() { @@ -170,8 +154,10 @@ fn main() -> Result<(), Error> { continue 'main_loop; } - 'event_loop: - for event in events.unwrap() { + 'event_loop: for event in events.unwrap() { + let _ = cfg.update_if_needed(false); + let config = cfg.borrow(); + match event { Ok(event) => { debug!("MPRIS event: {:#?}", event); @@ -179,7 +165,7 @@ fn main() -> Result<(), Error> { Event::PlayerShutDown => { info!("Player shut down"); break 'event_loop; - }, + } Event::TrackChanged(metadata) => { let title = metadata.title().unwrap_or(""); info!("--- new track : {} ---", title); @@ -194,17 +180,24 @@ fn main() -> Result<(), Error> { let mut artists = HashSet::new(); if let Some(aa) = metadata.artists() { - for a in aa { artists.insert(a); } + for a in aa { + artists.insert(a); + } } if let Some(aa) = metadata.album_artists() { - for a in aa { artists.insert(a); } + for a in aa { + artists.insert(a); + } } let mut skip = false; let mut confidence = false; - 'artists_loop: - for (an, a) in artists.iter().take(config.max_artists_per_track as usize).enumerate() { - info!("Checking artist #{}: {}", an+1, a); + 'artists_loop: for (an, a) in artists + .iter() + .take(config.max_artists_per_track as usize) + .enumerate() + { + info!("Checking artist #{}: {}", an + 1, a); if let Some(resolution) = artist_cache.get(a.as_str()) { confidence = true; if !resolution { @@ -243,11 +236,12 @@ fn main() -> Result<(), Error> { skip = true; break 'artists_loop; } - }, + } Err(e) => { warn!("Something went wrong: {}", e); // probably no tags, or not found - use the default action - artist_cache.insert(a.to_string(), config.allow_by_default); + artist_cache + .insert(a.to_string(), config.allow_by_default); } } } @@ -262,12 +256,12 @@ fn main() -> Result<(), Error> { } ::std::thread::sleep(Duration::from_millis(config.cooldown_ms)); - }, + } _ => { debug!("Event not handled."); } } - }, + } Err(err) => { error!("D-Bus error: {}. Aborting.", err); break 'event_loop; @@ -279,8 +273,6 @@ fn main() -> Result<(), Error> { debug!("No player found, waiting..."); } - ::std::thread::sleep(Duration::from_millis(config.player_find_interval_ms)); + ::std::thread::sleep(Duration::from_millis(cfg.borrow().player_find_interval_ms)); } } - -