From 11c823701b12f10933b40044a12cc4048ccf8bd2 Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Sat, 31 Oct 2020 02:27:26 +0100 Subject: add support for mumctl server list --- mumctl/src/main.rs | 36 +++++++++++++++++++++++++++++++-- mumd/src/command.rs | 53 ++++++++++++++++++++++++++++++++++--------------- mumd/src/main.rs | 13 ++++++++++-- mumd/src/network/tcp.rs | 6 +++--- mumd/src/network/udp.rs | 45 +++++++++++++++++++++++++++++++++++++++++ mumd/src/state.rs | 42 +++++++++++++++++++++++++++++---------- mumlib/src/command.rs | 10 ++++++++++ mumlib/src/config.rs | 11 ++++++++++ mumlib/src/lib.rs | 1 + 9 files changed, 183 insertions(+), 34 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 9471b6a..18967db 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -23,6 +23,11 @@ fn main() { setup_logger(io::stderr(), true); let mut config = config::read_default_cfg(); + /*println!("{:?}", send_command(Command::ServerStatus { + host: "icahasse.se".to_string(), + port: 64738, + }).unwrap());*/ + let mut app = App::new("mumctl") .setting(AppSettings::ArgRequiredElseHelp) .subcommand( @@ -74,7 +79,8 @@ fn main() { ) .subcommand( SubCommand::with_name("remove").arg(Arg::with_name("name").required(true)), - ), + ) + .subcommand(SubCommand::with_name("list")), ) .subcommand( SubCommand::with_name("channel") @@ -116,6 +122,32 @@ fn main() { match_server_remove(matches, &mut config); } else if let Some(matches) = matches.subcommand_matches("add") { match_server_add(matches, &mut config); + } else if let Some(_) = matches.subcommand_matches("list") { + let servers = config + .as_ref() + .map(|e| e.servers + .as_ref() + .map(|e| e.clone()) + .unwrap_or(Vec::new())) + .unwrap_or(Vec::new()); + for (server, response) in servers + .into_iter() + .map(|e| { + let response = send_command(Command::ServerStatus { + host: e.host.clone(), + port: e.port.unwrap_or(mumlib::DEFAULT_PORT), + }); + (e, response) + }) + .filter(|e| e.1.is_ok()) + .map(|e| (e.0, e.1.unwrap().unwrap())) + { + if let CommandResponse::ServerStatus { users, max_users, .. } = response { + println!("{} [{}/{}]", server.name, users, max_users) + } else { + unreachable!() + } + } } } else if let Some(matches) = matches.subcommand_matches("channel") { if let Some(_matches) = matches.subcommand_matches("list") { @@ -195,7 +227,7 @@ fn match_server_connect(matches: &clap::ArgMatches<'_>, config: &Option Some(64738), + None => Some(mumlib::DEFAULT_PORT), Some(Err(_)) => None, Some(Ok(v)) => Some(v), }; diff --git a/mumd/src/command.rs b/mumd/src/command.rs index d4b25d0..ff53dc7 100644 --- a/mumd/src/command.rs +++ b/mumd/src/command.rs @@ -1,4 +1,4 @@ -use crate::state::State; +use crate::state::{State, ExecutionContext}; use crate::network::tcp::{TcpEvent, TcpEventCallback}; use ipc_channel::ipc::IpcSender; @@ -6,6 +6,8 @@ use log::*; use mumlib::command::{Command, CommandResponse}; use std::sync::{Arc, Mutex}; use tokio::sync::{mpsc, oneshot}; +use mumble_protocol::ping::PongPacket; +use std::net::SocketAddr; pub async fn handle( state: Arc>, @@ -14,28 +16,47 @@ pub async fn handle( IpcSender>>, )>, tcp_event_register_sender: mpsc::UnboundedSender<(TcpEvent, TcpEventCallback)>, + ping_request_sender: mpsc::UnboundedSender<(u64, SocketAddr, Box)>, ) { debug!("Begin listening for commands"); while let Some((command, response_sender)) = command_receiver.recv().await { debug!("Received command {:?}", command); let mut state = state.lock().unwrap(); - let (event, generator) = state.handle_command(command); + let event = state.handle_command(command); drop(state); - if let Some(event) = event { - let (tx, rx) = oneshot::channel(); - //TODO handle this error - let _ = tcp_event_register_sender.send(( - event, - Box::new(move |e| { - let response = generator(Some(e)); - response_sender.send(response).unwrap(); - tx.send(()).unwrap(); - }), - )); + match event { + ExecutionContext::TcpEvent(event, generator) => { + let (tx, rx) = oneshot::channel(); + //TODO handle this error + let _ = tcp_event_register_sender.send(( + event, + Box::new(move |e| { + let response = generator(e); + response_sender.send(response).unwrap(); + tx.send(()).unwrap(); + }), + )); - rx.await.unwrap(); - } else { - response_sender.send(generator(None)).unwrap(); + rx.await.unwrap(); + } + ExecutionContext::Now(generator) => { + response_sender.send(generator()).unwrap(); + } + ExecutionContext::Ping(generator, converter) => { + match generator() { + Ok(addr) => { + let res = ping_request_sender.send((0, addr, Box::new(move |packet| { + response_sender.send(converter(packet)).unwrap(); + }))); + if res.is_err() { + panic!(); + } + }, + Err(e) => { + response_sender.send(Err(e)).unwrap(); + } + }; + } } } } diff --git a/mumd/src/main.rs b/mumd/src/main.rs index 37ff0dd..70cc21b 100644 --- a/mumd/src/main.rs +++ b/mumd/src/main.rs @@ -36,11 +36,12 @@ async fn main() { let (connection_info_sender, connection_info_receiver) = watch::channel::>(None); let (response_sender, response_receiver) = mpsc::unbounded_channel(); + let (ping_request_sender, ping_request_receiver) = mpsc::unbounded_channel(); let state = State::new(packet_sender, connection_info_sender); let state = Arc::new(Mutex::new(state)); - let (_, _, _, e) = join!( + let (_, _, _, e, _) = join!( network::tcp::handle( Arc::clone(&state), connection_info_receiver.clone(), @@ -53,11 +54,19 @@ async fn main() { connection_info_receiver.clone(), crypt_state_receiver, ), - command::handle(state, command_receiver, response_sender), + command::handle( + state, + command_receiver, + response_sender, + ping_request_sender, + ), spawn_blocking(move || { // IpcSender is blocking receive_oneshot_commands(command_sender); }), + network::udp::handle_pings( + ping_request_receiver + ), ); e.unwrap(); } diff --git a/mumd/src/network/tcp.rs b/mumd/src/network/tcp.rs index cd11690..131f066 100644 --- a/mumd/src/network/tcp.rs +++ b/mumd/src/network/tcp.rs @@ -27,7 +27,7 @@ type TcpSender = SplitSink< type TcpReceiver = SplitStream, ControlCodec>>; -pub(crate) type TcpEventCallback = Box; +pub(crate) type TcpEventCallback = Box; #[derive(Debug, Clone, Hash, Eq, PartialEq)] pub enum TcpEvent { @@ -228,7 +228,7 @@ async fn listen( if let Some(vec) = event_queue.lock().unwrap().get_mut(&TcpEvent::Connected) { let old = std::mem::take(vec); for handler in old { - handler(&TcpEventData::Connected(&msg)); + handler(TcpEventData::Connected(&msg)); } } let mut state = state.lock().unwrap(); @@ -282,7 +282,7 @@ async fn listen( if let Some(vec) = event_queue.lock().unwrap().get_mut(&TcpEvent::Disconnected) { let old = std::mem::take(vec); for handler in old { - handler(&TcpEventData::Disconnected); + handler(TcpEventData::Disconnected); } } }, diff --git a/mumd/src/network/udp.rs b/mumd/src/network/udp.rs index 4f96c4c..febf7f1 100644 --- a/mumd/src/network/udp.rs +++ b/mumd/src/network/udp.rs @@ -13,6 +13,10 @@ use std::sync::{Arc, Mutex}; use tokio::net::UdpSocket; use tokio::sync::{mpsc, oneshot, watch}; use tokio_util::udp::UdpFramed; +use std::collections::HashMap; +use mumble_protocol::ping::{PingPacket, PongPacket}; +use std::rc::Rc; +use std::convert::TryFrom; type UdpSender = SplitSink, (VoicePacket, SocketAddr)>; type UdpReceiver = SplitStream>; @@ -225,3 +229,44 @@ async fn send_voice( debug!("UDP sender process killed"); } + +pub async fn handle_pings( + mut ping_request_receiver: mpsc::UnboundedReceiver<(u64, SocketAddr, Box)>, +) { + let udp_socket = UdpSocket::bind((Ipv6Addr::from(0u128), 0u16)) + .await + .expect("Failed to bind UDP socket"); + + let (mut receiver, mut sender) = udp_socket.split(); + + let pending = Rc::new(Mutex::new(HashMap::new())); + + let sender_handle = async { + while let Some((id, socket_addr, handle)) = ping_request_receiver.recv().await { + let packet = PingPacket { id }; + let packet: [u8; 12] = packet.into(); + sender.send_to(&packet, &socket_addr).await.unwrap(); + pending.lock().unwrap().insert(id, handle); + } + }; + + let receiver_handle = async { + let mut buf = vec![0; 24]; + while let Ok(read) = receiver.recv(&mut buf).await { + assert_eq!(read, 24); + + let packet = match PongPacket::try_from(buf.as_slice()) { + Ok(v) => v, + Err(_) => panic!(), + }; + + if let Some(handler) = pending.lock().unwrap().remove(&packet.id) { + handler(packet); + } + } + }; + + debug!("Waiting for ping requests"); + + join!(sender_handle, receiver_handle); +} \ No newline at end of file diff --git a/mumd/src/state.rs b/mumd/src/state.rs index 81b6c98..0d0fad8 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -16,21 +16,29 @@ use mumlib::command::{Command, CommandResponse}; use mumlib::config::Config; use mumlib::error::{ChannelIdentifierError, Error}; use mumlib::state::UserDiff; -use std::net::ToSocketAddrs; +use std::net::{ToSocketAddrs, SocketAddr}; use tokio::sync::{mpsc, watch}; +use mumble_protocol::ping::PongPacket; macro_rules! at { ($event:expr, $generator:expr) => { - (Some($event), Box::new($generator)) + ExecutionContext::TcpEvent($event, Box::new($generator)) }; } macro_rules! now { ($data:expr) => { - (None, Box::new(move |_| $data)) + ExecutionContext::Now(Box::new(move || $data)) }; } +//TODO give me a better name +pub enum ExecutionContext { + TcpEvent(TcpEvent, Box mumlib::error::Result>>), + Now(Box mumlib::error::Result>>), + Ping(Box mumlib::error::Result>, Box mumlib::error::Result>>), +} + #[derive(Clone, Debug, Eq, PartialEq)] pub enum StatePhase { Disconnected, @@ -71,10 +79,7 @@ impl State { pub fn handle_command( &mut self, command: Command, - ) -> ( - Option, - Box) -> mumlib::error::Result>>, - ) { + ) -> ExecutionContext { match command { Command::ChannelJoin { channel_identifier } => { if !matches!(*self.phase_receiver().borrow(), StatePhase::Connected) { @@ -128,7 +133,7 @@ impl State { } Command::ChannelList => { if !matches!(*self.phase_receiver().borrow(), StatePhase::Connected) { - return (None, Box::new(|_| Err(Error::DisconnectedError))); + return now!(Err(Error::DisconnectedError)); } let list = channel::into_channel( self.server.as_ref().unwrap().channels(), @@ -173,7 +178,7 @@ impl State { .unwrap(); at!(TcpEvent::Connected, |e| { //runs the closure when the client is connected - if let Some(TcpEventData::Connected(msg)) = e { + if let TcpEventData::Connected(msg) = e { Ok(Some(CommandResponse::ServerConnect { welcome_message: if msg.has_welcome_text() { Some(msg.get_welcome_text().to_string()) @@ -217,6 +222,21 @@ impl State { self.reload_config(); now!(Ok(None)) } + Command::ServerStatus { host, port } => { + ExecutionContext::Ping(Box::new(move || { + match (host.as_str(), port).to_socket_addrs().map(|mut e| e.next()) { + Ok(Some(v)) => Ok(v), + _ => Err(mumlib::error::Error::InvalidServerAddrError(host, port)), + } + }), Box::new(move |pong| { + Ok(Some(CommandResponse::ServerStatus { + version: pong.version, + users: pong.users, + max_users: pong.max_users, + bandwidth: pong.bandwidth, + })) + })) + } } } @@ -229,9 +249,9 @@ impl State { // check if this is initial state if !self.server().unwrap().users().contains_key(&session) { self.parse_initial_user_state(session, msg); - return None; + None } else { - return Some(self.parse_updated_user_state(session, msg)); + Some(self.parse_updated_user_state(session, msg)) } } diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs index e404056..26071ac 100644 --- a/mumlib/src/command.rs +++ b/mumlib/src/command.rs @@ -18,6 +18,10 @@ pub enum Command { }, ServerDisconnect, Status, + ServerStatus { + host: String, + port: u16, + }, } #[derive(Debug, Deserialize, Serialize)] @@ -25,4 +29,10 @@ pub enum CommandResponse { ChannelList { channels: Channel }, ServerConnect { welcome_message: Option }, Status { server_state: Server }, + ServerStatus { + version: u32, + users: u32, + max_users: u32, + bandwidth: u32, + }, } diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index e6b97fd..e7d107a 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -4,6 +4,8 @@ use std::fs; use std::path::Path; use toml::value::Array; use toml::Value; +use std::net::{SocketAddr, ToSocketAddrs}; +use crate::DEFAULT_PORT; #[derive(Debug, Deserialize, Serialize)] struct TOMLConfig { @@ -58,6 +60,15 @@ pub struct ServerConfig { pub password: Option, } +impl ServerConfig { + pub fn to_socket_addr(&self) -> Option { + match (self.host.as_str(), self.port.unwrap_or(DEFAULT_PORT)).to_socket_addrs().map(|mut e| e.next()) { + Ok(Some(addr)) => Some(addr), + _ => None, + } + } +} + pub fn get_cfg_path() -> String { if let Ok(var) = std::env::var("XDG_CONFIG_HOME") { let path = format!("{}/mumdrc", var); diff --git a/mumlib/src/lib.rs b/mumlib/src/lib.rs index a54990e..439efa9 100644 --- a/mumlib/src/lib.rs +++ b/mumlib/src/lib.rs @@ -7,6 +7,7 @@ use colored::*; use log::*; pub const SOCKET_PATH: &str = "/var/tmp/mumd"; +pub const DEFAULT_PORT: u16 = 64738; pub fn setup_logger>(target: T, color: bool) { fern::Dispatch::new() -- cgit v1.2.1 From d72b0fe5862a99d9ce1a0ef37938f4517de36ed7 Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Sat, 31 Oct 2020 02:37:24 +0100 Subject: cargo fmt --- mumctl/src/main.rs | 15 +++++---------- mumd/src/command.rs | 18 +++++++++++------- mumd/src/main.rs | 4 +--- mumd/src/network/udp.rs | 16 ++++++++++------ mumd/src/state.rs | 35 +++++++++++++++++++++-------------- mumlib/src/command.rs | 12 +++++++++--- mumlib/src/config.rs | 9 ++++++--- 7 files changed, 63 insertions(+), 46 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 18967db..50ccfe0 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -23,11 +23,6 @@ fn main() { setup_logger(io::stderr(), true); let mut config = config::read_default_cfg(); - /*println!("{:?}", send_command(Command::ServerStatus { - host: "icahasse.se".to_string(), - port: 64738, - }).unwrap());*/ - let mut app = App::new("mumctl") .setting(AppSettings::ArgRequiredElseHelp) .subcommand( @@ -125,10 +120,7 @@ fn main() { } else if let Some(_) = matches.subcommand_matches("list") { let servers = config .as_ref() - .map(|e| e.servers - .as_ref() - .map(|e| e.clone()) - .unwrap_or(Vec::new())) + .map(|e| e.servers.as_ref().map(|e| e.clone()).unwrap_or(Vec::new())) .unwrap_or(Vec::new()); for (server, response) in servers .into_iter() @@ -142,7 +134,10 @@ fn main() { .filter(|e| e.1.is_ok()) .map(|e| (e.0, e.1.unwrap().unwrap())) { - if let CommandResponse::ServerStatus { users, max_users, .. } = response { + if let CommandResponse::ServerStatus { + users, max_users, .. + } = response + { println!("{} [{}/{}]", server.name, users, max_users) } else { unreachable!() diff --git a/mumd/src/command.rs b/mumd/src/command.rs index ff53dc7..330e3fc 100644 --- a/mumd/src/command.rs +++ b/mumd/src/command.rs @@ -1,13 +1,13 @@ -use crate::state::{State, ExecutionContext}; +use crate::state::{ExecutionContext, State}; use crate::network::tcp::{TcpEvent, TcpEventCallback}; use ipc_channel::ipc::IpcSender; use log::*; +use mumble_protocol::ping::PongPacket; use mumlib::command::{Command, CommandResponse}; +use std::net::SocketAddr; use std::sync::{Arc, Mutex}; use tokio::sync::{mpsc, oneshot}; -use mumble_protocol::ping::PongPacket; -use std::net::SocketAddr; pub async fn handle( state: Arc>, @@ -45,13 +45,17 @@ pub async fn handle( ExecutionContext::Ping(generator, converter) => { match generator() { Ok(addr) => { - let res = ping_request_sender.send((0, addr, Box::new(move |packet| { - response_sender.send(converter(packet)).unwrap(); - }))); + let res = ping_request_sender.send(( + 0, + addr, + Box::new(move |packet| { + response_sender.send(converter(packet)).unwrap(); + }), + )); if res.is_err() { panic!(); } - }, + } Err(e) => { response_sender.send(Err(e)).unwrap(); } diff --git a/mumd/src/main.rs b/mumd/src/main.rs index 70cc21b..b83299f 100644 --- a/mumd/src/main.rs +++ b/mumd/src/main.rs @@ -64,9 +64,7 @@ async fn main() { // IpcSender is blocking receive_oneshot_commands(command_sender); }), - network::udp::handle_pings( - ping_request_receiver - ), + network::udp::handle_pings(ping_request_receiver), ); e.unwrap(); } diff --git a/mumd/src/network/udp.rs b/mumd/src/network/udp.rs index febf7f1..f97807d 100644 --- a/mumd/src/network/udp.rs +++ b/mumd/src/network/udp.rs @@ -6,17 +6,17 @@ use bytes::Bytes; use futures::{join, pin_mut, select, FutureExt, SinkExt, StreamExt}; use futures_util::stream::{SplitSink, SplitStream}; use mumble_protocol::crypt::ClientCryptState; +use mumble_protocol::ping::{PingPacket, PongPacket}; use mumble_protocol::voice::{VoicePacket, VoicePacketPayload}; use mumble_protocol::Serverbound; +use std::collections::HashMap; +use std::convert::TryFrom; use std::net::{Ipv6Addr, SocketAddr}; +use std::rc::Rc; use std::sync::{Arc, Mutex}; use tokio::net::UdpSocket; use tokio::sync::{mpsc, oneshot, watch}; use tokio_util::udp::UdpFramed; -use std::collections::HashMap; -use mumble_protocol::ping::{PingPacket, PongPacket}; -use std::rc::Rc; -use std::convert::TryFrom; type UdpSender = SplitSink, (VoicePacket, SocketAddr)>; type UdpReceiver = SplitStream>; @@ -231,7 +231,11 @@ async fn send_voice( } pub async fn handle_pings( - mut ping_request_receiver: mpsc::UnboundedReceiver<(u64, SocketAddr, Box)>, + mut ping_request_receiver: mpsc::UnboundedReceiver<( + u64, + SocketAddr, + Box, + )>, ) { let udp_socket = UdpSocket::bind((Ipv6Addr::from(0u128), 0u16)) .await @@ -269,4 +273,4 @@ pub async fn handle_pings( debug!("Waiting for ping requests"); join!(sender_handle, receiver_handle); -} \ No newline at end of file +} diff --git a/mumd/src/state.rs b/mumd/src/state.rs index 0d0fad8..306ded8 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -11,14 +11,14 @@ use crate::network::tcp::{TcpEvent, TcpEventData}; use log::*; use mumble_protocol::control::msgs; use mumble_protocol::control::ControlPacket; +use mumble_protocol::ping::PongPacket; use mumble_protocol::voice::Serverbound; use mumlib::command::{Command, CommandResponse}; use mumlib::config::Config; use mumlib::error::{ChannelIdentifierError, Error}; use mumlib::state::UserDiff; -use std::net::{ToSocketAddrs, SocketAddr}; +use std::net::{SocketAddr, ToSocketAddrs}; use tokio::sync::{mpsc, watch}; -use mumble_protocol::ping::PongPacket; macro_rules! at { ($event:expr, $generator:expr) => { @@ -34,9 +34,15 @@ macro_rules! now { //TODO give me a better name pub enum ExecutionContext { - TcpEvent(TcpEvent, Box mumlib::error::Result>>), + TcpEvent( + TcpEvent, + Box mumlib::error::Result>>, + ), Now(Box mumlib::error::Result>>), - Ping(Box mumlib::error::Result>, Box mumlib::error::Result>>), + Ping( + Box mumlib::error::Result>, + Box mumlib::error::Result>>, + ), } #[derive(Clone, Debug, Eq, PartialEq)] @@ -76,10 +82,7 @@ impl State { } //TODO? move bool inside Result - pub fn handle_command( - &mut self, - command: Command, - ) -> ExecutionContext { + pub fn handle_command(&mut self, command: Command) -> ExecutionContext { match command { Command::ChannelJoin { channel_identifier } => { if !matches!(*self.phase_receiver().borrow(), StatePhase::Connected) { @@ -222,21 +225,25 @@ impl State { self.reload_config(); now!(Ok(None)) } - Command::ServerStatus { host, port } => { - ExecutionContext::Ping(Box::new(move || { - match (host.as_str(), port).to_socket_addrs().map(|mut e| e.next()) { + Command::ServerStatus { host, port } => ExecutionContext::Ping( + Box::new(move || { + match (host.as_str(), port) + .to_socket_addrs() + .map(|mut e| e.next()) + { Ok(Some(v)) => Ok(v), _ => Err(mumlib::error::Error::InvalidServerAddrError(host, port)), } - }), Box::new(move |pong| { + }), + Box::new(move |pong| { Ok(Some(CommandResponse::ServerStatus { version: pong.version, users: pong.users, max_users: pong.max_users, bandwidth: pong.bandwidth, })) - })) - } + }), + ), } } diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs index 26071ac..9b0c9ed 100644 --- a/mumlib/src/command.rs +++ b/mumlib/src/command.rs @@ -26,9 +26,15 @@ pub enum Command { #[derive(Debug, Deserialize, Serialize)] pub enum CommandResponse { - ChannelList { channels: Channel }, - ServerConnect { welcome_message: Option }, - Status { server_state: Server }, + ChannelList { + channels: Channel, + }, + ServerConnect { + welcome_message: Option, + }, + Status { + server_state: Server, + }, ServerStatus { version: u32, users: u32, diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index e7d107a..ae569aa 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -1,11 +1,11 @@ +use crate::DEFAULT_PORT; use serde::{Deserialize, Serialize}; use std::convert::TryFrom; use std::fs; +use std::net::{SocketAddr, ToSocketAddrs}; use std::path::Path; use toml::value::Array; use toml::Value; -use std::net::{SocketAddr, ToSocketAddrs}; -use crate::DEFAULT_PORT; #[derive(Debug, Deserialize, Serialize)] struct TOMLConfig { @@ -62,7 +62,10 @@ pub struct ServerConfig { impl ServerConfig { pub fn to_socket_addr(&self) -> Option { - match (self.host.as_str(), self.port.unwrap_or(DEFAULT_PORT)).to_socket_addrs().map(|mut e| e.next()) { + match (self.host.as_str(), self.port.unwrap_or(DEFAULT_PORT)) + .to_socket_addrs() + .map(|mut e| e.next()) + { Ok(Some(addr)) => Some(addr), _ => None, } -- cgit v1.2.1 From 46861ce465d6f1d86e80007742a850fd1cfa9bad Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Mon, 2 Nov 2020 20:31:50 +0100 Subject: add mumd support for volume adjustment --- mumd/src/audio.rs | 41 +++++++++++++++++++++++++++++++++++------ mumd/src/audio/output.rs | 10 ++++++++-- mumd/src/state.rs | 27 +++++++++++++++++++++++++-- mumlib/src/command.rs | 2 ++ mumlib/src/error.rs | 6 +++--- 5 files changed, 73 insertions(+), 13 deletions(-) diff --git a/mumd/src/audio.rs b/mumd/src/audio.rs index ad4a762..9f837f7 100644 --- a/mumd/src/audio.rs +++ b/mumd/src/audio.rs @@ -19,6 +19,10 @@ pub struct Audio { input_channel_receiver: Option>, input_volume_sender: watch::Sender, + output_volume_sender: watch::Sender, + + user_volumes: Arc>>, + client_streams: Arc>>, } @@ -65,21 +69,36 @@ impl Audio { let err_fn = |err| error!("An error occurred on the output audio stream: {}", err); + let user_volumes = Arc::new(Mutex::new(HashMap::new())); + let (output_volume_sender, output_volume_receiver) = watch::channel::(1.0); + let client_streams = Arc::new(Mutex::new(HashMap::new())); let output_stream = match output_supported_sample_format { SampleFormat::F32 => output_device.build_output_stream( &output_config, - output::curry_callback::(Arc::clone(&client_streams)), + output::curry_callback::( + Arc::clone(&client_streams), + output_volume_receiver, + Arc::clone(&user_volumes), + ), err_fn, ), SampleFormat::I16 => output_device.build_output_stream( &output_config, - output::curry_callback::(Arc::clone(&client_streams)), + output::curry_callback::( + Arc::clone(&client_streams), + output_volume_receiver, + Arc::clone(&user_volumes), + ), err_fn, ), SampleFormat::U16 => output_device.build_output_stream( &output_config, - output::curry_callback::(Arc::clone(&client_streams)), + output::curry_callback::( + Arc::clone(&client_streams), + output_volume_receiver, + Arc::clone(&user_volumes), + ), err_fn, ), } @@ -109,7 +128,7 @@ impl Audio { input_encoder, input_sender, input_config.sample_rate.0, - input_volume_receiver.clone(), + input_volume_receiver, 4, // 10 ms ), err_fn, @@ -120,7 +139,7 @@ impl Audio { input_encoder, input_sender, input_config.sample_rate.0, - input_volume_receiver.clone(), + input_volume_receiver, 4, // 10 ms ), err_fn, @@ -131,7 +150,7 @@ impl Audio { input_encoder, input_sender, input_config.sample_rate.0, - input_volume_receiver.clone(), + input_volume_receiver, 4, // 10 ms ), err_fn, @@ -148,6 +167,8 @@ impl Audio { input_volume_sender, input_channel_receiver: Some(input_receiver), client_streams, + output_volume_sender, + user_volumes, } } @@ -203,4 +224,12 @@ impl Audio { pub fn set_input_volume(&self, input_volume: f32) { self.input_volume_sender.broadcast(input_volume).unwrap(); } + + pub fn set_output_volume(&self, output_volume: f32) { + self.output_volume_sender.broadcast(output_volume).unwrap(); + } + + pub fn set_user_volume(&self, id: u32, volume: f32) { + self.user_volumes.lock().unwrap().insert(id, volume); + } } diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs index 94e4b21..78dba02 100644 --- a/mumd/src/audio/output.rs +++ b/mumd/src/audio/output.rs @@ -4,6 +4,7 @@ use opus::Channels; use std::collections::{HashMap, VecDeque}; use std::ops::AddAssign; use std::sync::{Arc, Mutex}; +use tokio::sync::watch; pub struct ClientStream { buffer: VecDeque, //TODO ring buffer? @@ -72,17 +73,22 @@ impl SaturatingAdd for u16 { pub fn curry_callback( buf: Arc>>, + output_volume_receiver: watch::Receiver, + user_volumes: Arc>> ) -> impl FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static { move |data: &mut [T], _info: &OutputCallbackInfo| { for sample in data.iter_mut() { *sample = Sample::from(&0.0); } + let volume = *output_volume_receiver.borrow(); + let mut lock = buf.lock().unwrap(); - for client_stream in lock.values_mut() { + for (id, client_stream) in &mut *lock { + let user_volume = user_volumes.lock().unwrap().get(id).cloned().unwrap_or(1.0); for sample in data.iter_mut() { *sample = sample.saturating_add(Sample::from( - &client_stream.buffer.pop_front().unwrap_or(0.0), + &(client_stream.buffer.pop_front().unwrap_or(0.0) * volume * user_volume), )); } } diff --git a/mumd/src/state.rs b/mumd/src/state.rs index 81b6c98..2060845 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -209,12 +209,35 @@ impl State { .unwrap(); now!(Ok(None)) } + Command::ConfigReload => { + self.reload_config(); + now!(Ok(None)) + } Command::InputVolumeSet(volume) => { self.audio.set_input_volume(volume); now!(Ok(None)) } - Command::ConfigReload => { - self.reload_config(); + Command::OutputVolumeSet(volume) => { + self.audio.set_output_volume(volume); + now!(Ok(None)) + } + Command::UserVolumeSet(string, volume) => { + if !matches!(*self.phase_receiver().borrow(), StatePhase::Connected) { + return now!(Err(Error::DisconnectedError)); + } + let user_id = match self + .server() + .unwrap() + .users() + .iter() + .find(|e| e.1.name() == &string) + .map(|e| *e.0) + { + None => return now!(Err(Error::InvalidUsernameError(string))), + Some(v) => v, + }; + + self.audio.set_user_volume(user_id, volume); now!(Ok(None)) } } diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs index e404056..d2d5d53 100644 --- a/mumlib/src/command.rs +++ b/mumlib/src/command.rs @@ -10,6 +10,8 @@ pub enum Command { ChannelList, ConfigReload, InputVolumeSet(f32), + OutputVolumeSet(f32), + UserVolumeSet(String, f32), ServerConnect { host: String, port: u16, diff --git a/mumlib/src/error.rs b/mumlib/src/error.rs index c6d9255..eaf517c 100644 --- a/mumlib/src/error.rs +++ b/mumlib/src/error.rs @@ -10,6 +10,7 @@ pub enum Error { AlreadyConnectedError, ChannelIdentifierError(String, ChannelIdentifierError), InvalidServerAddrError(String, u16), + InvalidUsernameError(String), } impl Display for Error { @@ -18,9 +19,8 @@ impl Display for Error { Error::DisconnectedError => write!(f, "Not connected to a server"), Error::AlreadyConnectedError => write!(f, "Already connected to a server"), Error::ChannelIdentifierError(id, kind) => write!(f, "{}: {}", kind, id), - Error::InvalidServerAddrError(addr, port) => { - write!(f, "Invalid server address: {}: {}", addr, port) - } + Error::InvalidServerAddrError(addr, port) => write!(f, "Invalid server address: {}: {}", addr, port), + Error::InvalidUsernameError(username) => write!(f, "Invalid username: {}", username), } } } -- cgit v1.2.1 From 0cb39d13bba3dc5ffa3231e6021066e4191a43a4 Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Mon, 2 Nov 2020 21:47:47 +0100 Subject: refactor and add audio out config command --- mumctl/src/main.rs | 109 ++++++++++++++++++++------------------------------- mumd/src/state.rs | 18 ++++----- mumlib/src/config.rs | 31 ++++++++------- 3 files changed, 65 insertions(+), 93 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 9471b6a..162616c 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -150,6 +150,13 @@ fn main() { "audio.input_volume" => { if let Ok(volume) = value.parse() { send_command(Command::InputVolumeSet(volume)).unwrap(); + config.audio.input_volume = Some(volume); + } + } + "audio.output_volume" => { + if let Ok(volume) = value.parse() { + send_command(Command::InputVolumeSet(volume)).unwrap(); + config.audio.output_volume = Some(volume); } } _ => { @@ -171,27 +178,25 @@ fn main() { return; }; - if let Some(config) = config { - 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(); - } - _ => {} + 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(); + _ => {} } + } else { + config.write_default_cfg(false).unwrap(); } } -fn match_server_connect(matches: &clap::ArgMatches<'_>, config: &Option) { +fn match_server_connect(matches: &clap::ArgMatches<'_>, config: &mumlib::config::Config) { let host = matches.value_of("host").unwrap(); let username = matches.value_of("username"); let port = match matches.value_of("port").map(|e| e.parse()) { @@ -200,41 +205,35 @@ fn match_server_connect(matches: &clap::ArgMatches<'_>, config: &Option Some(v), }; if let Some(port) = port { - 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); + let (host, port, username) = match config.servers + .as_ref() + .and_then(|e| e.iter() + .find(|e| e.name == host)) + { + Some(server_config) => { + let host = server_config.host.as_str(); + let port = server_config.port.unwrap_or(port); + let username = server_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)) + (host, port, username.unwrap()) } 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)) + (host, port, username.unwrap()) } }; + let response = send_command(Command::ServerConnect { + host: host.to_string(), + port, + username: username.to_string(), + accept_invalid_cert: true, //TODO + }).map(|e| (e, host)); match response { Ok((e, host)) => { if let Some(CommandResponse::ServerConnect { welcome_message }) = e { @@ -253,14 +252,8 @@ fn match_server_connect(matches: &clap::ArgMatches<'_>, config: &Option, - config: &mut Option, + config: &mut 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); @@ -365,14 +358,8 @@ fn match_server_config( fn match_server_rename( matches: &clap::ArgMatches<'_>, - config: &mut Option, + config: &mut 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(); @@ -386,14 +373,8 @@ fn match_server_rename( fn match_server_remove( matches: &clap::ArgMatches<'_>, - config: &mut Option, + config: &mut 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) { @@ -409,13 +390,7 @@ fn match_server_remove( } } -fn match_server_add(matches: &clap::ArgMatches<'_>, config: &mut Option) { - if config.is_none() { - *config = Some(mumlib::config::Config::default()); - } - - let mut config = config.as_mut().unwrap(); - +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 diff --git a/mumd/src/state.rs b/mumd/src/state.rs index 2060845..4d8c139 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -39,7 +39,7 @@ pub enum StatePhase { } pub struct State { - config: Option, + config: Config, server: Option, audio: Audio, @@ -375,16 +375,12 @@ impl State { } pub fn reload_config(&mut self) { - 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"); + self.config = mumlib::config::read_default_cfg(); + if let Some(input_volume) = self.config.audio.input_volume { + self.audio.set_input_volume(input_volume); + } + if let Some(output_volume) = self.config.audio.output_volume { + self.audio.set_output_volume(output_volume); } } diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index e6b97fd..a971b2d 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -13,7 +13,7 @@ struct TOMLConfig { #[derive(Clone, Debug, Default)] pub struct Config { - pub audio: Option, + pub audio: AudioConfig, pub servers: Option>, } @@ -44,9 +44,10 @@ impl Config { } } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct AudioConfig { pub input_volume: Option, + pub output_volume: Option, } #[derive(Clone, Debug, Deserialize, Serialize)] @@ -113,7 +114,7 @@ impl TryFrom for Config { fn try_from(config: TOMLConfig) -> Result { Ok(Config { - audio: config.audio, + audio: config.audio.unwrap_or_default(), servers: config .servers .map(|servers| { @@ -130,7 +131,11 @@ impl TryFrom for Config { impl From for TOMLConfig { fn from(config: Config) -> Self { TOMLConfig { - audio: config.audio, + audio: if config.audio.output_volume.is_some() || config.audio.input_volume.is_some() { + Some(config.audio) + } else { + None + }, servers: config.servers.map(|servers| { servers .into_iter() @@ -141,15 +146,11 @@ impl From for TOMLConfig { } } -pub fn read_default_cfg() -> Option { - Some( - Config::try_from( - toml::from_str::(&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 +pub fn read_default_cfg() -> Config { + Config::try_from( + toml::from_str::(&match fs::read_to_string(get_cfg_path()) { + Ok(f) => f, + Err(_) => return Config::default(), + }).expect("invalid TOML in config file"), //TODO + ).expect("invalid config in TOML") //TODO } -- cgit v1.2.1 From 96f77c16ba006955acede513c310f95cf8efa5e7 Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Mon, 2 Nov 2020 22:13:59 +0100 Subject: fix minor oopsie --- mumctl/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 162616c..6513d6d 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -155,7 +155,7 @@ fn main() { } "audio.output_volume" => { if let Ok(volume) = value.parse() { - send_command(Command::InputVolumeSet(volume)).unwrap(); + send_command(Command::OutputVolumeSet(volume)).unwrap(); config.audio.output_volume = Some(volume); } } -- cgit v1.2.1 From 00edffbe2aa8a70e69d1a467b441265bc3a0f788 Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Mon, 2 Nov 2020 22:47:21 +0100 Subject: add support for changing volume of individual users --- mumctl/src/main.rs | 24 ++++++++++++++++++++++++ usage.org | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 6513d6d..0054d17 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -99,6 +99,16 @@ fn main() { .arg(Arg::with_name("zsh").long("zsh")) .arg(Arg::with_name("bash").long("bash")) .arg(Arg::with_name("fish").long("fish")), + ) + .subcommand( + SubCommand::with_name("volume") + .subcommand( + SubCommand::with_name("set") + .arg(Arg::with_name("user").required(true)) + .arg(Arg::with_name("volume").required(true)) + ) + .arg(Arg::with_name("user").required(true)) + .setting(AppSettings::SubcommandsNegateReqs) ); let matches = app.clone().get_matches(); @@ -176,6 +186,20 @@ fn main() { &mut io::stdout(), ); return; + } else if let Some(matches) = matches.subcommand_matches("volume") { + if let Some(matches) = matches.subcommand_matches("set") { + let user = matches.value_of("user").unwrap(); + let volume = matches.value_of("volume").unwrap(); + if let Ok(val) = volume.parse() { + err_print!(send_command(Command::UserVolumeSet(user.to_string(), val))) + } else { + println!("{} Invalid volume value: {}", "error:".red(), volume); + } + } else { + let _user = matches.value_of("user").unwrap(); + //TODO implement me + //needs work on mumd to implement + } }; if !config::cfg_exists() { diff --git a/usage.org b/usage.org index 9402f39..ca544be 100644 --- a/usage.org +++ b/usage.org @@ -145,3 +145,9 @@ $ mumctl config audio.input_volume 1.1 $ mumctl config audio.input_volume $ mumctl config audio.input_volume --help #+END_SRC +** TODO volume +#+BEGIN_SRC bash +$ mumctl volume set User1 1.1 +$ mumctl volume User1 +110% +#+END_SRC -- cgit v1.2.1 From 9d60f06ae05c5de08a026c7f9067c1a339bc24be Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Mon, 2 Nov 2020 22:57:52 +0100 Subject: remove redundancy --- mumctl/src/main.rs | 220 ++++++++++++++++++++++++--------------------------- mumlib/src/config.rs | 14 ++-- 2 files changed, 111 insertions(+), 123 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 0054d17..2ceb99c 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -229,10 +229,8 @@ fn match_server_connect(matches: &clap::ArgMatches<'_>, config: &mumlib::config: Some(Ok(v)) => Some(v), }; if let Some(port) = port { - let (host, port, username) = match config.servers - .as_ref() - .and_then(|e| e.iter() - .find(|e| e.name == host)) + let (host, port, username) = match config.servers.iter() + .find(|e| e.name == host) { Some(server_config) => { let host = server_config.host.as_str(); @@ -279,102 +277,97 @@ fn match_server_config( config: &mut mumlib::config::Config, ) { 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) + let server = config.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" => { - println!("{} use mumctl server rename instead!", "error:".red()); + server.name.to_string() } "host" => { - server.host = var_value.to_string(); + server.host.to_string() } "port" => { - server.port = Some(var_value.parse().unwrap()); + server + .port + .map(|s| s.to_string()) + .unwrap_or(format!("{} not set", "error:".red())) } "username" => { - server.username = Some(var_value.to_string()); + server + .username + .as_ref() + .map(|s| s.to_string()) + .unwrap_or(format!("{} not set", "error:".red())) } "password" => { - server.password = Some(var_value.to_string()); //TODO ask stdin if empty + server + .password + .as_ref() + .map(|s| s.to_string()) + .unwrap_or(format!("{} not set", "error:".red())) } _ => { - 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()) - } + 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); + // 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 { - // servers is None - println!("{} no servers found in configuration", "error:".red()); + // server is None + println!("{} server {} not found", "error:".red(), server_name); } } else { - for server in config.servers.iter().flat_map(|e| e.iter()) { + for server in config.servers.iter() { println!("{}", server.name); } } @@ -384,15 +377,15 @@ 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); - } + //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) = config.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( @@ -400,18 +393,15 @@ fn match_server_remove( 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()); - } + //if let Some(servers) = &mut config.servers { + match config.servers.iter().position(|server| server.name == name) { + Some(idx) => { + config.servers.remove(idx); + } + None => { + println!("{} server {} not found", "error:".red(), name); + } + }; } fn match_server_add(matches: &clap::ArgMatches<'_>, config: &mut mumlib::config::Config) { @@ -421,27 +411,27 @@ fn match_server_add(matches: &clap::ArgMatches<'_>, config: &mut mumlib::config: 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, - }); - } + //if let Some(servers) = &mut config.servers { + if config.servers.iter().any(|s| s.name == name) { + println!("{} a server named {} already exists", "error:".red(), name); } else { - config.servers = Some(vec![ServerConfig { + config.servers.push(ServerConfig { name, host, port, username, password, - }]); + }); } + /*} else { + config.servers = vec![ServerConfig { + name, + host, + port, + username, + password, + }]; + }*/ } fn parse_status(server_state: &mumlib::state::Server) { diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index a971b2d..210dc7b 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -14,7 +14,7 @@ struct TOMLConfig { #[derive(Clone, Debug, Default)] pub struct Config { pub audio: AudioConfig, - pub servers: Option>, + pub servers: Vec, } impl Config { @@ -123,7 +123,8 @@ impl TryFrom for Config { .map(|s| s.try_into::()) .collect() }) - .transpose()?, + .transpose()? + .unwrap_or(Vec::new()), }) } } @@ -136,12 +137,9 @@ impl From for TOMLConfig { } else { None }, - servers: config.servers.map(|servers| { - servers - .into_iter() - .map(|s| Value::try_from::(s).unwrap()) - .collect() - }), + servers: Some(config.servers.into_iter() + .map(|s| Value::try_from::(s).unwrap()) + .collect()), } } } -- cgit v1.2.1 From 36b5d69929d15212f5845f42d0239ba50e46a69c Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Mon, 2 Nov 2020 23:01:08 +0100 Subject: cargo fmt --- mumctl/src/main.rs | 32 +++++++++++++------------------- mumd/src/audio/output.rs | 2 +- mumlib/src/config.rs | 16 +++++++++++----- mumlib/src/error.rs | 4 +++- 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 2ceb99c..005e703 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -105,10 +105,10 @@ fn main() { .subcommand( SubCommand::with_name("set") .arg(Arg::with_name("user").required(true)) - .arg(Arg::with_name("volume").required(true)) + .arg(Arg::with_name("volume").required(true)), ) .arg(Arg::with_name("user").required(true)) - .setting(AppSettings::SubcommandsNegateReqs) + .setting(AppSettings::SubcommandsNegateReqs), ); let matches = app.clone().get_matches(); @@ -229,13 +229,15 @@ fn match_server_connect(matches: &clap::ArgMatches<'_>, config: &mumlib::config: Some(Ok(v)) => Some(v), }; if let Some(port) = port { - let (host, port, username) = match config.servers.iter() - .find(|e| e.name == host) - { + let (host, port, username) = match config.servers.iter().find(|e| e.name == host) { Some(server_config) => { let host = server_config.host.as_str(); let port = server_config.port.unwrap_or(port); - let username = server_config.username.as_ref().map(|e| e.as_str()).or(username); + let username = server_config + .username + .as_ref() + .map(|e| e.as_str()) + .or(username); if username.is_none() { println!("{} no username specified", "error:".red()); return; @@ -255,7 +257,8 @@ fn match_server_connect(matches: &clap::ArgMatches<'_>, config: &mumlib::config: port, username: username.to_string(), accept_invalid_cert: true, //TODO - }).map(|e| (e, host)); + }) + .map(|e| (e, host)); match response { Ok((e, host)) => { if let Some(CommandResponse::ServerConnect { welcome_message }) = e { @@ -272,10 +275,7 @@ fn match_server_connect(matches: &clap::ArgMatches<'_>, config: &mumlib::config: } } -fn match_server_config( - matches: &clap::ArgMatches<'_>, - config: &mut mumlib::config::Config, -) { +fn match_server_config(matches: &clap::ArgMatches<'_>, config: &mut mumlib::config::Config) { if let Some(server_name) = matches.value_of("server_name") { let server = config.servers.iter_mut().find(|s| s.name == server_name); if let Some(server) = server { @@ -373,10 +373,7 @@ fn match_server_config( } } -fn match_server_rename( - matches: &clap::ArgMatches<'_>, - config: &mut mumlib::config::Config, -) { +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(); @@ -388,10 +385,7 @@ fn match_server_rename( //} } -fn match_server_remove( - matches: &clap::ArgMatches<'_>, - config: &mut mumlib::config::Config, -) { +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 config.servers.iter().position(|server| server.name == name) { diff --git a/mumd/src/audio/output.rs b/mumd/src/audio/output.rs index 78dba02..56da596 100644 --- a/mumd/src/audio/output.rs +++ b/mumd/src/audio/output.rs @@ -74,7 +74,7 @@ impl SaturatingAdd for u16 { pub fn curry_callback( buf: Arc>>, output_volume_receiver: watch::Receiver, - user_volumes: Arc>> + user_volumes: Arc>>, ) -> impl FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static { move |data: &mut [T], _info: &OutputCallbackInfo| { for sample in data.iter_mut() { diff --git a/mumlib/src/config.rs b/mumlib/src/config.rs index 210dc7b..2eca104 100644 --- a/mumlib/src/config.rs +++ b/mumlib/src/config.rs @@ -137,9 +137,13 @@ impl From for TOMLConfig { } else { None }, - servers: Some(config.servers.into_iter() - .map(|s| Value::try_from::(s).unwrap()) - .collect()), + servers: Some( + config + .servers + .into_iter() + .map(|s| Value::try_from::(s).unwrap()) + .collect(), + ), } } } @@ -149,6 +153,8 @@ pub fn read_default_cfg() -> Config { toml::from_str::(&match fs::read_to_string(get_cfg_path()) { Ok(f) => f, Err(_) => return Config::default(), - }).expect("invalid TOML in config file"), //TODO - ).expect("invalid config in TOML") //TODO + }) + .expect("invalid TOML in config file"), //TODO + ) + .expect("invalid config in TOML") //TODO } diff --git a/mumlib/src/error.rs b/mumlib/src/error.rs index eaf517c..1e79b9c 100644 --- a/mumlib/src/error.rs +++ b/mumlib/src/error.rs @@ -19,7 +19,9 @@ impl Display for Error { Error::DisconnectedError => write!(f, "Not connected to a server"), Error::AlreadyConnectedError => write!(f, "Already connected to a server"), Error::ChannelIdentifierError(id, kind) => write!(f, "{}: {}", kind, id), - Error::InvalidServerAddrError(addr, port) => write!(f, "Invalid server address: {}: {}", addr, port), + Error::InvalidServerAddrError(addr, port) => { + write!(f, "Invalid server address: {}: {}", addr, port) + } Error::InvalidUsernameError(username) => write!(f, "Invalid username: {}", username), } } -- cgit v1.2.1 From 2fc37a27ef0d2705edc16165977e1d7849c4d850 Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Mon, 2 Nov 2020 23:23:49 +0100 Subject: remove commented out code --- mumctl/src/main.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 005e703..340539c 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -405,7 +405,6 @@ fn match_server_add(matches: &clap::ArgMatches<'_>, config: &mut mumlib::config: 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 config.servers.iter().any(|s| s.name == name) { println!("{} a server named {} already exists", "error:".red(), name); } else { @@ -417,15 +416,6 @@ fn match_server_add(matches: &clap::ArgMatches<'_>, config: &mut mumlib::config: password, }); } - /*} else { - config.servers = vec![ServerConfig { - name, - host, - port, - username, - password, - }]; - }*/ } fn parse_status(server_state: &mumlib::state::Server) { -- cgit v1.2.1 From f169a04da325b6467335812a53b315f1ecc8c7ad Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Mon, 2 Nov 2020 23:40:50 +0100 Subject: add warning without config --- mumctl/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 50ccfe0..9d38aa0 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -122,6 +122,9 @@ fn main() { .as_ref() .map(|e| e.servers.as_ref().map(|e| e.clone()).unwrap_or(Vec::new())) .unwrap_or(Vec::new()); + if servers.len() == 0 { + println!("{} No servers in config", "warning:".yellow()); + } for (server, response) in servers .into_iter() .map(|e| { -- cgit v1.2.1 From 972c11fe66c17728981ec57796c78fb70c7bd180 Mon Sep 17 00:00:00 2001 From: Eskil Queseth Date: Mon, 2 Nov 2020 23:43:42 +0100 Subject: remove commented out code --- mumctl/src/main.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs index 340539c..cbad4c6 100644 --- a/mumctl/src/main.rs +++ b/mumctl/src/main.rs @@ -374,7 +374,6 @@ fn match_server_config(matches: &clap::ArgMatches<'_>, config: &mut mumlib::conf } 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) = config.servers.iter_mut().find(|s| s.name == prev_name) { @@ -382,12 +381,10 @@ fn match_server_rename(matches: &clap::ArgMatches<'_>, config: &mut mumlib::conf } 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 config.servers.iter().position(|server| server.name == name) { Some(idx) => { config.servers.remove(idx); -- cgit v1.2.1