diff options
| -rw-r--r-- | Cargo.lock | 105 | ||||
| -rw-r--r-- | mumd/Cargo.toml | 1 | ||||
| -rw-r--r-- | mumd/src/main.rs | 2 | ||||
| -rw-r--r-- | mumd/src/network/tcp.rs | 13 | ||||
| -rw-r--r-- | mumd/src/notify.rs | 19 | ||||
| -rw-r--r-- | mumd/src/state.rs | 113 | ||||
| -rw-r--r-- | mumd/src/state/user.rs | 12 |
7 files changed, 234 insertions, 31 deletions
@@ -420,6 +420,33 @@ dependencies = [ ] [[package]] +name = "gdk-pixbuf" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16160d212ae91abe9f3324c3fb233929ba322dde63585d15cda3336f8c529ed1" +dependencies = [ + "gdk-pixbuf-sys", + "glib", + "glib-sys", + "gobject-sys", + "libc", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "798f97101eea8180da363d0e80e07ec7ec6d1809306601c0100c1de5bc8b4f52" +dependencies = [ + "bitflags", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", +] + +[[package]] name = "getrandom" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -431,12 +458,61 @@ dependencies = [ ] [[package]] +name = "gio-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a303bbf7a5e75ab3b627117ff10e495d1b9e97e1d68966285ac2b1f6270091bc" +dependencies = [ + "bitflags", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", +] + +[[package]] +name = "glib" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b0452824cc63066940f01adc721804919f0b76cdba3cfab977b00b87f16d4a" +dependencies = [ + "bitflags", + "glib-sys", + "gobject-sys", + "lazy_static", + "libc", +] + +[[package]] +name = "glib-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9693049613ff52b93013cc3d2590366d8e530366d288438724b73f6c7dc4be8" +dependencies = [ + "bitflags", + "libc", + "pkg-config", +] + +[[package]] name = "glob" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] +name = "gobject-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60d507c87a71b1143c66ed21a969be9b99a76df234b342d733e787e6c9c7d7c2" +dependencies = [ + "bitflags", + "glib-sys", + "libc", + "pkg-config", +] + +[[package]] name = "hermit-abi" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -520,6 +596,34 @@ dependencies = [ ] [[package]] +name = "libnotify" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10506a4f8bc6f8f7ccc6fde3a8290378d7aed3d1a26dca606a73e2ffe140cc2d" +dependencies = [ + "gdk-pixbuf", + "gdk-pixbuf-sys", + "glib", + "glib-sys", + "gobject-sys", + "libnotify-sys", +] + +[[package]] +name = "libnotify-sys" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a716b9b7d24ed10f1eb431e1527fa13c9a4bf2d4fa68bb3e54da1d0747383c" +dependencies = [ + "bitflags", + "gdk-pixbuf-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", +] + +[[package]] name = "lock_api" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -657,6 +761,7 @@ dependencies = [ "futures", "futures-util", "ipc-channel", + "libnotify", "log", "mumble-protocol", "mumlib", diff --git a/mumd/Cargo.toml b/mumd/Cargo.toml index e27c2a8..350d81e 100644 --- a/mumd/Cargo.toml +++ b/mumd/Cargo.toml @@ -17,6 +17,7 @@ cpal = { git = "https://github.com/RustAudio/cpal" } futures = "0.3" futures-util = "0.3" ipc-channel = "0.14" +libnotify = "1.0" log = "0.4" mumble-protocol = "0.3" native-tls = "0.2" diff --git a/mumd/src/main.rs b/mumd/src/main.rs index e88eede..37ff0dd 100644 --- a/mumd/src/main.rs +++ b/mumd/src/main.rs @@ -1,6 +1,7 @@ mod audio; mod command; mod network; +mod notify; mod state; use crate::network::ConnectionInfo; @@ -22,6 +23,7 @@ use tokio::task::spawn_blocking; #[tokio::main] async fn main() { setup_logger(std::io::stderr(), true); + notify::init(); // Oneshot channel for setting UDP CryptState from control task // For simplicity we don't deal with re-syncing, real applications would have to. diff --git a/mumd/src/network/tcp.rs b/mumd/src/network/tcp.rs index c2cb234..630f46a 100644 --- a/mumd/src/network/tcp.rs +++ b/mumd/src/network/tcp.rs @@ -250,24 +250,15 @@ async fn listen( } ControlPacket::UserState(msg) => { let mut state = state.lock().unwrap(); - let session = msg.get_session(); if *state.phase_receiver().borrow() == StatePhase::Connecting { state.audio_mut().add_client(msg.get_session()); state.parse_user_state(*msg); } else { state.parse_user_state(*msg); } - let server = state.server_mut().unwrap(); - let user = server.users().get(&session).unwrap(); - info!("User {} connected to {}", user.name(), user.channel()); } ControlPacket::UserRemove(msg) => { - info!("User {} left", msg.get_session()); - state - .lock() - .unwrap() - .audio_mut() - .remove_client(msg.get_session()); + state.lock().unwrap().remove_client(*msg); } ControlPacket::ChannelState(msg) => { debug!("Channel state received"); @@ -367,4 +358,4 @@ async fn run_until_disconnection<T, F, G, H>( }; join!(main_block, phase_transition_block); -}
\ No newline at end of file +} diff --git a/mumd/src/notify.rs b/mumd/src/notify.rs new file mode 100644 index 0000000..5bb1a26 --- /dev/null +++ b/mumd/src/notify.rs @@ -0,0 +1,19 @@ +use log::*; + +pub fn init() { + libnotify::init("mumd").unwrap(); +} + +pub fn send(msg: String) -> bool { + match libnotify::Notification::new( + "mumd", + Some(msg.as_str()), + None, + ).show() { + Ok(_) => { true } + Err(_) => { + debug!("Unable to send notification"); + false + } + } +} diff --git a/mumd/src/state.rs b/mumd/src/state.rs index 44d8b21..ea081fc 100644 --- a/mumd/src/state.rs +++ b/mumd/src/state.rs @@ -4,6 +4,7 @@ pub mod user; use crate::audio::Audio; use crate::network::ConnectionInfo; +use crate::notify; use crate::state::server::Server; use log::*; @@ -13,6 +14,7 @@ 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; use tokio::sync::{mpsc, watch}; use crate::network::tcp::{TcpEvent, TcpEventData}; @@ -205,31 +207,106 @@ impl State { } } - pub fn parse_user_state(&mut self, msg: msgs::UserState) -> Option<mumlib::state::UserDiff> { + pub fn parse_user_state(&mut self, msg: msgs::UserState) -> Option<UserDiff> { if !msg.has_session() { warn!("Can't parse user state without session"); return None; } - let sess = msg.get_session(); + let session = msg.get_session(); // check if this is initial state - if !self.server().unwrap().users().contains_key(&sess) { - if !msg.has_name() { - warn!("Missing name in initial user state"); - } else if msg.get_name() == self.server().unwrap().username().unwrap() { - // this is us - *self.server_mut().unwrap().session_id_mut() = Some(sess); - } else { - // this is someone else - self.audio_mut().add_client(sess); + if !self.server().unwrap().users().contains_key(&session) { + self.parse_initial_user_state(session, msg); + return None; + } else { + return Some(self.parse_updated_user_state(session, msg)); + } + } + + fn parse_initial_user_state(&mut self, session: u32, msg: msgs::UserState) { + if !msg.has_name() { + warn!("Missing name in initial user state"); + } else if msg.get_name() == self.server().unwrap().username().unwrap() { + // this is us + *self.server_mut().unwrap().session_id_mut() = Some(session); + } else { + // this is someone else + self.audio_mut().add_client(session); + + // send notification only if we've passed the connecting phase + if *self.phase_receiver().borrow() == StatePhase::Connected { + let channel_id = if msg.has_channel_id() { + msg.get_channel_id() + } else { + 0 + }; + if let Some(channel) = self.server().unwrap().channels().get(&channel_id) { + notify::send(format!("{} connected and joined {}", &msg.get_name(), channel.name())); + } } - self.server_mut().unwrap().users_mut().insert(sess, user::User::new(msg)); + } + self.server_mut().unwrap().users_mut().insert(session, user::User::new(msg)); + } + + fn parse_updated_user_state(&mut self, session: u32, msg: msgs::UserState) -> UserDiff { + let user = self.server_mut().unwrap().users_mut().get_mut(&session).unwrap(); + + let mute = if msg.has_self_mute() && user.self_mute() != msg.get_self_mute() { + Some(msg.get_self_mute()) + } else { None + }; + let deaf = if msg.has_self_deaf() && user.self_deaf() != msg.get_self_deaf() { + Some(msg.get_self_deaf()) } else { - let user = self.server_mut().unwrap().users_mut().get_mut(&sess).unwrap(); - let diff = mumlib::state::UserDiff::from(msg); - user.apply_user_diff(&diff); - Some(diff) + None + }; + + let diff = UserDiff::from(msg); + user.apply_user_diff(&diff); + let user = self.server().unwrap().users().get(&session).unwrap(); + + // send notification if the user moved to or from any channel + //TODO our channel only + if let Some(channel_id) = diff.channel_id { + if let Some(channel) = self.server().unwrap().channels().get(&channel_id) { + notify::send(format!( + "{} moved to channel {}", + &user.name(), + channel.name())); + } else { + warn!("{} moved to invalid channel {}", &user.name(), channel_id); + } } + + // send notification if a user muted/unmuted + //TODO our channel only + let notif_desc = + if let Some(deaf) = deaf { + if deaf { + Some(format!("{} muted and deafend themselves", &user.name())) + } else if !deaf { + Some(format!("{} unmuted and undeafend themselves", &user.name())) + } else { + warn!("Invalid user state received"); + None + } + } else if let Some(mute) = mute { + if mute { + Some(format!("{} muted themselves", &user.name())) + } else if !mute { + Some(format!("{} unmuted themselves", &user.name())) + } else { + warn!("Invalid user state received"); + None + } + } else { + None + }; + if let Some(notif_desc) = notif_desc { + notify::send(notif_desc); + } + + diff } pub fn remove_client(&mut self, msg: msgs::UserRemove) { @@ -237,6 +314,10 @@ impl State { warn!("Tried to remove user state without session"); return; } + if let Some(user) = self.server().unwrap().users().get(&msg.get_session()) { + notify::send(format!("{} disconnected", &user.name())); + } + self.audio().remove_client(msg.get_session()); self.server_mut().unwrap().users_mut().remove(&msg.get_session()); info!("User {} disconnected", msg.get_session()); diff --git a/mumd/src/state/user.rs b/mumd/src/state/user.rs index 679d0ff..848208c 100644 --- a/mumd/src/state/user.rs +++ b/mumd/src/state/user.rs @@ -1,4 +1,3 @@ -use log::*; use mumble_protocol::control::msgs; use serde::{Deserialize, Serialize}; @@ -80,7 +79,6 @@ impl User { } pub fn apply_user_diff(&mut self, diff: &mumlib::state::UserDiff) { - debug!("applying user diff\n{:#?}", diff); if let Some(comment) = diff.comment.clone() { self.comment = Some(comment); } @@ -111,13 +109,11 @@ impl User { if let Some(deaf) = diff.deaf { self.deaf = deaf; } - if let Some(channel_id) = diff.channel_id { self.channel = channel_id; } } - pub fn name(&self) -> &str { &self.name } @@ -125,6 +121,14 @@ impl User { pub fn channel(&self) -> u32 { self.channel } + + pub fn self_mute(&self) -> bool { + self.self_mute + } + + pub fn self_deaf(&self) -> bool { + self.self_deaf + } } impl From<&User> for mumlib::state::User { |
