aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mumctl/src/main.rs161
-rw-r--r--mumd/src/command.rs5
-rw-r--r--mumd/src/main.rs41
-rw-r--r--mumd/src/state.rs76
-rw-r--r--mumlib/src/command.rs8
-rw-r--r--mumlib/src/error.rs10
-rw-r--r--mumlib/src/lib.rs2
-rw-r--r--mumlib/src/state.rs20
8 files changed, 198 insertions, 125 deletions
diff --git a/mumctl/src/main.rs b/mumctl/src/main.rs
index c73b793..bcb5e71 100644
--- a/mumctl/src/main.rs
+++ b/mumctl/src/main.rs
@@ -1,10 +1,10 @@
use clap::{App, AppSettings, Arg, Shell, SubCommand};
+use colored::Colorize;
use ipc_channel::ipc::{self, IpcSender};
use mumlib::command::{Command, CommandResponse};
use mumlib::setup_logger;
-use std::{fs, io, iter};
-use colored::Colorize;
use mumlib::state::Channel;
+use std::{fs, io, iter};
const INDENTATION: &str = " ";
@@ -21,37 +21,38 @@ fn main() {
let mut app = App::new("mumctl")
.setting(AppSettings::ArgRequiredElseHelp)
- .subcommand(SubCommand::with_name("server")
- .setting(AppSettings::ArgRequiredElseHelp)
- .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)))
- .subcommand(SubCommand::with_name("disconnect")))
- .subcommand(SubCommand::with_name("channel")
- .setting(AppSettings::ArgRequiredElseHelp)
- .subcommand(SubCommand::with_name("list")
- .arg(Arg::with_name("short")
- .short("s")
- .long("short")))
- .subcommand(SubCommand::with_name("connect")
- .arg(Arg::with_name("channel")
- .required(true))))
+ .subcommand(
+ SubCommand::with_name("server")
+ .setting(AppSettings::ArgRequiredElseHelp)
+ .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)),
+ )
+ .subcommand(SubCommand::with_name("disconnect")),
+ )
+ .subcommand(
+ SubCommand::with_name("channel")
+ .setting(AppSettings::ArgRequiredElseHelp)
+ .subcommand(
+ SubCommand::with_name("list")
+ .arg(Arg::with_name("short").short("s").long("short")),
+ )
+ .subcommand(
+ SubCommand::with_name("connect").arg(Arg::with_name("channel").required(true)),
+ ),
+ )
.subcommand(SubCommand::with_name("status"))
- .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")));
+ .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")),
+ );
let matches = app.clone().get_matches();
-
+
if let Some(matches) = matches.subcommand_matches("server") {
if let Some(matches) = matches.subcommand_matches("connect") {
let host = matches.value_of("host").unwrap();
@@ -68,14 +69,12 @@ fn main() {
} else if let Some(matches) = matches.subcommand_matches("channel") {
if let Some(_matches) = matches.subcommand_matches("list") {
match send_command(Command::ChannelList) {
- Ok(res) => {
- match res {
- Some(CommandResponse::ChannelList { channels }) => {
- print_channel(&channels, 0);
- }
- _ => unreachable!(),
+ Ok(res) => match res {
+ Some(CommandResponse::ChannelList { channels }) => {
+ print_channel(&channels, 0);
}
- }
+ _ => unreachable!(),
+ },
Err(e) => println!("{} {}", "error:".red(), e),
}
} else if let Some(matches) = matches.subcommand_matches("connect") {
@@ -85,42 +84,53 @@ fn main() {
}
} else if let Some(_matches) = 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);
+ 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);
}
- _ => unreachable!(),
}
- }
+ _ => unreachable!(),
+ },
Err(e) => println!("{} {}", "error:".red(), e),
}
} else if let Some(matches) = matches.subcommand_matches("completions") {
- app.gen_completions_to("mumctl",
- match matches.value_of("shell").unwrap_or("zsh") {
- "bash" => {
- Shell::Bash
- },
- "fish" => {
- Shell::Fish
- },
- _ => {
- Shell::Zsh
- },
- },
- &mut io::stdout());
- return;
+ app.gen_completions_to(
+ "mumctl",
+ match matches.value_of("shell").unwrap_or("zsh") {
+ "bash" => Shell::Bash,
+ "fish" => Shell::Fish,
+ _ => Shell::Zsh,
+ },
+ &mut io::stdout(),
+ );
+ return;
};
}
fn send_command(command: Command) -> mumlib::error::Result<Option<CommandResponse>> {
- let (tx_client, rx_client) = ipc::channel::<mumlib::error::Result<Option<CommandResponse>>>().unwrap();
+ let (tx_client, rx_client) =
+ ipc::channel::<mumlib::error::Result<Option<CommandResponse>>>().unwrap();
let server_name = fs::read_to_string("/var/tmp/mumd-oneshot").unwrap(); //TODO don't panic
@@ -132,15 +142,26 @@ fn send_command(command: Command) -> mumlib::error::Result<Option<CommandRespons
}
fn print_channel(channel: &Channel, depth: usize) {
- println!("{}{}{}", iter::repeat(INDENTATION).take(depth).collect::<String>(), channel.name.bold(), if channel.max_users != 0 {
- format!(" {}/{}", channel.users.len(), channel.max_users)
- } else {
- "".to_string()
- });
+ println!(
+ "{}{}{}",
+ iter::repeat(INDENTATION).take(depth).collect::<String>(),
+ channel.name.bold(),
+ if channel.max_users != 0 {
+ format!(" {}/{}", channel.users.len(), channel.max_users)
+ } else {
+ "".to_string()
+ }
+ );
for user in &channel.users {
- println!("{}-{}", iter::repeat(INDENTATION).take(depth + 1).collect::<String>(), user);
+ println!(
+ "{}-{}",
+ iter::repeat(INDENTATION)
+ .take(depth + 1)
+ .collect::<String>(),
+ user
+ );
}
for child in &channel.children {
print_channel(child, depth + 1);
}
-} \ No newline at end of file
+}
diff --git a/mumd/src/command.rs b/mumd/src/command.rs
index 57eaaa3..a035a26 100644
--- a/mumd/src/command.rs
+++ b/mumd/src/command.rs
@@ -8,7 +8,10 @@ use tokio::sync::mpsc;
pub async fn handle(
state: Arc<Mutex<State>>,
- mut command_receiver: mpsc::UnboundedReceiver<(Command, IpcSender<mumlib::error::Result<Option<CommandResponse>>>)>,
+ mut command_receiver: mpsc::UnboundedReceiver<(
+ Command,
+ IpcSender<mumlib::error::Result<Option<CommandResponse>>>,
+ )>,
) {
debug!("Begin listening for commands");
while let Some(command) = command_receiver.recv().await {
diff --git a/mumd/src/main.rs b/mumd/src/main.rs
index 3a0d7ec..5ae077a 100644
--- a/mumd/src/main.rs
+++ b/mumd/src/main.rs
@@ -7,7 +7,7 @@ use crate::network::ConnectionInfo;
use crate::state::State;
use futures::join;
-use ipc_channel::ipc::{IpcSender, IpcOneShotServer};
+use ipc_channel::ipc::{IpcOneShotServer, IpcSender};
use log::*;
use mumble_protocol::control::ControlPacket;
use mumble_protocol::crypt::ClientCryptState;
@@ -27,14 +27,14 @@ async fn main() {
// For simplicity we don't deal with re-syncing, real applications would have to.
let (crypt_state_sender, crypt_state_receiver) = mpsc::channel::<ClientCryptState>(1); // crypt state should always be consumed before sending a new one
let (packet_sender, packet_receiver) = mpsc::unbounded_channel::<ControlPacket<Serverbound>>();
- let (command_sender, command_receiver) = mpsc::unbounded_channel::<(Command, IpcSender<mumlib::error::Result<Option<CommandResponse>>>)>();
+ let (command_sender, command_receiver) = mpsc::unbounded_channel::<(
+ Command,
+ IpcSender<mumlib::error::Result<Option<CommandResponse>>>,
+ )>();
let (connection_info_sender, connection_info_receiver) =
watch::channel::<Option<ConnectionInfo>>(None);
- let state = State::new(
- packet_sender,
- connection_info_sender,
- );
+ let state = State::new(packet_sender, connection_info_sender);
let state = Arc::new(Mutex::new(state));
let (_, _, _, e) = join!(
@@ -49,11 +49,9 @@ async fn main() {
connection_info_receiver.clone(),
crypt_state_receiver,
),
- command::handle(
- state,
- command_receiver,
- ),
- spawn_blocking(move || { // IpcSender is blocking
+ command::handle(state, command_receiver,),
+ spawn_blocking(move || {
+ // IpcSender is blocking
receive_oneshot_commands(command_sender);
}),
);
@@ -61,16 +59,31 @@ async fn main() {
}
fn receive_oneshot_commands(
- command_sender: mpsc::UnboundedSender<(Command, IpcSender<mumlib::error::Result<Option<CommandResponse>>>)>,
+ command_sender: mpsc::UnboundedSender<(
+ Command,
+ IpcSender<mumlib::error::Result<Option<CommandResponse>>>,
+ )>,
) {
loop {
// create listener
- let (server, server_name): (IpcOneShotServer<(Command, IpcSender<mumlib::error::Result<Option<CommandResponse>>>)>, String) = IpcOneShotServer::new().unwrap();
+ let (server, server_name): (
+ IpcOneShotServer<(
+ Command,
+ IpcSender<mumlib::error::Result<Option<CommandResponse>>>,
+ )>,
+ String,
+ ) = IpcOneShotServer::new().unwrap();
fs::write("/var/tmp/mumd-oneshot", &server_name).unwrap();
debug!("Listening to {}", server_name);
// receive command and response channel
- let (_, conn): (_, (Command, IpcSender<mumlib::error::Result<Option<CommandResponse>>>)) = server.accept().unwrap();
+ let (_, conn): (
+ _,
+ (
+ Command,
+ IpcSender<mumlib::error::Result<Option<CommandResponse>>>,
+ ),
+ ) = server.accept().unwrap();
debug!("Sending command {:?} to command handler", conn.0);
command_sender.send(conn).unwrap();
}
diff --git a/mumd/src/state.rs b/mumd/src/state.rs
index 2ad88ad..de74a46 100644
--- a/mumd/src/state.rs
+++ b/mumd/src/state.rs
@@ -6,12 +6,12 @@ use mumble_protocol::control::msgs;
use mumble_protocol::control::ControlPacket;
use mumble_protocol::voice::Serverbound;
use mumlib::command::{Command, CommandResponse};
-use std::net::ToSocketAddrs;
-use tokio::sync::{mpsc, watch};
use mumlib::error::Error;
+use serde::{Deserialize, Serialize};
use std::collections::hash_map::Entry;
use std::collections::HashMap;
-use serde::{Serialize, Deserialize};
+use std::net::ToSocketAddrs;
+use tokio::sync::{mpsc, watch};
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum StatePhase {
@@ -69,10 +69,13 @@ impl State {
if !matches!(*self.phase_receiver().borrow(), StatePhase::Connected) {
return (false, Err(Error::DisconnectedError));
}
- (false, Ok(Some(CommandResponse::ChannelList {
+ (
+ false,
+ Ok(Some(CommandResponse::ChannelList {
channels: into_channel(
self.server.as_ref().unwrap().channels(),
- self.server.as_ref().unwrap().users()),
+ self.server.as_ref().unwrap().users(),
+ ),
})),
)
}
@@ -94,7 +97,10 @@ impl State {
.broadcast(StatePhase::Connecting)
.unwrap();
- let socket_addr = match (host.as_ref(), port).to_socket_addrs().map(|mut e| e.next()) {
+ let socket_addr = match (host.as_ref(), port)
+ .to_socket_addrs()
+ .map(|mut e| e.next())
+ {
Ok(Some(v)) => v,
_ => {
warn!("Error parsing server addr");
@@ -214,7 +220,7 @@ impl Server {
welcome_text: None,
username: None,
session_id: None,
- host: None
+ host: None,
}
}
@@ -284,7 +290,7 @@ impl From<&Server> for mumlib::state::Server {
channels: into_channel(server.channels(), server.users()),
welcome_text: server.welcome_text.clone(),
username: server.username.clone().unwrap(),
- host: server.host.as_ref().unwrap().clone()
+ host: server.host.as_ref().unwrap().clone(),
}
}
}
@@ -347,28 +353,36 @@ impl Channel {
struct ProtoTree<'a> {
channel: Option<&'a Channel>,
children: HashMap<u32, ProtoTree<'a>>,
- users: Vec<&'a User>
+ users: Vec<&'a User>,
}
impl<'a> ProtoTree<'a> {
- fn walk_and_add(&mut self, channel: &'a Channel, users: &HashMap<u32, Vec<&'a User>>, walk: &[u32]) {
+ fn walk_and_add(
+ &mut self,
+ channel: &'a Channel,
+ users: &HashMap<u32, Vec<&'a User>>,
+ walk: &[u32],
+ ) {
match walk {
[] => unreachable!("nu gick nĂ¥got snett"),
&[node] => {
let pt = self.children.entry(node).or_insert(ProtoTree {
channel: None,
children: HashMap::new(),
- users: Vec::new()
+ users: Vec::new(),
});
pt.channel = Some(channel);
pt.users = users.get(&node).map(|e| e.clone()).unwrap_or(Vec::new());
}
longer => {
- self.children.entry(longer[0]).or_insert(ProtoTree {
- channel: None,
- children: HashMap::new(),
- users: Vec::new()
- }).walk_and_add(channel, users, &walk[1..]);
+ self.children
+ .entry(longer[0])
+ .or_insert(ProtoTree {
+ channel: None,
+ children: HashMap::new(),
+ users: Vec::new(),
+ })
+ .walk_and_add(channel, users, &walk[1..]);
}
}
}
@@ -377,8 +391,15 @@ impl<'a> ProtoTree<'a> {
impl<'a> From<&ProtoTree<'a>> for mumlib::state::Channel {
fn from(tree: &ProtoTree<'a>) -> Self {
let mut c = mumlib::state::Channel::from(tree.channel.unwrap());
- let mut children = tree.children.iter()
- .map(|e| (e.1.channel.unwrap().position, mumlib::state::Channel::from(e.1)))
+ let mut children = tree
+ .children
+ .iter()
+ .map(|e| {
+ (
+ e.1.channel.unwrap().position,
+ mumlib::state::Channel::from(e.1),
+ )
+ })
.collect::<Vec<_>>();
children.sort_by_key(|e| e.0);
c.children = children.into_iter().map(|e| e.1).collect();
@@ -387,13 +408,19 @@ impl<'a> From<&ProtoTree<'a>> for mumlib::state::Channel {
}
}
-pub fn into_channel(channels: &HashMap<u32, Channel>, users: &HashMap<u32, User>) -> mumlib::state::Channel {
+pub fn into_channel(
+ channels: &HashMap<u32, Channel>,
+ users: &HashMap<u32, User>,
+) -> mumlib::state::Channel {
let mut walks = Vec::new();
let mut channel_lookup = HashMap::new();
for (_, user) in users {
- channel_lookup.entry(user.channel).or_insert(Vec::new()).push(user);
+ channel_lookup
+ .entry(user.channel)
+ .or_insert(Vec::new())
+ .push(user);
}
for (channel_id, channel) in channels {
@@ -413,7 +440,10 @@ pub fn into_channel(channels: &HashMap<u32, Channel>, users: &HashMap<u32, User>
let mut proto_tree = ProtoTree {
channel: Some(channels.get(&0).unwrap()),
children: HashMap::new(),
- users: channel_lookup.get(&0).map(|e| e.clone()).unwrap_or(Vec::new()),
+ users: channel_lookup
+ .get(&0)
+ .map(|e| e.clone())
+ .unwrap_or(Vec::new()),
};
for (walk, channel) in walks {
@@ -431,7 +461,7 @@ impl From<&Channel> for mumlib::state::Channel {
max_users: channel.max_users,
name: channel.name.clone(),
children: Vec::new(),
- users: Vec::new()
+ users: Vec::new(),
}
}
}
@@ -537,4 +567,4 @@ impl From<&User> for mumlib::state::User {
deaf: user.deaf,
}
}
-} \ No newline at end of file
+}
diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs
index a216445..e8f4a4d 100644
--- a/mumlib/src/command.rs
+++ b/mumlib/src/command.rs
@@ -20,10 +20,6 @@ pub enum Command {
#[derive(Debug, Deserialize, Serialize)]
pub enum CommandResponse {
- ChannelList {
- channels: Channel,
- },
- Status {
- server_state: Server,
- },
+ ChannelList { channels: Channel },
+ Status { server_state: Server },
}
diff --git a/mumlib/src/error.rs b/mumlib/src/error.rs
index cb88aa7..9728f32 100644
--- a/mumlib/src/error.rs
+++ b/mumlib/src/error.rs
@@ -1,6 +1,6 @@
-use serde::{Serialize, Deserialize};
-use std::fmt::Display;
use serde::export::Formatter;
+use serde::{Deserialize, Serialize};
+use std::fmt::Display;
pub type Result<T> = std::result::Result<T, Error>;
@@ -18,7 +18,9 @@ impl Display for Error {
Error::DisconnectedError => write!(f, "Not connected to a server"),
Error::AlreadyConnectedError => write!(f, "Already connected to a server"),
Error::InvalidChannelIdError(id) => write!(f, "Invalid channel id: {}", id),
- Error::InvalidServerAddrError(addr, port) => write!(f, "Invalid server address: {}:{}", addr, port),
+ Error::InvalidServerAddrError(addr, port) => {
+ write!(f, "Invalid server address: {}:{}", addr, port)
+ }
}
}
-} \ No newline at end of file
+}
diff --git a/mumlib/src/lib.rs b/mumlib/src/lib.rs
index b77653c..d989a7e 100644
--- a/mumlib/src/lib.rs
+++ b/mumlib/src/lib.rs
@@ -1,6 +1,6 @@
pub mod command;
-pub mod state;
pub mod error;
+pub mod state;
use colored::*;
use log::*;
diff --git a/mumlib/src/state.rs b/mumlib/src/state.rs
index 96598de..b09726e 100644
--- a/mumlib/src/state.rs
+++ b/mumlib/src/state.rs
@@ -1,6 +1,6 @@
+use serde::export::Formatter;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
-use serde::export::Formatter;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Server {
@@ -24,17 +24,25 @@ impl Channel {
pub fn iter(&self) -> Iter<'_> {
Iter {
me: Some(&self),
- channel: if self.children.len() > 0 { Some(0) } else { None },
- channels: self.children.iter().map(|e| e.iter()).collect()
+ channel: if self.children.len() > 0 {
+ Some(0)
+ } else {
+ None
+ },
+ channels: self.children.iter().map(|e| e.iter()).collect(),
}
}
pub fn users_iter(&self) -> UsersIter<'_> {
UsersIter {
channels: self.children.iter().map(|e| e.users_iter()).collect(),
- channel: if self.children.len() > 0 { Some(0) } else { None },
+ channel: if self.children.len() > 0 {
+ Some(0)
+ } else {
+ None
+ },
user: if self.users.len() > 0 { Some(0) } else { None },
- users: &self.users
+ users: &self.users,
}
}
}
@@ -125,4 +133,4 @@ impl Display for User {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
}
-} \ No newline at end of file
+}