From e552035142b36fa1da78faed5cf83ff89f4506c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 01:32:50 +0200 Subject: initial reading of config file --- mumd/Cargo.toml | 1 - mumd/src/state.rs | 13 +++++++++++- mumlib/Cargo.toml | 1 + mumlib/src/config.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ mumlib/src/lib.rs | 1 + 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 mumlib/src/config.rs diff --git a/mumd/Cargo.toml b/mumd/Cargo.toml index 9101b43..ffb463a 100644 --- a/mumd/Cargo.toml +++ b/mumd/Cargo.toml @@ -27,6 +27,5 @@ tokio = { version = "0.2", features = ["full"] } tokio-tls = "0.3" tokio-util = { version = "0.3", features = ["codec", "udp"] } -#clap = "2.33" #compressor = "0.3" #daemonize = "0.4" diff --git a/mumd/src/state.rs b/mumd/src/state.rs index 55fd8ae..e2892fc 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -6,6 +6,7 @@ use mumble_protocol::control::msgs; use mumble_protocol::control::ControlPacket; use mumble_protocol::voice::Serverbound; use mumlib::command::{Command, CommandResponse}; +use mumlib::config::Config; use mumlib::error::{ChannelIdentifierError, Error}; use serde::{Deserialize, Serialize}; use std::collections::hash_map::Entry; @@ -21,6 +22,7 @@ pub enum StatePhase { } pub struct State { + config: Config, server: Option, audio: Audio, @@ -28,6 +30,7 @@ pub struct State { connection_info_sender: watch::Sender>, phase_watcher: (watch::Sender, watch::Receiver), + } impl State { @@ -35,9 +38,17 @@ impl State { packet_sender: mpsc::UnboundedSender>, connection_info_sender: watch::Sender>, ) -> Self { + let config = mumlib::config::read_default_cfg(); + let audio = Audio::new(); + if let Some(ref audio_config) = config.audio { + if let Some(input_volume) = audio_config.input_volume { + audio.set_input_volume(input_volume); + } + } Self { + config, server: None, - audio: Audio::new(), + audio, packet_sender, connection_info_sender, phase_watcher: watch::channel(StatePhase::Disconnected), diff --git a/mumlib/Cargo.toml b/mumlib/Cargo.toml index a2627d4..471a1fe 100644 --- a/mumlib/Cargo.toml +++ b/mumlib/Cargo.toml @@ -13,3 +13,4 @@ fern = "0.5" log = "0.4" mumble-protocol = "0.3" serde = { version = "1.0", features = ["derive"] } +toml = "0.5" diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs new file mode 100644 index 0000000..0012cc6 --- /dev/null +++ b/mumlib/src/config.rs @@ -0,0 +1,60 @@ +use serde::Deserialize; +use std::fs; +use toml::value::Array; + +#[derive(Debug, Deserialize)] +struct TOMLConfig { + audio: Option, + servers: Option, +} + +#[derive(Debug, Deserialize)] +pub struct Config { + pub audio: Option, + pub servers: Option>, +} + +#[derive(Debug, Deserialize)] +pub struct AudioConfig { + pub input_volume: Option, +} + +#[derive(Debug, Deserialize)] +pub struct ServerConfig { + pub name: String, + pub host: String, + pub port: u16, + pub username: Option, + pub password: Option, +} + +fn get_cfg_path() -> String { + "~/.mumdrc".to_string() //TODO XDG_CONFIG and whatever +} + +impl From for Config { + fn from(config: TOMLConfig) -> Self { + Config { + audio: config.audio, + servers: if let Some(servers) = config.servers { + Some(servers + .into_iter() + .map(|s| s.try_into::().expect("invalid server config format")) + .collect()) + } else { + None + }, + } + } +} + +pub fn read_default_cfg() -> Config { + //TODO ignore when config file doesn't exist + Config::from( + toml::from_str::( + &fs::read_to_string( + get_cfg_path()) + .expect("config file not found") + .to_string()) + .unwrap()) +} diff --git a/mumlib/src/lib.rs b/mumlib/src/lib.rs index b26db13..93b7682 100644 --- a/mumlib/src/lib.rs +++ b/mumlib/src/lib.rs @@ -1,4 +1,5 @@ pub mod command; +pub mod config; pub mod error; pub mod state; -- cgit v1.2.1 From 3e61f2d4a48b621c4cef820e24cd2515cbc1c919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 02:40:43 +0200 Subject: convert config to string --- mumd/src/main.rs | 1 + mumd/src/state.rs | 4 ++++ mumlib/src/config.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/mumd/src/main.rs b/mumd/src/main.rs index 75726f8..5307a09 100644 --- a/mumd/src/main.rs +++ b/mumd/src/main.rs @@ -35,6 +35,7 @@ async fn main() { watch::channel::>(None); let state = State::new(packet_sender, connection_info_sender); + state.config().write_default_cfg(); let state = Arc::new(Mutex::new(state)); let (_, _, _, e) = join!( diff --git a/mumd/src/state.rs b/mumd/src/state.rs index e2892fc..e199552 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -215,6 +215,10 @@ impl State { .unwrap(); } + pub fn config(&self) -> &Config { + &self.config + } + pub fn audio(&self) -> &Audio { &self.audio } diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index 0012cc6..d6550c1 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -1,25 +1,34 @@ -use serde::Deserialize; +use log::*; +use serde::{Deserialize, Serialize}; use std::fs; +use toml::Value; use toml::value::Array; -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize)] struct TOMLConfig { audio: Option, servers: Option, } -#[derive(Debug, Deserialize)] +#[derive(Debug)] pub struct Config { pub audio: Option, pub servers: Option>, } -#[derive(Debug, Deserialize)] +impl Config { + pub fn write_default_cfg(&self) { + debug!("{}", toml::to_string(&(TOMLConfig::from(self))).unwrap()); + //fs::write(, get_cfg_path()) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct AudioConfig { pub input_volume: Option, } -#[derive(Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct ServerConfig { pub name: String, pub host: String, @@ -29,7 +38,7 @@ pub struct ServerConfig { } fn get_cfg_path() -> String { - "~/.mumdrc".to_string() //TODO XDG_CONFIG and whatever + ".mumdrc".to_string() //TODO XDG_CONFIG and whatever } impl From for Config { @@ -48,6 +57,38 @@ impl From for Config { } } +impl From for TOMLConfig { + fn from(config: Config) -> Self { + TOMLConfig { + audio: config.audio, + servers: if let Some(servers) = config.servers { + Some(servers + .into_iter() + .map(|s| Value::try_from::(s).unwrap()) + .collect()) + } else { + None + }, + } + } +} + +impl From<&Config> for TOMLConfig { + fn from(config: &Config) -> Self { + TOMLConfig { + audio: config.audio.clone(), + servers: if let Some(servers) = config.servers.clone() { + Some(servers + .into_iter() + .map(|s| Value::try_from::(s).unwrap()) + .collect()) + } else { + None + }, + } + } +} + pub fn read_default_cfg() -> Config { //TODO ignore when config file doesn't exist Config::from( -- cgit v1.2.1 From 26ccc76b3fcab00d21f88346d816fb83c2ae7563 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 02:50:45 +0200 Subject: write config to file --- mumlib/src/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index d6550c1..e2ede02 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -18,8 +18,8 @@ pub struct Config { impl Config { pub fn write_default_cfg(&self) { - debug!("{}", toml::to_string(&(TOMLConfig::from(self))).unwrap()); - //fs::write(, get_cfg_path()) + debug!("{}", toml::to_string(&TOMLConfig::from(self)).unwrap()); + fs::write(get_cfg_path(), toml::to_string(&TOMLConfig::from(self)).unwrap()).unwrap(); } } -- cgit v1.2.1 From 00f95b860b30923016ebf5d9e78c520b95afb9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 03:28:02 +0200 Subject: server config subcommand --- mumctl/src/main.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++- mumlib/src/config.rs | 2 -- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index f4b8139..7b60f04 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -1,7 +1,9 @@ use clap::{App, AppSettings, Arg, Shell, SubCommand}; use colored::Colorize; use ipc_channel::ipc::{self, IpcSender}; +use log::*; use mumlib::command::{Command, CommandResponse}; +use mumlib::config; use mumlib::setup_logger; use mumlib::state::Channel; use std::{fs, io, iter}; @@ -18,6 +20,7 @@ macro_rules! err_print { fn main() { setup_logger(io::stderr(), true); + let mut config = config::read_default_cfg(); let mut app = App::new("mumctl") .setting(AppSettings::ArgRequiredElseHelp) @@ -31,7 +34,13 @@ fn main() { .arg(Arg::with_name("username").required(true).index(2)) .arg(Arg::with_name("port").short("p").long("port").takes_value(true)), ) - .subcommand(SubCommand::with_name("disconnect")), + .subcommand(SubCommand::with_name("disconnect")) + .subcommand( + SubCommand::with_name("config") + .setting(AppSettings::ArgRequiredElseHelp) + .arg(Arg::with_name("server_name").required(true).index(1)) + .arg(Arg::with_name("var_name").required(true).index(2)) + .arg(Arg::with_name("var_value").required(true).index(3))), ) .subcommand( SubCommand::with_name("channel") @@ -79,6 +88,40 @@ fn main() { } } else if let Some(_) = matches.subcommand_matches("disconnect") { err_print!(send_command(Command::ServerDisconnect)); + } else if let Some(matches) = matches.subcommand_matches("config") { + let server_name = matches.value_of("server_name").unwrap(); + let var_name = matches.value_of("var_name").unwrap(); + let var_value = matches.value_of("var_value").unwrap(); + if let Some(ref mut servers) = config.servers { + let server = servers + .iter_mut() + .find( + |s| s.name == server_name); + if server.is_none() { + println!("{} server {} not found", "error:".red(), server_name); + } else { + let server = server.unwrap(); + match var_name { + "host" => { + server.host = var_value.to_string(); + }, + "port" => { + server.port = var_value.parse().unwrap(); + }, + "username" => { + server.username = Some(var_value.to_string()); + }, + "password" => { + server.password = Some(var_value.to_string()); //TODO ask stdin if empty + }, + &_ => { + println!("{} variable {} not found", "error:".red(), var_name); + }, + }; + } + } else { + println!("{} no servers found in configuration", "error:".red()); + } } } else if let Some(matches) = matches.subcommand_matches("channel") { if let Some(_matches) = matches.subcommand_matches("list") { @@ -153,6 +196,8 @@ fn main() { ); return; }; + + config.write_default_cfg(); } fn send_command(command: Command) -> mumlib::error::Result> { diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index e2ede02..d93b172 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -1,4 +1,3 @@ -use log::*; use serde::{Deserialize, Serialize}; use std::fs; use toml::Value; @@ -18,7 +17,6 @@ pub struct Config { impl Config { pub fn write_default_cfg(&self) { - debug!("{}", toml::to_string(&TOMLConfig::from(self)).unwrap()); fs::write(get_cfg_path(), toml::to_string(&TOMLConfig::from(self)).unwrap()).unwrap(); } } -- cgit v1.2.1 From 9d01775d4ce468718c903d9f9e80e696359fdbe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 03:35:07 +0200 Subject: server rename command --- mumctl/src/main.rs | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 7b60f04..eaad1d1 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -32,27 +32,27 @@ fn main() { .setting(AppSettings::ArgRequiredElseHelp) .arg(Arg::with_name("host").required(true).index(1)) .arg(Arg::with_name("username").required(true).index(2)) - .arg(Arg::with_name("port").short("p").long("port").takes_value(true)), - ) + .arg(Arg::with_name("port").short("p").long("port").takes_value(true))) .subcommand(SubCommand::with_name("disconnect")) .subcommand( SubCommand::with_name("config") .setting(AppSettings::ArgRequiredElseHelp) .arg(Arg::with_name("server_name").required(true).index(1)) .arg(Arg::with_name("var_name").required(true).index(2)) - .arg(Arg::with_name("var_value").required(true).index(3))), - ) + .arg(Arg::with_name("var_value").required(true).index(3))) + .subcommand( + SubCommand::with_name("rename") + .setting(AppSettings::ArgRequiredElseHelp) + .arg(Arg::with_name("prev_name").required(true).index(1)) + .arg(Arg::with_name("next_name").required(true).index(2)))) .subcommand( SubCommand::with_name("channel") .setting(AppSettings::ArgRequiredElseHelp) .subcommand( SubCommand::with_name("list") - .arg(Arg::with_name("short").short("s").long("short")), - ) + .arg(Arg::with_name("short").short("s").long("short"))) .subcommand( - SubCommand::with_name("connect").arg(Arg::with_name("channel").required(true)), - ), - ) + SubCommand::with_name("connect").arg(Arg::with_name("channel").required(true)))) .subcommand(SubCommand::with_name("status")) .subcommand(SubCommand::with_name("config") .arg(Arg::with_name("name") @@ -102,6 +102,9 @@ fn main() { } else { let server = server.unwrap(); match var_name { + "name" => { + println!("use mumctl server rename instead!"); + }, "host" => { server.host = var_value.to_string(); }, @@ -122,6 +125,21 @@ fn main() { } else { println!("{} no servers found in configuration", "error:".red()); } + } else if let Some(matches) = matches.subcommand_matches("rename") { + if let Some(ref mut servers) = config.servers { + let prev_name = matches.value_of("prev_name").unwrap(); + let next_name = matches.value_of("next_name").unwrap(); + let server = servers + .iter_mut() + .find( + |s| s.name == prev_name + ); + if server.is_none() { + println!("{} server {} not found", "error:".red(), prev_name); + } else { + server.unwrap().name = next_name.to_string(); + } + } } } else if let Some(matches) = matches.subcommand_matches("channel") { if let Some(_matches) = matches.subcommand_matches("list") { -- cgit v1.2.1 From e8e24a6a630bec475232ab862c864ddb59d1526f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 03:58:05 +0200 Subject: server new --- mumctl/src/main.rs | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index eaad1d1..2cffe44 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -4,6 +4,7 @@ use ipc_channel::ipc::{self, IpcSender}; use log::*; use mumlib::command::{Command, CommandResponse}; use mumlib::config; +use mumlib::config::ServerConfig; use mumlib::setup_logger; use mumlib::state::Channel; use std::{fs, io, iter}; @@ -44,7 +45,15 @@ fn main() { SubCommand::with_name("rename") .setting(AppSettings::ArgRequiredElseHelp) .arg(Arg::with_name("prev_name").required(true).index(1)) - .arg(Arg::with_name("next_name").required(true).index(2)))) + .arg(Arg::with_name("next_name").required(true).index(2))) + .subcommand( + SubCommand::with_name("add") + .setting(AppSettings::ArgRequiredElseHelp) + .arg(Arg::with_name("name").required(true)) + .arg(Arg::with_name("host").required(true)) + .arg(Arg::with_name("port").long("port").takes_value(true).default_value("64738")) + .arg(Arg::with_name("username").long("username").takes_value(true)) + .arg(Arg::with_name("password").long("password").takes_value(true)))) .subcommand( SubCommand::with_name("channel") .setting(AppSettings::ArgRequiredElseHelp) @@ -140,6 +149,41 @@ fn main() { server.unwrap().name = next_name.to_string(); } } + } else if let Some(matches) = matches.subcommand_matches("add") { + let name = matches.value_of("name").unwrap().to_string(); + let host = matches.value_of("host").unwrap().to_string(); + let port = matches.value_of("port").unwrap().parse().unwrap(); + let username = if let Some(username) = matches.value_of("username") { + Some(username.to_string()) + } else { + None + }; + let password = if let Some(password) = matches.value_of("password") { + Some(password.to_string()) + } else { + None + }; + if let Some(ref mut servers) = config.servers { + if servers.into_iter().any(|s| s.name == name) { + println!("{} a server named {} already exists", "error:".red(), name); + } else { + servers.push(ServerConfig { + name, + host, + port, + username, + password, + }); + } + } else { + config.servers = Some(vec![ServerConfig { + name, + host, + port, + username, + password, + }]); + } } } else if let Some(matches) = matches.subcommand_matches("channel") { if let Some(_matches) = matches.subcommand_matches("list") { -- cgit v1.2.1 From 6d4206da1cb917e33a2ae874b11fc35a001de639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 03:59:08 +0200 Subject: skip arg .index() --- mumctl/src/main.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 2cffe44..f35c826 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -31,21 +31,21 @@ fn main() { .subcommand( SubCommand::with_name("connect") .setting(AppSettings::ArgRequiredElseHelp) - .arg(Arg::with_name("host").required(true).index(1)) - .arg(Arg::with_name("username").required(true).index(2)) + .arg(Arg::with_name("host").required(true)) + .arg(Arg::with_name("username").required(true)) .arg(Arg::with_name("port").short("p").long("port").takes_value(true))) .subcommand(SubCommand::with_name("disconnect")) .subcommand( SubCommand::with_name("config") .setting(AppSettings::ArgRequiredElseHelp) - .arg(Arg::with_name("server_name").required(true).index(1)) - .arg(Arg::with_name("var_name").required(true).index(2)) - .arg(Arg::with_name("var_value").required(true).index(3))) + .arg(Arg::with_name("server_name").required(true)) + .arg(Arg::with_name("var_name").required(true)) + .arg(Arg::with_name("var_value").required(true))) .subcommand( SubCommand::with_name("rename") .setting(AppSettings::ArgRequiredElseHelp) - .arg(Arg::with_name("prev_name").required(true).index(1)) - .arg(Arg::with_name("next_name").required(true).index(2))) + .arg(Arg::with_name("prev_name").required(true)) + .arg(Arg::with_name("next_name").required(true))) .subcommand( SubCommand::with_name("add") .setting(AppSettings::ArgRequiredElseHelp) -- cgit v1.2.1 From 130059b4270dde7c49fd1e86e7400d5e611ee790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 04:10:01 +0200 Subject: update usage.org --- usage.org | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/usage.org b/usage.org index 8746014..9402f39 100644 --- a/usage.org +++ b/usage.org @@ -16,7 +16,7 @@ We want to support / explain how to do the following at some point: The daemon doesn't do anything by itself. Interfacing with it is done through `mumctl`. -* Basic commands +* 0.1 The basic commands are the smallest subset of commands that allow the user to actually use mum for something. In this case it means connecting to a server, listing channels and connecting to channels. @@ -85,17 +85,17 @@ your_name@localhost:65387/root (3) your_name #+END_SRC -* More commands +* 0.2 ** server -*** add -Add a server with a name: +*** TODO add +**** DONE With name #+BEGIN_SRC bash -$ mumctl server add 127.0.0.1 loopback +$ mumctl server add loopback 127.0.0.1 username: *** password: *** #+END_SRC -Add a server without a name: +**** TODO Without name #+BEGIN_SRC bash $ mumctl server add 127.0.0.1 username: *** @@ -110,22 +110,22 @@ loopback [4 / 100] 127.0.0.1 [4 / 100] 127.0.0.3 [OFFLINE] #+END_SRC -*** config -**** username +*** TODO config +**** DONE username #+BEGIN_SRC bash -$ mumctl server config loopback set username xX_gamerboy_Xx +$ mumctl server config loopback username xX_gamerboy_Xx #+END_SRC -**** password +**** TODO password #+BEGIN_SRC bash -$ mumctl server config loopback set password *** +$ mumctl server config loopback password *** #+END_SRC Optionally ask stdin #+BEGIN_SRC bash -$ mumctl server config loopback set password +$ mumctl server config loopback password enter password: *** #+END_SRC -*** connect: handle invalid keys +*** TODO connect: handle invalid keys #+BEGIN_SRC bash server offered invalid key. what do you want to do? [I]nspect, [A]ccept, [D]eny, [C]ompare, [T]emporarily trust (default D): @@ -135,11 +135,11 @@ server offered invalid key. what do you want to do? - Deny: Abort the connection. Do not trust the key. - Compare: Compare the key to a file to confirm legitimacy and ask again. - Temporarily trust: Accept the key and connect, but do not trust the key. -*** rename +*** DONE rename #+BEGIN_SRC bash $ mumctl server rename loopback my_server #+END_SRC -** config +** TODO config #+BEGIN_SRC bash $ mumctl config audio.input_volume 1.1 $ mumctl config audio.input_volume -- cgit v1.2.1 From 034efb9431897c098f859286b059298ea1123471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 16:34:02 +0200 Subject: clap cleanup --- mumctl/src/main.rs | 56 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index f35c826..5e6ce84 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -30,51 +30,61 @@ fn main() { .setting(AppSettings::ArgRequiredElseHelp) .subcommand( SubCommand::with_name("connect") - .setting(AppSettings::ArgRequiredElseHelp) .arg(Arg::with_name("host").required(true)) .arg(Arg::with_name("username").required(true)) - .arg(Arg::with_name("port").short("p").long("port").takes_value(true))) - .subcommand(SubCommand::with_name("disconnect")) + .arg(Arg::with_name("port") + .long("port") + .short("p") + .takes_value(true))) + .subcommand( + SubCommand::with_name("disconnect")) .subcommand( SubCommand::with_name("config") - .setting(AppSettings::ArgRequiredElseHelp) .arg(Arg::with_name("server_name").required(true)) .arg(Arg::with_name("var_name").required(true)) .arg(Arg::with_name("var_value").required(true))) .subcommand( SubCommand::with_name("rename") - .setting(AppSettings::ArgRequiredElseHelp) .arg(Arg::with_name("prev_name").required(true)) .arg(Arg::with_name("next_name").required(true))) .subcommand( SubCommand::with_name("add") - .setting(AppSettings::ArgRequiredElseHelp) .arg(Arg::with_name("name").required(true)) .arg(Arg::with_name("host").required(true)) - .arg(Arg::with_name("port").long("port").takes_value(true).default_value("64738")) - .arg(Arg::with_name("username").long("username").takes_value(true)) - .arg(Arg::with_name("password").long("password").takes_value(true)))) + .arg(Arg::with_name("port") + .long("port") + .takes_value(true) + .default_value("64738")) + .arg(Arg::with_name("username") + .long("username") + .takes_value(true)) + .arg(Arg::with_name("password") + .long("password") + .takes_value(true)))) .subcommand( SubCommand::with_name("channel") .setting(AppSettings::ArgRequiredElseHelp) .subcommand( SubCommand::with_name("list") - .arg(Arg::with_name("short").short("s").long("short"))) + .arg(Arg::with_name("short") + .long("short") + .short("s"))) .subcommand( - SubCommand::with_name("connect").arg(Arg::with_name("channel").required(true)))) - .subcommand(SubCommand::with_name("status")) - .subcommand(SubCommand::with_name("config") - .arg(Arg::with_name("name") - .required(true)) - .arg(Arg::with_name("value") - .required(true))) + SubCommand::with_name("connect") + .arg(Arg::with_name("channel").required(true)))) + .subcommand( + SubCommand::with_name("status")) + .subcommand( + SubCommand::with_name("config") + .arg(Arg::with_name("name").required(true)) + .arg(Arg::with_name("value").required(true))) .subcommand(SubCommand::with_name("completions") - .arg(Arg::with_name("zsh") - .long("zsh")) - .arg(Arg::with_name("bash") - .long("bash")) - .arg(Arg::with_name("fish") - .long("fish"))); + .arg(Arg::with_name("zsh") + .long("zsh")) + .arg(Arg::with_name("bash") + .long("bash")) + .arg(Arg::with_name("fish") + .long("fish"))); let matches = app.clone().get_matches(); -- cgit v1.2.1 From d7a35eaf7900659d54419ae356fec1f658caac48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 17:44:17 +0200 Subject: minor --- mumctl/src/main.rs | 8 ++++---- mumd/src/state.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 5e6ce84..44c5d26 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -111,7 +111,7 @@ fn main() { let server_name = matches.value_of("server_name").unwrap(); let var_name = matches.value_of("var_name").unwrap(); let var_value = matches.value_of("var_value").unwrap(); - if let Some(ref mut servers) = config.servers { + if let Some(servers) = &mut config.servers { let server = servers .iter_mut() .find( @@ -136,7 +136,7 @@ fn main() { "password" => { server.password = Some(var_value.to_string()); //TODO ask stdin if empty }, - &_ => { + _ => { println!("{} variable {} not found", "error:".red(), var_name); }, }; @@ -145,7 +145,7 @@ fn main() { println!("{} no servers found in configuration", "error:".red()); } } else if let Some(matches) = matches.subcommand_matches("rename") { - if let Some(ref mut servers) = config.servers { + if let Some(servers) = &mut config.servers { let prev_name = matches.value_of("prev_name").unwrap(); let next_name = matches.value_of("next_name").unwrap(); let server = servers @@ -173,7 +173,7 @@ fn main() { } else { None }; - if let Some(ref mut servers) = config.servers { + if let Some(servers) = &mut config.servers { if servers.into_iter().any(|s| s.name == name) { println!("{} a server named {} already exists", "error:".red(), name); } else { diff --git a/mumd/src/state.rs b/mumd/src/state.rs index e199552..5e1908c 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -40,7 +40,7 @@ impl State { ) -> Self { let config = mumlib::config::read_default_cfg(); let audio = Audio::new(); - if let Some(ref audio_config) = config.audio { + if let Some(audio_config) = &config.audio { if let Some(input_volume) = audio_config.input_volume { audio.set_input_volume(input_volume); } -- cgit v1.2.1 From f5f14327f7038159541f9f569170268fd64a8fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 23:33:06 +0200 Subject: dont write config after loading state --- mumd/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/mumd/src/main.rs b/mumd/src/main.rs index 5307a09..75726f8 100644 --- a/mumd/src/main.rs +++ b/mumd/src/main.rs @@ -35,7 +35,6 @@ async fn main() { watch::channel::>(None); let state = State::new(packet_sender, connection_info_sender); - state.config().write_default_cfg(); let state = Arc::new(Mutex::new(state)); let (_, _, _, e) = join!( -- cgit v1.2.1 From fa4a2c53705c978c9c3410b4988f53d6db249b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 23:33:56 +0200 Subject: mumd: add method to reload config --- mumd/src/state.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/mumd/src/state.rs b/mumd/src/state.rs index 5e1908c..e436d3d 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -30,7 +30,6 @@ pub struct State { connection_info_sender: watch::Sender>, phase_watcher: (watch::Sender, watch::Receiver), - } impl State { @@ -38,21 +37,17 @@ impl State { packet_sender: mpsc::UnboundedSender>, connection_info_sender: watch::Sender>, ) -> Self { - let config = mumlib::config::read_default_cfg(); let audio = Audio::new(); - if let Some(audio_config) = &config.audio { - if let Some(input_volume) = audio_config.input_volume { - audio.set_input_volume(input_volume); - } - } - Self { - config, + let mut state = Self { + config: mumlib::config::read_default_cfg().expect("format error in config file"), server: None, audio, packet_sender, connection_info_sender, phase_watcher: watch::channel(StatePhase::Disconnected), - } + }; + state.reload_config(); + state } //TODO? move bool inside Result @@ -208,6 +203,16 @@ impl State { self.server.as_mut().unwrap().parse_user_state(msg); } + pub fn reload_config(&mut self) { + self.config = mumlib::config::read_default_cfg() + .expect("format error in config file"); + if let Some(audio_config) = &self.config.audio { + if let Some(input_volume) = audio_config.input_volume { + self.audio.set_input_volume(input_volume); + } + } + } + pub fn initialized(&self) { self.phase_watcher .0 -- cgit v1.2.1 From d75bc24bdd176786a1340e16f7aa3db6e3e6a093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 23:34:39 +0200 Subject: send config-reload-command --- mumctl/src/main.rs | 4 ++++ mumd/src/state.rs | 4 ++++ mumlib/src/command.rs | 1 + 3 files changed, 9 insertions(+) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 44c5d26..e55796b 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -78,6 +78,8 @@ fn main() { SubCommand::with_name("config") .arg(Arg::with_name("name").required(true)) .arg(Arg::with_name("value").required(true))) + .subcommand( + SubCommand::with_name("config-reload")) .subcommand(SubCommand::with_name("completions") .arg(Arg::with_name("zsh") .long("zsh")) @@ -256,6 +258,8 @@ fn main() { println!("{} Unknown config value {}", "error:".red(), name); } } + } else if matches.subcommand_matches("config-reload").is_some() { + send_command(Command::ConfigReload).unwrap(); } else if let Some(matches) = matches.subcommand_matches("completions") { app.gen_completions_to( "mumctl", diff --git a/mumd/src/state.rs b/mumd/src/state.rs index e436d3d..08724dd 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -171,6 +171,10 @@ impl State { self.audio.set_input_volume(volume); (false, Ok(None)) } + Command::ConfigReload => { + self.reload_config(); + (false, Ok(None)) + } } } diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs index b4ab07a..05702f0 100644 --- a/mumlib/src/command.rs +++ b/mumlib/src/command.rs @@ -8,6 +8,7 @@ pub enum Command { channel_identifier: String, }, ChannelList, + ConfigReload, InputVolumeSet(f32), ServerConnect { host: String, -- cgit v1.2.1 From d290a6926b2c495d04396924985ac87e632de1da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 19 Oct 2020 23:35:21 +0200 Subject: some changes They got a bit bundled together but they at least do the following: - read_default_cfg returns a result - command to print all server config values - command to print a single server config value - command to remove servers - Option::map instead of if let Some()-... - TryFrom instead of Try --- mumctl/src/main.rs | 128 ++++++++++++++++++++++++++++++--------------------- mumlib/src/config.rs | 64 +++++++++----------------- 2 files changed, 98 insertions(+), 94 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index e55796b..7c36f02 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -21,7 +21,8 @@ macro_rules! err_print { fn main() { setup_logger(io::stderr(), true); - let mut config = config::read_default_cfg(); + let mut config = config::read_default_cfg() + .expect("format error in config file"); let mut app = App::new("mumctl") .setting(AppSettings::ArgRequiredElseHelp) @@ -41,8 +42,8 @@ fn main() { .subcommand( SubCommand::with_name("config") .arg(Arg::with_name("server_name").required(true)) - .arg(Arg::with_name("var_name").required(true)) - .arg(Arg::with_name("var_value").required(true))) + .arg(Arg::with_name("var_name")) + .arg(Arg::with_name("var_value"))) .subcommand( SubCommand::with_name("rename") .arg(Arg::with_name("prev_name").required(true)) @@ -60,7 +61,10 @@ fn main() { .takes_value(true)) .arg(Arg::with_name("password") .long("password") - .takes_value(true)))) + .takes_value(true))) + .subcommand( + SubCommand::with_name("remove") + .arg(Arg::with_name("name").required(true)))) .subcommand( SubCommand::with_name("channel") .setting(AppSettings::ArgRequiredElseHelp) @@ -111,72 +115,92 @@ fn main() { err_print!(send_command(Command::ServerDisconnect)); } else if let Some(matches) = matches.subcommand_matches("config") { let server_name = matches.value_of("server_name").unwrap(); - let var_name = matches.value_of("var_name").unwrap(); - let var_value = matches.value_of("var_value").unwrap(); if let Some(servers) = &mut config.servers { let server = servers .iter_mut() - .find( - |s| s.name == server_name); - if server.is_none() { + .find(|s| s.name == server_name); + if let Some(server) = server { + if let Some(var_name) = matches.value_of("var_name") { + if let Some(var_value) = matches.value_of("var_value") { + // save var_value in var_name + match var_name { + "name" => { + println!("{} use mumctl server rename instead!", "error:".red()); + }, + "host" => { + server.host = var_value.to_string(); + }, + "port" => { + server.port = Some(var_value.parse().unwrap()); + }, + "username" => { + server.username = Some(var_value.to_string()); + }, + "password" => { + server.password = Some(var_value.to_string()); //TODO ask stdin if empty + }, + _ => { + println!("{} variable {} not found", "error:".red(), var_name); + }, + }; + } else { // var_value is None + // print value of var_name + println!("{}", match var_name { + "name" => { server.name.to_string() }, + "host" => { server.host.to_string() }, + "port" => { server.port.map(|s| s.to_string()).unwrap_or(format!("{} not set", "error:".red())) }, + "username" => { server.username.as_ref().map(|s| s.to_string()).unwrap_or(format!("{} not set", "error:".red())) }, + "password" => { server.password.as_ref().map(|s| s.to_string()).unwrap_or(format!("{} not set", "error:".red())) }, + _ => { format!("{} unknown variable", "error:".red()) }, + }); + } + } else { // var_name is None + // print server config + print!("{}{}{}{}", + format!("host: {}\n", server.host.to_string()), + server.port.map(|s| format!("port: {}\n", s)).unwrap_or("".to_string()), + server.username.as_ref().map(|s| format!("username: {}\n", s)).unwrap_or("".to_string()), + server.password.as_ref().map(|s| format!("password: {}\n", s)).unwrap_or("".to_string()), + ) + } + } else { // server is None println!("{} server {} not found", "error:".red(), server_name); - } else { - let server = server.unwrap(); - match var_name { - "name" => { - println!("use mumctl server rename instead!"); - }, - "host" => { - server.host = var_value.to_string(); - }, - "port" => { - server.port = var_value.parse().unwrap(); - }, - "username" => { - server.username = Some(var_value.to_string()); - }, - "password" => { - server.password = Some(var_value.to_string()); //TODO ask stdin if empty - }, - _ => { - println!("{} variable {} not found", "error:".red(), var_name); - }, - }; } - } else { + } else { // servers is None println!("{} no servers found in configuration", "error:".red()); } } else if let Some(matches) = matches.subcommand_matches("rename") { if let Some(servers) = &mut config.servers { let prev_name = matches.value_of("prev_name").unwrap(); let next_name = matches.value_of("next_name").unwrap(); - let server = servers - .iter_mut() - .find( - |s| s.name == prev_name - ); - if server.is_none() { - println!("{} server {} not found", "error:".red(), prev_name); + if let Some(server) = servers + .iter_mut() + .find(|s| s.name == prev_name) { + server.name = next_name.to_string(); } else { - server.unwrap().name = next_name.to_string(); + println!("{} server {} not found", "error:".red(), prev_name); + } + } + } else if let Some(matches) = matches.subcommand_matches("remove") { + let name = matches.value_of("name").unwrap(); + if config.servers.is_none() { + println!("{} no servers found in configuration", "error:".red()); + } else { + let prev_amount = config.servers.as_ref().unwrap().len(); + config.servers = config.servers.map(|servers| servers.into_iter().filter(|server| server.name != name).collect()); + if prev_amount == config.servers.as_ref().unwrap().len() { + println!("{} server {} not found", "error:".red(), name); } } } else if let Some(matches) = matches.subcommand_matches("add") { let name = matches.value_of("name").unwrap().to_string(); let host = matches.value_of("host").unwrap().to_string(); - let port = matches.value_of("port").unwrap().parse().unwrap(); - let username = if let Some(username) = matches.value_of("username") { - Some(username.to_string()) - } else { - None - }; - let password = if let Some(password) = matches.value_of("password") { - Some(password.to_string()) - } else { - None - }; + // optional arguments map None to None + let port = matches.value_of("port").map(|s| s.parse().unwrap()); + let username = matches.value_of("username").map(|s| s.to_string()); + let password = matches.value_of("password").map(|s| s.to_string()); if let Some(servers) = &mut config.servers { - if servers.into_iter().any(|s| s.name == name) { + if servers.iter().any(|s| s.name == name) { println!("{} a server named {} already exists", "error:".red(), name); } else { servers.push(ServerConfig { diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index d93b172..3e55607 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use std::convert::TryFrom; use std::fs; use toml::Value; use toml::value::Array; @@ -9,7 +10,7 @@ struct TOMLConfig { servers: Option, } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Config { pub audio: Option, pub servers: Option>, @@ -17,7 +18,7 @@ pub struct Config { impl Config { pub fn write_default_cfg(&self) { - fs::write(get_cfg_path(), toml::to_string(&TOMLConfig::from(self)).unwrap()).unwrap(); + fs::write(get_cfg_path(), toml::to_string(&TOMLConfig::from(self.clone())).unwrap()).unwrap(); } } @@ -30,7 +31,7 @@ pub struct AudioConfig { pub struct ServerConfig { pub name: String, pub host: String, - pub port: u16, + pub port: Option, pub username: Option, pub password: Option, } @@ -39,19 +40,18 @@ fn get_cfg_path() -> String { ".mumdrc".to_string() //TODO XDG_CONFIG and whatever } -impl From for Config { - fn from(config: TOMLConfig) -> Self { - Config { +impl TryFrom for Config { + type Error = toml::de::Error; + + fn try_from(config: TOMLConfig) -> Result { + Ok(Config { audio: config.audio, - servers: if let Some(servers) = config.servers { - Some(servers - .into_iter() - .map(|s| s.try_into::().expect("invalid server config format")) - .collect()) - } else { - None - }, - } + servers: config.servers.map(|servers| servers + .into_iter() + .map(|s| s.try_into::()) + .collect()) + .transpose()?, + }) } } @@ -59,37 +59,17 @@ impl From for TOMLConfig { fn from(config: Config) -> Self { TOMLConfig { audio: config.audio, - servers: if let Some(servers) = config.servers { - Some(servers - .into_iter() - .map(|s| Value::try_from::(s).unwrap()) - .collect()) - } else { - None - }, - } - } -} - -impl From<&Config> for TOMLConfig { - fn from(config: &Config) -> Self { - TOMLConfig { - audio: config.audio.clone(), - servers: if let Some(servers) = config.servers.clone() { - Some(servers - .into_iter() - .map(|s| Value::try_from::(s).unwrap()) - .collect()) - } else { - None - }, + servers: config.servers.map(|servers| servers + .into_iter() + .map(|s| Value::try_from::(s).unwrap()) + .collect()), } } } -pub fn read_default_cfg() -> Config { - //TODO ignore when config file doesn't exist - Config::from( +pub fn read_default_cfg() -> Result { + //TODO return None if file doesn't exist (Option::map) + Config::try_from( toml::from_str::( &fs::read_to_string( get_cfg_path()) -- cgit v1.2.1 From 2afb9bed4ef5a51b1d2b49728819d187b194829d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Wed, 21 Oct 2020 00:33:30 +0200 Subject: mumctl: refactor matching of config values --- mumctl/src/main.rs | 313 +++++++++++++++++++++++++++++------------------------ 1 file changed, 170 insertions(+), 143 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 7c36f02..0392b2c 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -96,130 +96,17 @@ fn main() { if let Some(matches) = matches.subcommand_matches("server") { if let Some(matches) = matches.subcommand_matches("connect") { - let host = matches.value_of("host").unwrap(); - let username = matches.value_of("username").unwrap(); - let port = match matches.value_of("port").map(|e| e.parse()) { - None => Some(64738), - Some(Err(_)) => None, - Some(Ok(v)) => Some(v), - }; - if let Some(port) = port { - err_print!(send_command(Command::ServerConnect { - host: host.to_string(), - port, - username: username.to_string(), - accept_invalid_cert: true, //TODO - })); - } + match_server_connect(matches); } else if let Some(_) = matches.subcommand_matches("disconnect") { err_print!(send_command(Command::ServerDisconnect)); } else if let Some(matches) = matches.subcommand_matches("config") { - let server_name = matches.value_of("server_name").unwrap(); - if let Some(servers) = &mut config.servers { - let server = servers - .iter_mut() - .find(|s| s.name == server_name); - if let Some(server) = server { - if let Some(var_name) = matches.value_of("var_name") { - if let Some(var_value) = matches.value_of("var_value") { - // save var_value in var_name - match var_name { - "name" => { - println!("{} use mumctl server rename instead!", "error:".red()); - }, - "host" => { - server.host = var_value.to_string(); - }, - "port" => { - server.port = Some(var_value.parse().unwrap()); - }, - "username" => { - server.username = Some(var_value.to_string()); - }, - "password" => { - server.password = Some(var_value.to_string()); //TODO ask stdin if empty - }, - _ => { - println!("{} variable {} not found", "error:".red(), var_name); - }, - }; - } else { // var_value is None - // print value of var_name - println!("{}", match var_name { - "name" => { server.name.to_string() }, - "host" => { server.host.to_string() }, - "port" => { server.port.map(|s| s.to_string()).unwrap_or(format!("{} not set", "error:".red())) }, - "username" => { server.username.as_ref().map(|s| s.to_string()).unwrap_or(format!("{} not set", "error:".red())) }, - "password" => { server.password.as_ref().map(|s| s.to_string()).unwrap_or(format!("{} not set", "error:".red())) }, - _ => { format!("{} unknown variable", "error:".red()) }, - }); - } - } else { // var_name is None - // print server config - print!("{}{}{}{}", - format!("host: {}\n", server.host.to_string()), - server.port.map(|s| format!("port: {}\n", s)).unwrap_or("".to_string()), - server.username.as_ref().map(|s| format!("username: {}\n", s)).unwrap_or("".to_string()), - server.password.as_ref().map(|s| format!("password: {}\n", s)).unwrap_or("".to_string()), - ) - } - } else { // server is None - println!("{} server {} not found", "error:".red(), server_name); - } - } else { // servers is None - println!("{} no servers found in configuration", "error:".red()); - } + match_server_config(matches, &mut config); } else if let Some(matches) = matches.subcommand_matches("rename") { - if let Some(servers) = &mut config.servers { - let prev_name = matches.value_of("prev_name").unwrap(); - let next_name = matches.value_of("next_name").unwrap(); - if let Some(server) = servers - .iter_mut() - .find(|s| s.name == prev_name) { - server.name = next_name.to_string(); - } else { - println!("{} server {} not found", "error:".red(), prev_name); - } - } + match_server_rename(matches, &mut config); } else if let Some(matches) = matches.subcommand_matches("remove") { - let name = matches.value_of("name").unwrap(); - if config.servers.is_none() { - println!("{} no servers found in configuration", "error:".red()); - } else { - let prev_amount = config.servers.as_ref().unwrap().len(); - config.servers = config.servers.map(|servers| servers.into_iter().filter(|server| server.name != name).collect()); - if prev_amount == config.servers.as_ref().unwrap().len() { - println!("{} server {} not found", "error:".red(), name); - } - } + match_server_remove(matches, &mut config); } else if let Some(matches) = matches.subcommand_matches("add") { - let name = matches.value_of("name").unwrap().to_string(); - let host = matches.value_of("host").unwrap().to_string(); - // optional arguments map None to None - let port = matches.value_of("port").map(|s| s.parse().unwrap()); - let username = matches.value_of("username").map(|s| s.to_string()); - let password = matches.value_of("password").map(|s| s.to_string()); - if let Some(servers) = &mut config.servers { - if servers.iter().any(|s| s.name == name) { - println!("{} a server named {} already exists", "error:".red(), name); - } else { - servers.push(ServerConfig { - name, - host, - port, - username, - password, - }); - } - } else { - config.servers = Some(vec![ServerConfig { - name, - host, - port, - username, - password, - }]); - } + match_server_add(matches, &mut config); } } else if let Some(matches) = matches.subcommand_matches("channel") { if let Some(_matches) = matches.subcommand_matches("list") { @@ -237,34 +124,12 @@ fn main() { channel_identifier: matches.value_of("channel").unwrap().to_string() })); } - } else if let Some(_matches) = matches.subcommand_matches("status") { + } else if let Some(_) = matches.subcommand_matches("status") { match send_command(Command::Status) { Ok(res) => match res { Some(CommandResponse::Status { server_state }) => { - println!( - "Connected to {} as {}", - server_state.host, server_state.username - ); - let own_channel = server_state - .channels - .iter() - .find(|e| e.users.iter().any(|e| e.name == server_state.username)) - .unwrap(); - println!( - "Currently in {} with {} other client{}:", - own_channel.name, - own_channel.users.len() - 1, - if own_channel.users.len() == 2 { - "" - } else { - "s" - } - ); - println!("{}{}", INDENTATION, own_channel.name); - for user in &own_channel.users { - println!("{}{}{}", INDENTATION, INDENTATION, user); - } - } + parse_status(&server_state); + }, _ => unreachable!(), }, Err(e) => println!("{} {}", "error:".red(), e), @@ -300,6 +165,168 @@ fn main() { config.write_default_cfg(); } +fn match_server_connect(matches : &clap::ArgMatches<>) { + let host = matches.value_of("host").unwrap(); + let username = matches.value_of("username").unwrap(); + let port = match matches.value_of("port").map(|e| e.parse()) { + None => Some(64738), + Some(Err(_)) => None, + Some(Ok(v)) => Some(v), + }; + if let Some(port) = port { + err_print!(send_command(Command::ServerConnect { + host: host.to_string(), + port, + username: username.to_string(), + accept_invalid_cert: true, //TODO + })); + } +} + +fn match_server_config(matches: &clap::ArgMatches<>, config: &mut mumlib::config::Config) { + let server_name = matches.value_of("server_name").unwrap(); + if let Some(servers) = &mut config.servers { + let server = servers + .iter_mut() + .find(|s| s.name == server_name); + if let Some(server) = server { + if let Some(var_name) = matches.value_of("var_name") { + if let Some(var_value) = matches.value_of("var_value") { + // save var_value in var_name (if it is valid) + match var_name { + "name" => { + println!("{} use mumctl server rename instead!", "error:".red()); + }, + "host" => { + server.host = var_value.to_string(); + }, + "port" => { + server.port = Some(var_value.parse().unwrap()); + }, + "username" => { + server.username = Some(var_value.to_string()); + }, + "password" => { + server.password = Some(var_value.to_string()); //TODO ask stdin if empty + }, + _ => { + println!("{} variable {} not found", "error:".red(), var_name); + }, + }; + } else { // var_value is None + // print value of var_name + println!("{}", match var_name { + "name" => { server.name.to_string() }, + "host" => { server.host.to_string() }, + "port" => { server.port.map(|s| s.to_string()).unwrap_or(format!("{} not set", "error:".red())) }, + "username" => { server.username.as_ref().map(|s| s.to_string()).unwrap_or(format!("{} not set", "error:".red())) }, + "password" => { server.password.as_ref().map(|s| s.to_string()).unwrap_or(format!("{} not set", "error:".red())) }, + _ => { format!("{} unknown variable", "error:".red()) }, + }); + } + } else { // var_name is None + // print server config + print!("{}{}{}{}", + format!("host: {}\n", server.host.to_string()), + server.port.map(|s| format!("port: {}\n", s)).unwrap_or("".to_string()), + server.username.as_ref().map(|s| format!("username: {}\n", s)).unwrap_or("".to_string()), + server.password.as_ref().map(|s| format!("password: {}\n", s)).unwrap_or("".to_string()), + ) + } + } else { // server is None + println!("{} server {} not found", "error:".red(), server_name); + } + } else { // servers is None + println!("{} no servers found in configuration", "error:".red()); + } +} + +fn match_server_rename(matches: &clap::ArgMatches<>, config: &mut mumlib::config::Config) { + if let Some(servers) = &mut config.servers { + let prev_name = matches.value_of("prev_name").unwrap(); + let next_name = matches.value_of("next_name").unwrap(); + if let Some(server) = servers + .iter_mut() + .find(|s| s.name == prev_name) { + server.name = next_name.to_string(); + } else { + println!("{} server {} not found", "error:".red(), prev_name); + } + } +} + +fn match_server_remove(matches: &clap::ArgMatches<>, config: &mut mumlib::config::Config) { + let name = matches.value_of("name").unwrap(); + if let Some(servers) = &mut config.servers { + match servers.iter().position(|server| server.name == name) { + Some(idx) => { + servers.remove(idx); + }, + None => { + println!("{} server {} not found", "error:".red(), name); + } + }; + } else { + println!("{} no servers found in configuration", "error:".red()); + } +} + +fn match_server_add(matches: &clap::ArgMatches<>, config: &mut mumlib::config::Config) { + let name = matches.value_of("name").unwrap().to_string(); + let host = matches.value_of("host").unwrap().to_string(); + // optional arguments map None to None + let port = matches.value_of("port").map(|s| s.parse().unwrap()); + let username = matches.value_of("username").map(|s| s.to_string()); + let password = matches.value_of("password").map(|s| s.to_string()); + if let Some(servers) = &mut config.servers { + if servers.iter().any(|s| s.name == name) { + println!("{} a server named {} already exists", "error:".red(), name); + } else { + servers.push(ServerConfig { + name, + host, + port, + username, + password, + }); + } + } else { + config.servers = Some(vec![ServerConfig { + name, + host, + port, + username, + password, + }]); + } +} + +fn parse_status(server_state: &mumlib::state::Server) { + println!( + "Connected to {} as {}", + server_state.host, server_state.username + ); + let own_channel = server_state + .channels + .iter() + .find(|e| e.users.iter().any(|e| e.name == server_state.username)) + .unwrap(); + println!( + "Currently in {} with {} other client{}:", + own_channel.name, + own_channel.users.len() - 1, + if own_channel.users.len() == 2 { + "" + } else { + "s" + } + ); + println!("{}{}", INDENTATION, own_channel.name); + for user in &own_channel.users { + println!("{}{}{}", INDENTATION, INDENTATION, user); + } +} + fn send_command(command: Command) -> mumlib::error::Result> { let (tx_client, rx_client) = ipc::channel::>>().unwrap(); -- cgit v1.2.1 From 6a136ac842dd601ce7f68566c27b5262d221872c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Wed, 21 Oct 2020 00:57:37 +0200 Subject: default cfg is option None if the file doesn't exist --- mumctl/src/main.rs | 27 +++++++++++++++++++-------- mumd/src/state.rs | 22 +++++++++++----------- mumlib/src/config.rs | 40 ++++++++++++++++++++++++++++++---------- 3 files changed, 60 insertions(+), 29 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 0392b2c..6e97296 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -1,7 +1,6 @@ use clap::{App, AppSettings, Arg, Shell, SubCommand}; use colored::Colorize; use ipc_channel::ipc::{self, IpcSender}; -use log::*; use mumlib::command::{Command, CommandResponse}; use mumlib::config; use mumlib::config::ServerConfig; @@ -21,8 +20,10 @@ macro_rules! err_print { fn main() { setup_logger(io::stderr(), true); - let mut config = config::read_default_cfg() - .expect("format error in config file"); + let mut config = config::read_default_cfg(); + if config.is_none() { + println!("{} unable to find config file", "error:".red()); + } let mut app = App::new("mumctl") .setting(AppSettings::ArgRequiredElseHelp) @@ -100,13 +101,21 @@ fn main() { } else if let Some(_) = matches.subcommand_matches("disconnect") { err_print!(send_command(Command::ServerDisconnect)); } else if let Some(matches) = matches.subcommand_matches("config") { - match_server_config(matches, &mut config); + if let Some(config) = &mut config { + match_server_config(matches, config); + } } else if let Some(matches) = matches.subcommand_matches("rename") { - match_server_rename(matches, &mut config); + if let Some(config) = &mut config { + match_server_rename(matches, config); + } } else if let Some(matches) = matches.subcommand_matches("remove") { - match_server_remove(matches, &mut config); + if let Some(config) = &mut config { + match_server_remove(matches, config); + } } else if let Some(matches) = matches.subcommand_matches("add") { - match_server_add(matches, &mut config); + if let Some(config) = &mut config { + match_server_add(matches, config); + } } } else if let Some(matches) = matches.subcommand_matches("channel") { if let Some(_matches) = matches.subcommand_matches("list") { @@ -162,7 +171,9 @@ fn main() { return; }; - config.write_default_cfg(); + if let Some(config) = config { + config.write_default_cfg(); + } } fn match_server_connect(matches : &clap::ArgMatches<>) { diff --git a/mumd/src/state.rs b/mumd/src/state.rs index 08724dd..0dbf9c5 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -22,7 +22,7 @@ pub enum StatePhase { } pub struct State { - config: Config, + config: Option, server: Option, audio: Audio, @@ -39,7 +39,7 @@ impl State { ) -> Self { let audio = Audio::new(); let mut state = Self { - config: mumlib::config::read_default_cfg().expect("format error in config file"), + config: mumlib::config::read_default_cfg(), server: None, audio, packet_sender, @@ -208,12 +208,16 @@ impl State { } pub fn reload_config(&mut self) { - self.config = mumlib::config::read_default_cfg() - .expect("format error in config file"); - if let Some(audio_config) = &self.config.audio { - if let Some(input_volume) = audio_config.input_volume { - self.audio.set_input_volume(input_volume); + if let Some(config) = mumlib::config::read_default_cfg() { + self.config = Some(config); + let config = &self.config.as_ref().unwrap(); + if let Some(audio_config) = &config.audio { + if let Some(input_volume) = audio_config.input_volume { + self.audio.set_input_volume(input_volume); + } } + } else { + warn!("config file not found"); } } @@ -224,10 +228,6 @@ impl State { .unwrap(); } - pub fn config(&self) -> &Config { - &self.config - } - pub fn audio(&self) -> &Audio { &self.audio } diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index 3e55607..aa8a8ed 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -1,3 +1,4 @@ +use log::*; use serde::{Deserialize, Serialize}; use std::convert::TryFrom; use std::fs; @@ -17,8 +18,23 @@ pub struct Config { } impl Config { - pub fn write_default_cfg(&self) { - fs::write(get_cfg_path(), toml::to_string(&TOMLConfig::from(self.clone())).unwrap()).unwrap(); + pub fn write_default_cfg(&self) -> Result<(), std::io::Error> { + let path = get_cfg_path(); + let path = std::path::Path::new(&path); + // Possible race here. It's fine since it shows when: + // 1) the file doesn't exist when checked and is then created + // 2) the file exists when checked but is then removed + // If 1) we don't do anything anyway so it's fine, and if 2) we + // immediately re-create the file which, while not perfect, at least + // should work. Unless the file is removed AND the permissions + // change, but then we don't have permissions so we can't + // do anything anyways. + if !path.exists() { + warn!("config file {} does not exist, ignoring", path.display()); + Ok(()) + } else { + fs::write(path, toml::to_string(&TOMLConfig::from(self.clone())).unwrap()) + } } } @@ -67,13 +83,17 @@ impl From for TOMLConfig { } } -pub fn read_default_cfg() -> Result { - //TODO return None if file doesn't exist (Option::map) - Config::try_from( +pub fn read_default_cfg() -> Option { + Some(Config::try_from( toml::from_str::( - &fs::read_to_string( - get_cfg_path()) - .expect("config file not found") - .to_string()) - .unwrap()) + &match fs::read_to_string(get_cfg_path()) { + Ok(f) => { + f.to_string() + }, + Err(_) => { + return None + } + } + ).expect("invalid TOML in config file") //TODO + ).expect("invalid config in TOML")) //TODO } -- cgit v1.2.1