aboutsummaryrefslogtreecommitdiffstats
path: root/mumd/src/state.rs
diff options
context:
space:
mode:
Diffstat (limited to 'mumd/src/state.rs')
-rw-r--r--mumd/src/state.rs205
1 files changed, 130 insertions, 75 deletions
diff --git a/mumd/src/state.rs b/mumd/src/state.rs
index d93181a..d2d77b1 100644
--- a/mumd/src/state.rs
+++ b/mumd/src/state.rs
@@ -8,14 +8,15 @@ use crate::network::tcp::{TcpEvent, TcpEventData};
use crate::network::{ConnectionInfo, VoiceStreamType};
use crate::notifications;
use crate::state::server::Server;
-
use crate::state::user::UserDiff;
+
+use chrono::NaiveDateTime;
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, MessageTarget};
+use mumlib::command::{ChannelTarget, Command, CommandResponse, MessageTarget, MumbleEvent, MumbleEventKind};
use mumlib::config::Config;
use mumlib::Error;
use std::{
@@ -74,9 +75,11 @@ pub struct State {
server: Option<Server>,
audio_input: AudioInput,
audio_output: AudioOutput,
- message_buffer: Vec<(String, u32)>,
+ message_buffer: Vec<(NaiveDateTime, String, u32)>,
phase_watcher: (watch::Sender<StatePhase>, watch::Receiver<StatePhase>),
+
+ events: Vec<MumbleEvent>,
}
impl State {
@@ -97,6 +100,7 @@ impl State {
audio_output,
message_buffer: Vec::new(),
phase_watcher,
+ events: Vec::new(),
};
state.reload_config();
Ok(state)
@@ -131,21 +135,25 @@ impl State {
// this is someone else
// send notification only if we've passed the connecting phase
if matches!(*self.phase_receiver().borrow(), StatePhase::Connected(_)) {
- let channel_id = msg.get_channel_id();
-
- if channel_id
- == self.get_users_channel(self.server().unwrap().session_id().unwrap())
- {
- if let Some(channel) = self.server().unwrap().channels().get(&channel_id) {
- notifications::send(format!(
- "{} connected and joined {}",
- &msg.get_name(),
- channel.name()
- ));
- }
-
- self.audio_output
- .play_effect(NotificationEvents::UserConnected);
+ let this_channel = msg.get_channel_id();
+ let other_channel = self.get_users_channel(self.server().unwrap().session_id().unwrap());
+ let this_channel_name = self
+ .server()
+ .unwrap()
+ .channels()
+ .get(&this_channel)
+ .map(|c| c.name())
+ .unwrap_or("<unnamed channel>")
+ .to_string();
+
+ if this_channel == other_channel {
+ notifications::send(format!(
+ "{} connected and joined {}",
+ msg.get_name(),
+ this_channel_name,
+ ));
+ self.push_event(MumbleEventKind::UserConnected(msg.get_name().to_string(), this_channel_name));
+ self.audio_output.play_effect(NotificationEvents::UserConnected);
}
}
}
@@ -167,6 +175,7 @@ impl State {
.users_mut()
.get_mut(&session)
.unwrap();
+ let username = user.name().to_string();
let mute = if msg.has_self_mute() && user.self_mute() != msg.get_self_mute() {
Some(msg.get_self_mute())
@@ -182,35 +191,43 @@ impl State {
let diff = UserDiff::from(msg);
user.apply_user_diff(&diff);
- let user = self.server().unwrap().users().get(&session).unwrap();
if Some(session) != self.server().unwrap().session_id() {
- //send notification if the user moved to or from any channel
+ // Send notification if the user moved either to or from our channel
if let Some(to_channel) = diff.channel_id {
let this_channel =
self.get_users_channel(self.server().unwrap().session_id().unwrap());
- if from_channel == this_channel || to_channel == this_channel {
+
+ if from_channel == this_channel {
+ // User moved from our channel to somewhere else
if let Some(channel) = self.server().unwrap().channels().get(&to_channel) {
+ let channel = channel.name().to_string();
notifications::send(format!(
"{} moved to channel {}",
- user.name(),
- channel.name()
+ &username,
+ &channel,
));
- } else {
- warn!("{} moved to invalid channel {}", user.name(), to_channel);
+ self.push_event(MumbleEventKind::UserLeftChannel(username.clone(), channel));
}
- self.audio_output
- .play_effect(if from_channel == this_channel {
- NotificationEvents::UserJoinedChannel
- } else {
- NotificationEvents::UserLeftChannel
- });
+ self.audio_output.play_effect(NotificationEvents::UserLeftChannel);
+ } else if to_channel == this_channel {
+ // User moved from somewhere else to our channel
+ if let Some(channel) = self.server().unwrap().channels().get(&from_channel) {
+ let channel = channel.name().to_string();
+ notifications::send(format!(
+ "{} moved to your channel from {}",
+ &username,
+ &channel,
+ ));
+ self.push_event(MumbleEventKind::UserJoinedChannel(username.clone(), channel));
+ }
+ self.audio_output.play_effect(NotificationEvents::UserJoinedChannel);
}
}
//send notification if a user muted/unmuted
if mute != None || deaf != None {
- let mut s = user.name().to_string();
+ let mut s = username;
if let Some(mute) = mute {
s += if mute { " muted" } else { " unmuted" };
}
@@ -221,7 +238,8 @@ impl State {
s += if deaf { " deafened" } else { " undeafened" };
}
s += " themselves";
- notifications::send(s);
+ notifications::send(s.clone());
+ self.push_event(MumbleEventKind::UserMuteStateChanged(s));
}
}
}
@@ -235,11 +253,25 @@ impl State {
let this_channel = self.get_users_channel(self.server().unwrap().session_id().unwrap());
let other_channel = self.get_users_channel(msg.get_session());
if this_channel == other_channel {
- self.audio_output
- .play_effect(NotificationEvents::UserDisconnected);
- if let Some(user) = self.server().unwrap().users().get(&msg.get_session()) {
- notifications::send(format!("{} disconnected", &user.name()));
- }
+ let channel_name = self
+ .server()
+ .unwrap()
+ .channels()
+ .get(&this_channel)
+ .map(|c| c.name())
+ .unwrap_or("<unnamed channel>")
+ .to_string();
+ let user_name = self
+ .server()
+ .unwrap()
+ .users()
+ .get(&msg.get_session())
+ .map(|u| u.name())
+ .unwrap_or("<unknown user>")
+ .to_string();
+ notifications::send(format!("{} disconnected", &user_name));
+ self.push_event(MumbleEventKind::UserDisconnected(user_name, channel_name));
+ self.audio_output.play_effect(NotificationEvents::UserDisconnected);
}
self.server_mut()
@@ -268,7 +300,7 @@ impl State {
}
pub fn register_message(&mut self, msg: (String, u32)) {
- self.message_buffer.push(msg);
+ self.message_buffer.push((chrono::Local::now().naive_local(), msg.0, msg.1));
}
pub fn broadcast_phase(&self, phase: StatePhase) {
@@ -281,6 +313,11 @@ impl State {
.play_effect(NotificationEvents::ServerConnect);
}
+ /// Store a new event
+ pub fn push_event(&mut self, kind: MumbleEventKind) {
+ self.events.push(MumbleEvent { timestamp: chrono::Local::now().naive_local(), kind });
+ }
+
pub fn audio_input(&self) -> &AudioInput {
&self.audio_input
}
@@ -420,6 +457,19 @@ pub fn handle_command(
new_deaf.map(|b| CommandResponse::DeafenStatus { is_deafened: b })
))
}
+ Command::Events { block } => {
+ if block {
+ warn!("Blocking event list is unimplemented");
+ now!(Err(Error::Unimplemented))
+ } else {
+ let events: Vec<_> = state
+ .events
+ .iter()
+ .map(|event| Ok(Some(CommandResponse::Event { event: event.clone() })))
+ .collect();
+ ExecutionContext::Now(Box::new(move || Box::new(events.into_iter())))
+ }
+ }
Command::InputVolumeSet(volume) => {
state.audio_input.set_volume(volume);
now!(Ok(None))
@@ -557,8 +607,9 @@ pub fn handle_command(
accept_invalid_cert,
)))
.unwrap();
+ let state = Arc::clone(&og_state);
at!(
- TcpEvent::Connected => |res| {
+ TcpEvent::Connected => move |res| {
//runs the closure when the client is connected
if let TcpEventData::Connected(res) = res {
Box::new(iter::once(res.map(|msg| {
@@ -568,6 +619,7 @@ pub fn handle_command(
} else {
None
},
+ server_state: state.read().unwrap().server.as_ref().unwrap().into(),
})
})))
} else {
@@ -608,12 +660,12 @@ pub fn handle_command(
}),
Box::new(move |pong| {
Ok(pong.map(|pong| {
- (CommandResponse::ServerStatus {
+ CommandResponse::ServerStatus {
version: pong.version,
users: pong.users,
max_users: pong.max_users,
bandwidth: pong.bandwidth,
- })
+ }
}))
}),
),
@@ -657,6 +709,7 @@ pub fn handle_command(
Box::new(move |data, sender| {
if let TcpEventData::TextMessage(a) = data {
let message = (
+ chrono::Local::now().naive_local(),
a.get_message().to_owned(),
ref_state
.read()
@@ -676,7 +729,7 @@ pub fn handle_command(
let messages = std::mem::take(&mut state.message_buffer);
let messages: Vec<_> = messages
.into_iter()
- .map(|(msg, user)| (msg, state.get_user_name(user).unwrap()))
+ .map(|(timestamp, msg, user)| (timestamp, msg, state.get_user_name(user).unwrap()))
.map(|e| Ok(Some(CommandResponse::PastMessage { message: e })))
.collect();
@@ -692,43 +745,45 @@ pub fn handle_command(
msg.set_message(message);
- for target in targets {
- match target {
- MessageTarget::Channel { recursive, name } => {
- let channel_id = state.server().unwrap().channel_name(&name);
-
- let channel_id = match channel_id {
- Ok(id) => id,
+ match targets {
+ MessageTarget::Channel(channels) => for (channel, recursive) in channels {
+ let channel_id = if let ChannelTarget::Named(name) = channel {
+ let channel = state.server().unwrap().channel_name(&name);
+ match channel {
+ Ok(channel) => channel.0,
Err(e) => return now!(Err(Error::ChannelIdentifierError(name, e))),
}
- .0;
-
- if recursive {
- msg.mut_tree_id()
- } else {
- msg.mut_channel_id()
+ } else {
+ match state.server().unwrap().current_channel() {
+ Some(channel) => channel.0,
+ None => return now!(Err(Error::NotConnectedToChannel)),
}
- .push(channel_id);
- }
- MessageTarget::User { name } => {
- let id = state
- .server()
- .unwrap()
- .users()
- .iter()
- .find(|(_, user)| user.name() == &name)
- .map(|(e, _)| *e);
-
- let id = match id {
- Some(id) => id,
- None => return now!(Err(Error::InvalidUsername(name))),
- };
-
- msg.mut_session().push(id);
- }
+ };
+
+ let ids = if recursive {
+ msg.mut_tree_id()
+ } else {
+ msg.mut_channel_id()
+ };
+ ids.push(channel_id);
+ }
+ MessageTarget::User(names) => for name in names {
+ let id = state
+ .server()
+ .unwrap()
+ .users()
+ .iter()
+ .find(|(_, user)| user.name() == &name)
+ .map(|(e, _)| *e);
+
+ let id = match id {
+ Some(id) => id,
+ None => return now!(Err(Error::InvalidUsername(name))),
+ };
+
+ msg.mut_session().push(id);
}
}
-
packet_sender.send(msg.into()).unwrap();
now!(Ok(None))