Sfoglia il codice sorgente

Add text messaging

Sergey Chushin 3 anni fa
parent
commit
d30c2276cd

+ 39 - 1
src/protocol/parser.rs

@@ -61,7 +61,7 @@ pub enum ControlMessage {
     ServerConfig(ServerConfig),
     ServerSync(ServerSync),
     SuggestConfig(),
-    TextMessage(),
+    TextMessage(TextMessage),
     UserList(),
     UserRemove(UserRemove),
     UserState(UserState),
@@ -151,6 +151,13 @@ pub struct ServerSync {
     pub welcome_text: String,
 }
 
+#[derive(Clone)]
+pub struct TextMessage {
+    pub sender: Option<SessionId>,
+    pub targets: Vec<u32>,
+    pub message: String,
+}
+
 pub struct UserRemove {
     pub session_id: SessionId,
 }
@@ -187,6 +194,9 @@ impl ControlMessage {
             }
             CRYPT_SETUP => CryptSetup::from(mumble::CryptSetup::parse_from_bytes(payload)?).into(),
             PING => Ping::from(mumble::Ping::parse_from_bytes(payload)?).into(),
+            TEXT_MESSAGE => {
+                TextMessage::from(mumble::TextMessage::parse_from_bytes(payload)?).into()
+            }
             USER_STATE => UserState::from(mumble::UserState::parse_from_bytes(payload)?).into(),
             UDP_TUNNEL => ControlMessage::UdpTunnel(UdpTunnel {
                 audio_packet: AudioPacket::parse(payload.to_vec())?,
@@ -379,6 +389,18 @@ impl Message for ServerSync {
     }
 }
 
+impl Message for TextMessage {
+    fn serialize(self) -> Vec<u8> {
+        let proto = mumble::TextMessage {
+            actor: self.sender.map(u32::from),
+            session: self.targets,
+            message: SingularField::some(self.message),
+            ..Default::default()
+        };
+        serialize_protobuf_message(proto, TEXT_MESSAGE)
+    }
+}
+
 impl Message for UserRemove {
     fn serialize(self) -> Vec<u8> {
         let proto = mumble::UserRemove {
@@ -474,6 +496,12 @@ impl From<ServerSync> for ControlMessage {
     }
 }
 
+impl From<TextMessage> for ControlMessage {
+    fn from(message: TextMessage) -> Self {
+        ControlMessage::TextMessage(message)
+    }
+}
+
 impl From<UserRemove> for ControlMessage {
     fn from(remove: UserRemove) -> Self {
         ControlMessage::UserRemove(remove)
@@ -529,6 +557,16 @@ impl From<mumble::Ping> for Ping {
     }
 }
 
+impl From<mumble::TextMessage> for TextMessage {
+    fn from(message: mumble::TextMessage) -> Self {
+        TextMessage {
+            sender: message.actor.map(SessionId::from),
+            targets: message.session,
+            message: message.message.unwrap(),
+        }
+    }
+}
+
 impl From<mumble::UserState> for UserState {
     fn from(state: mumble::UserState) -> Self {
         UserState {

+ 3 - 1
src/server/client/client.rs

@@ -1,5 +1,5 @@
 use crate::protocol::connection::{AudioChannel, ControlChannel};
-use crate::protocol::parser::{AudioData, AudioPacket, UserState};
+use crate::protocol::parser::{AudioData, AudioPacket, TextMessage, UserState};
 use crate::server::client::handler::{Config, Error, Handler};
 use crate::storage::Storage;
 use std::marker::PhantomData;
@@ -19,6 +19,7 @@ pub struct Client<C: ControlChannel, A: AudioChannel> {
 pub enum ClientEvent {
     Talking(AudioData),
     StateChanged(UserState),
+    TextMessage(TextMessage),
     Disconnected,
 }
 
@@ -26,6 +27,7 @@ pub enum ServerEvent {
     Connected(u32),
     Talking(AudioData),
     StateChanged(UserState),
+    TextMessage(TextMessage),
     Disconnected(u32),
 }
 

+ 23 - 2
src/server/client/handler.rs

@@ -1,8 +1,8 @@
 use crate::protocol::connection::{AudioChannel, ControlChannel};
 use crate::protocol::parser::{
     AudioData, AudioPacket, Authenticate, ChannelState, CodecVersion, ControlMessage, CryptSetup,
-    Ping, ServerConfig, ServerSync, SessionId, UdpTunnel, UserRemove, UserState, Version,
-    MUMBLE_PROTOCOL_VERSION,
+    Ping, ServerConfig, ServerSync, SessionId, TextMessage, UdpTunnel, UserRemove, UserState,
+    Version, MUMBLE_PROTOCOL_VERSION,
 };
 use crate::server::client::client::{ClientEvent, ServerEvent};
 use crate::storage::{Guest, SessionData, Storage};
@@ -157,6 +157,7 @@ impl<C: ControlChannel, A: AudioChannel> Handler<C, A> {
             ServerEvent::StateChanged(state) => self.user_state_changed(state).await?,
             ServerEvent::Talking(audio_data) => self.user_talking(audio_data).await?,
             ServerEvent::Disconnected(session_id) => self.user_disconnected(session_id).await?,
+            ServerEvent::TextMessage(message) => self.user_text_message(message).await?,
         }
 
         Ok(())
@@ -165,6 +166,7 @@ impl<C: ControlChannel, A: AudioChannel> Handler<C, A> {
     pub async fn handle_message(&self, packet: ControlMessage) -> Result<(), Error> {
         match packet {
             ControlMessage::Ping(ping) => self.control_ping(ping).await?,
+            ControlMessage::TextMessage(message) => self.text_message(message).await?,
             ControlMessage::UserState(state) => self.user_state(state).await?,
             ControlMessage::UdpTunnel(tunnel) => self.tunnel(tunnel).await?,
             _ => error!("unimplemented!"),
@@ -214,6 +216,20 @@ impl<C: ControlChannel, A: AudioChannel> Handler<C, A> {
         Ok(())
     }
 
+    async fn text_message(&self, mut message: TextMessage) -> Result<(), Error> {
+        if self.config.max_message_length < message.message.len() as u32 {
+            // TODO send a permission denied message
+            return Ok(());
+        }
+        if message.sender.is_none() {
+            message.sender = Some(SessionId::from(self.session_id));
+        }
+        self.event_sender
+            .send(ClientEvent::TextMessage(message))
+            .await;
+        Ok(())
+    }
+
     async fn user_state(&self, mut state: UserState) -> Result<(), Error> {
         if state.session_id.is_none() {
             state.session_id = Some(SessionId::from(self.session_id));
@@ -312,6 +328,11 @@ impl<C: ControlChannel, A: AudioChannel> Handler<C, A> {
         Ok(self.control_channel.send(user_remove).await?)
     }
 
+    async fn user_text_message(&self, message: TextMessage) -> Result<(), Error> {
+        self.control_channel.send(message).await?;
+        Ok(())
+    }
+
     // Utils
     async fn authenticate(&self, auth: Authenticate) -> Result<(), Error> {
         let username = match auth.username {

+ 15 - 1
src/server/connection_worker.rs

@@ -1,5 +1,5 @@
 use crate::crypto::Ocb2Aes128Crypto;
-use crate::protocol::parser::{AudioData, UserState};
+use crate::protocol::parser::{AudioData, TextMessage, UserState};
 use crate::server::client::{Client, ClientEvent, Config, Error, ServerEvent};
 use crate::server::session_pool::{SessionId, SessionPool};
 use crate::server::tcp_control_channel::TcpControlChannel;
@@ -102,6 +102,9 @@ impl ConnectionWorker {
                 ClientEvent::StateChanged(state) => {
                     self.broadcast_state_change(state).await;
                 }
+                ClientEvent::TextMessage(message) => {
+                    self.broadcast_message(message).await;
+                }
             }
         }
     }
@@ -131,4 +134,15 @@ impl ConnectionWorker {
                 .await;
         }
     }
+
+    async fn broadcast_message(&self, message: TextMessage) {
+        for client in self.clients.iter().filter(|client| {
+            self.session_id != *client.key()
+                && (message.targets.is_empty() || message.targets.contains(client.key()))
+        }) {
+            client
+                .send_event(ServerEvent::TextMessage(message.clone()))
+                .await;
+        }
+    }
 }