aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock6
-rw-r--r--changelog/0.2.txt44
-rw-r--r--mumctl/Cargo.toml2
-rw-r--r--mumctl/src/main.rs227
-rw-r--r--mumd/Cargo.toml2
-rw-r--r--mumd/src/audio.rs34
-rw-r--r--mumlib/Cargo.toml2
-rw-r--r--mumlib/src/config.rs67
8 files changed, 272 insertions, 112 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 239a3b0..806bc91 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -742,7 +742,7 @@ dependencies = [
[[package]]
name = "mumctl"
-version = "0.1.0"
+version = "0.2.0"
dependencies = [
"clap",
"colored",
@@ -753,7 +753,7 @@ dependencies = [
[[package]]
name = "mumd"
-version = "0.1.0"
+version = "0.2.0"
dependencies = [
"argparse",
"bytes",
@@ -776,7 +776,7 @@ dependencies = [
[[package]]
name = "mumlib"
-version = "0.1.0"
+version = "0.2.0"
dependencies = [
"colored",
"fern",
diff --git a/changelog/0.2.txt b/changelog/0.2.txt
new file mode 100644
index 0000000..d7f7200
--- /dev/null
+++ b/changelog/0.2.txt
@@ -0,0 +1,44 @@
+778ea0b 0.2 version bump
+768fc7c Merge branch command-alias into main (eskil)
+ee46fd5 Merge branch config-home into main (eskil)
+cd3c1ad Merge branch tcp-event-macro into main (eskil)
+64eca3b Merge branch readme into main (gustav)
+161f58f Merge branch refactor-state into main (gustav)
+92d64a4 Merge branch network-rework into main (gustav)
+b268bec Merge branch refactor-audio into main (gustav)
+685eb0e Merge branch audio-new-clients into main (gustav)
+ff6103c Merge branch lock-cpal into main (gustav)
+34bf730 Merge branch getters into main (gustav)
+d58c2aa Merge branch config-file into main (gustav)
+d688a68 Merge branch port-configuration into main (eskil)
+cf25e78 Merge branch file-logging into main (eskil)
+f30b372 Merge branch socket into main (eskil)
+ccc5f76 Merge branch pretty-print into main (eskil)
+7675171 Merge branch channel-name into main (eskil)
+4e8402c Merge branch input-volume into main (gustav)
+27d8b16 Merge branch error-handling into main (eskil)
+18a3c0b Merge branch cli into main (gustav)
+8e4eb0a Merge branch audio-refactor into main (eskil)
+a40d365 Merge branch commands into main (eskil)
+dd8ebae initial commit
+
+git diff --stat dd8ebae..v0.2 --stat=80 -- **/*.rs
+ mumctl/src/main.rs | 450 ++++++++++++++++++++++++++++++++++++++++++++++
+ mumd/src/audio.rs | 194 ++++++++++++++++++++
+ mumd/src/audio/input.rs | 52 ++++++
+ mumd/src/audio/output.rs | 90 ++++++++++
+ mumd/src/command.rs | 38 ++++
+ mumd/src/main.rs | 92 ++++++++++
+ mumd/src/network.rs | 21 +++
+ mumd/src/network/tcp.rs | 370 ++++++++++++++++++++++++++++++++++++++
+ mumd/src/network/udp.rs | 227 +++++++++++++++++++++++
+ mumd/src/state.rs | 287 +++++++++++++++++++++++++++++
+ mumd/src/state/channel.rs | 184 +++++++++++++++++++
+ mumd/src/state/server.rs | 123 +++++++++++++
+ mumd/src/state/user.rs | 145 +++++++++++++++
+ mumlib/src/command.rs | 28 +++
+ mumlib/src/config.rs | 144 +++++++++++++++
+ mumlib/src/error.rs | 40 +++++
+ mumlib/src/lib.rs | 49 +++++
+ mumlib/src/state.rs | 200 +++++++++++++++++++++
+ 18 files changed, 2734 insertions(+)
diff --git a/mumctl/Cargo.toml b/mumctl/Cargo.toml
index c955afa..8483042 100644
--- a/mumctl/Cargo.toml
+++ b/mumctl/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "mumctl"
-version = "0.1.0"
+version = "0.2.0"
authors = ["Gustav Sörnäs <gustav@sornas.net>",
"Eskil Queseth <eskilq@kth.se>"]
license = "MIT"
diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs
index 7f74077..77340c0 100644
--- a/mumctl/src/main.rs
+++ b/mumctl/src/main.rs
@@ -7,6 +7,7 @@ use mumlib::config::ServerConfig;
use mumlib::setup_logger;
use mumlib::state::Channel;
use std::{fs, io, iter};
+use std::io::BufRead;
const INDENTATION: &str = " ";
@@ -21,9 +22,6 @@ macro_rules! err_print {
fn main() {
setup_logger(io::stderr(), true);
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)
@@ -33,7 +31,7 @@ fn main() {
.subcommand(
SubCommand::with_name("connect")
.arg(Arg::with_name("host").required(true))
- .arg(Arg::with_name("username").required(true))
+ .arg(Arg::with_name("username"))
.arg(Arg::with_name("port")
.long("port")
.short("p")
@@ -42,7 +40,7 @@ fn main() {
SubCommand::with_name("disconnect"))
.subcommand(
SubCommand::with_name("config")
- .arg(Arg::with_name("server_name").required(true))
+ .arg(Arg::with_name("server_name"))
.arg(Arg::with_name("var_name"))
.arg(Arg::with_name("var_value")))
.subcommand(
@@ -97,25 +95,17 @@ fn main() {
if let Some(matches) = matches.subcommand_matches("server") {
if let Some(matches) = matches.subcommand_matches("connect") {
- match_server_connect(matches);
+ match_server_connect(matches, &config);
} else if let Some(_) = matches.subcommand_matches("disconnect") {
err_print!(send_command(Command::ServerDisconnect));
} else if let Some(matches) = matches.subcommand_matches("config") {
- if let Some(config) = &mut config {
- match_server_config(matches, config);
- }
+ match_server_config(matches, &mut config);
} else if let Some(matches) = matches.subcommand_matches("rename") {
- if let Some(config) = &mut config {
- match_server_rename(matches, config);
- }
+ match_server_rename(matches, &mut config);
} else if let Some(matches) = matches.subcommand_matches("remove") {
- if let Some(config) = &mut config {
- match_server_remove(matches, config);
- }
+ match_server_remove(matches, &mut config);
} else if let Some(matches) = matches.subcommand_matches("add") {
- if let Some(config) = &mut config {
- match_server_add(matches, config);
- }
+ match_server_add(matches, &mut config);
}
} else if let Some(matches) = matches.subcommand_matches("channel") {
if let Some(_matches) = matches.subcommand_matches("list") {
@@ -172,26 +162,67 @@ fn main() {
};
if let Some(config) = config {
- config.write_default_cfg().unwrap();
+ if !config::cfg_exists() {
+ println!("Config file not found. Create one in {}? [Y/n]", config::get_creatable_cfg_path());
+ let stdin = std::io::stdin();
+ let response = stdin.lock().lines().next();
+ match response.map(|e| e.map(|e| &e == "Y")) {
+ Some(Ok(true)) => {
+ config.write_default_cfg(true).unwrap();
+ }
+ _ => {},
+ }
+ } else {
+ config.write_default_cfg(false).unwrap();
+ }
}
}
-fn match_server_connect(matches : &clap::ArgMatches<'_>) {
+fn match_server_connect(matches : &clap::ArgMatches<'_>, config: &Option<mumlib::config::Config>) {
let host = matches.value_of("host").unwrap();
- let username = matches.value_of("username").unwrap();
+ let username = matches.value_of("username");
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 {
- match send_command(Command::ServerConnect {
- host: host.to_string(),
- port,
- username: username.to_string(),
- accept_invalid_cert: true, //TODO
- }) {
- Ok(e) => {
+ let response = match config
+ .as_ref()
+ .and_then(|e| e.servers
+ .as_ref()
+ .and_then(|e| e.iter()
+ .find(|e| e.name == host))) {
+ Some(config) => {
+ let host = config.host.as_str();
+ let port = config.port.unwrap_or(port);
+ let username = config.username.as_ref().map(|e| e.as_str()).or(username);
+ if username.is_none() {
+ println!("{} no username specified", "error:".red());
+ return;
+ }
+ send_command(Command::ServerConnect {
+ host: host.to_string(),
+ port,
+ username: username.unwrap().to_string(),
+ accept_invalid_cert: true, //TODO
+ }).map(|e| (e, host))
+ }
+ None => {
+ if username.is_none() {
+ println!("{} no username specified", "error:".red());
+ return
+ }
+ send_command(Command::ServerConnect {
+ host: host.to_string(),
+ port,
+ username: username.unwrap().to_string(),
+ accept_invalid_cert: true, //TODO
+ }).map(|e| (e, host))
+ }
+ };
+ match response {
+ Ok((e, host)) => {
if let Some(CommandResponse::ServerConnect { welcome_message }) = e {
println!("Connected to {}", host);
if let Some(message) = welcome_message {
@@ -206,65 +237,83 @@ fn match_server_connect(matches : &clap::ArgMatches<'_>) {
}
}
-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()) },
- });
+fn match_server_config(matches: &clap::ArgMatches<'_>, config: &mut Option<mumlib::config::Config>) {
+ if config.is_none() {
+ *config = Some(mumlib::config::Config::default());
+ }
+
+ let config = config.as_mut().unwrap();
+
+ if let Some(server_name) = matches.value_of("server_name") {
+ 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 { // 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 { // server is None
- println!("{} server {} not found", "error:".red(), server_name);
+ } else { // servers is None
+ println!("{} no servers found in configuration", "error:".red());
+ }
+ } else {
+ for server in config.servers.iter().flat_map(|e| e.iter()) {
+ println!("{}", 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) {
+fn match_server_rename(matches: &clap::ArgMatches<'_>, config: &mut Option<mumlib::config::Config>) {
+ if config.is_none() {
+ *config = Some(mumlib::config::Config::default());
+ }
+
+ let config = config.as_mut().unwrap();
+
+
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();
@@ -278,7 +327,13 @@ fn match_server_rename(matches: &clap::ArgMatches<'_>, config: &mut mumlib::conf
}
}
-fn match_server_remove(matches: &clap::ArgMatches<'_>, config: &mut mumlib::config::Config) {
+fn match_server_remove(matches: &clap::ArgMatches<'_>, config: &mut Option<mumlib::config::Config>) {
+ if config.is_none() {
+ *config = Some(mumlib::config::Config::default());
+ }
+
+ let config = config.as_mut().unwrap();
+
let name = matches.value_of("name").unwrap();
if let Some(servers) = &mut config.servers {
match servers.iter().position(|server| server.name == name) {
@@ -294,7 +349,13 @@ fn match_server_remove(matches: &clap::ArgMatches<'_>, config: &mut mumlib::conf
}
}
-fn match_server_add(matches: &clap::ArgMatches<'_>, config: &mut mumlib::config::Config) {
+fn match_server_add(matches: &clap::ArgMatches<'_>, config: &mut Option<mumlib::config::Config>) {
+ if config.is_none() {
+ *config = Some(mumlib::config::Config::default());
+ }
+
+ let mut config = config.as_mut().unwrap();
+
let name = matches.value_of("name").unwrap().to_string();
let host = matches.value_of("host").unwrap().to_string();
// optional arguments map None to None
diff --git a/mumd/Cargo.toml b/mumd/Cargo.toml
index c59c32b..350d81e 100644
--- a/mumd/Cargo.toml
+++ b/mumd/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "mumd"
-version = "0.1.0"
+version = "0.2.0"
authors = ["Gustav Sörnäs <gustav@sornas.net>",
"Eskil Queseth <eskilq@kth.se>"]
license = "MIT"
diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs
index 8609a91..7a673ff 100644
--- a/mumd/src/audio.rs
+++ b/mumd/src/audio.rs
@@ -24,30 +24,40 @@ pub struct Audio {
impl Audio {
pub fn new() -> Self {
+ let sample_rate = SampleRate(48000);
+
let host = cpal::default_host();
let output_device = host
.default_output_device()
.expect("default output device not found");
- let mut output_supported_configs_range = output_device
+ let output_supported_config = output_device
.supported_output_configs()
- .expect("error querying output configs");
- let output_supported_config = output_supported_configs_range
- .next()
- .expect("no supported output config??")
- .with_sample_rate(SampleRate(48000));
+ .expect("error querying output configs")
+ .find_map(|c|
+ if c.min_sample_rate() <= sample_rate && c.max_sample_rate() >= sample_rate {
+ Some(c)
+ } else {
+ None
+ })
+ .unwrap()
+ .with_sample_rate(sample_rate);
let output_supported_sample_format = output_supported_config.sample_format();
let output_config: StreamConfig = output_supported_config.into();
let input_device = host
.default_input_device()
.expect("default input device not found");
- let mut input_supported_configs_range = input_device
+ let input_supported_config = input_device
.supported_input_configs()
- .expect("error querying input configs");
- let input_supported_config = input_supported_configs_range
- .next()
- .expect("no supported input config??")
- .with_sample_rate(SampleRate(48000));
+ .expect("error querying output configs")
+ .find_map(|c|
+ if c.min_sample_rate() <= sample_rate && c.max_sample_rate() >= sample_rate {
+ Some(c)
+ } else {
+ None
+ })
+ .unwrap()
+ .with_sample_rate(sample_rate);
let input_supported_sample_format = input_supported_config.sample_format();
let input_config: StreamConfig = input_supported_config.into();
diff --git a/mumlib/Cargo.toml b/mumlib/Cargo.toml
index 471a1fe..59feb75 100644
--- a/mumlib/Cargo.toml
+++ b/mumlib/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "mumlib"
-version = "0.1.0"
+version = "0.2.0"
authors = ["Gustav Sörnäs <gustav@sornas.net>",
"Eskil Queseth <eskilq@kth.se>"]
edition = "2018"
diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs
index aa8a8ed..5c37a2b 100644
--- a/mumlib/src/config.rs
+++ b/mumlib/src/config.rs
@@ -1,9 +1,9 @@
-use log::*;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use std::fs;
use toml::Value;
use toml::value::Array;
+use std::path::Path;
#[derive(Debug, Deserialize, Serialize)]
struct TOMLConfig {
@@ -11,15 +11,15 @@ struct TOMLConfig {
servers: Option<Array>,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Default)]
pub struct Config {
pub audio: Option<AudioConfig>,
pub servers: Option<Vec<ServerConfig>>,
}
impl Config {
- pub fn write_default_cfg(&self) -> Result<(), std::io::Error> {
- let path = get_cfg_path();
+ pub fn write_default_cfg(&self, create: bool) -> Result<(), std::io::Error> {
+ let path = if create { get_creatable_cfg_path() } else { 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
@@ -29,12 +29,11 @@ impl Config {
// 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())
+ if !create && !path.exists() {
+ return Ok(());
}
+
+ fs::write(path, toml::to_string(&TOMLConfig::from(self.clone())).unwrap())
}
}
@@ -52,8 +51,54 @@ pub struct ServerConfig {
pub password: Option<String>,
}
-fn get_cfg_path() -> String {
- ".mumdrc".to_string() //TODO XDG_CONFIG and whatever
+pub fn get_cfg_path() -> String {
+ if let Ok(var) = std::env::var("XDG_CONFIG_HOME") {
+ let path = format!("{}/mumdrc", var);
+ if Path::new(&path).exists() {
+ return path;
+ }
+ } else if let Ok(var) = std::env::var("HOME") {
+ let path = format!("{}/.config/mumdrc", var);
+ if Path::new(&path).exists() {
+ return path;
+ }
+ }
+
+ "/etc/mumdrc".to_string()
+}
+
+pub fn get_creatable_cfg_path() -> String {
+ if let Ok(var) = std::env::var("XDG_CONFIG_HOME") {
+ let path = format!("{}/mumdrc", var);
+ if !Path::new(&path).exists() {
+ return path;
+ }
+ } else if let Ok(var) = std::env::var("HOME") {
+ let path = format!("{}/.config/mumdrc", var);
+ if !Path::new(&path).exists() {
+ return path;
+ }
+ }
+
+ "/etc/mumdrc".to_string()
+}
+
+pub fn cfg_exists() -> bool {
+ if let Ok(var) = std::env::var("XDG_CONFIG_HOME") {
+ let path = format!("{}/mumdrc", var);
+ if Path::new(&path).exists() {
+ return true;
+ }
+ } else if let Ok(var) = std::env::var("HOME") {
+ let path = format!("{}/.config/mumdrc", var);
+ if Path::new(&path).exists() {
+ return true;
+ }
+ } else if Path::new("/etc/mumdrc").exists() {
+ return true;
+ }
+
+ false
}
impl TryFrom<TOMLConfig> for Config {