From e105d4030828a63bb7fe60b7706891f85b6676c9 Mon Sep 17 00:00:00 2001 From: alemi Date: Thu, 22 Feb 2024 04:55:58 +0100 Subject: [PATCH] feat: track channels no way to get them yet tho but they should get tracked too now oh users have a channel_id field --- src/model.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/session.rs | 35 +++++++++++++++++++++++-------- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/model.rs b/src/model.rs index 82a3068..82cac84 100644 --- a/src/model.rs +++ b/src/model.rs @@ -38,6 +38,9 @@ pub struct User { /// Registered user ID if the user is registered. pub user_id: Option, + /// Channel on which the user is. + pub channel_id: u32, + /// User comment if it is less than 128 bytes. pub comment: Option, @@ -70,6 +73,7 @@ impl User { if let Some(name) = state.name { self.name = name } if let Some(user_id) = state.user_id { self.user_id = Some(user_id) } if let Some(comment) = state.comment { self.comment = Some(comment) } + if let Some(channel_id) = state.channel_id { self.channel_id = channel_id } if let Some(mute) = state.mute { self.properties.mute = mute } if let Some(deaf) = state.deaf { self.properties.deaf = deaf } if let Some(suppress) = state.suppress { self.properties.suppress = suppress } @@ -89,6 +93,7 @@ impl From for User { name: value.name().to_string(), user_id: value.user_id, comment: value.comment.clone(), + channel_id: value.channel_id(), properties: UserProperties { mute: value.mute(), deaf: value.deaf(), @@ -101,3 +106,54 @@ impl From for User { } } } + +#[derive(Debug, Clone, serde::Serialize)] +pub struct Channel { + /// Unique ID for the channel within the server. + pub id: u32, + + /// channel_id of the parent channel. + pub parent: Option, + + /// UTF-8 encoded channel name. + pub name: String, + + /// UTF-8 encoded channel description + pub description: String, + + /// True if the channel is temporary. + pub temporary: bool, + + /// Position weight to tweak the channel position in the channel list. + pub position: i32, + + /// Maximum number of users allowed in the channel. If this value is zero, + /// the maximum number of users allowed in the channel is given by the + /// server's "usersperchannel" setting. + pub max_users: u32, +} + +impl From for Channel { + fn from(value: crate::tcp::proto::ChannelState) -> Self { + Channel { + id: value.channel_id(), + parent: value.parent, + name: value.name().to_string(), + description: value.description().to_string(), + temporary: value.temporary(), + position: value.position(), + max_users: value.max_users() + } + } +} + +impl Channel { + pub fn update(&mut self, value: crate::tcp::proto::ChannelState) { + if self.id != value.channel_id() { tracing::warn!("updating channel with different id") } + if let Some(parent) = value.parent { self.parent = Some(parent) } + if let Some(name) = value.name { self.name = name } + if let Some(description) = value.description { self.description = description } + if let Some(temporary) = value.temporary { self.temporary = temporary } + if let Some(max_users) = value.max_users { self.max_users = max_users } + } +} diff --git a/src/session.rs b/src/session.rs index 54a1d16..51bf76e 100644 --- a/src/session.rs +++ b/src/session.rs @@ -2,12 +2,13 @@ use std::{borrow::Borrow, collections::HashMap, net::SocketAddr, sync::{atomic:: use tokio::{net::UdpSocket, sync::{broadcast, RwLock}}; -use crate::{model::User, tcp::{control::ControlChannel, proto}, udp::proto::{PingPacket, PongPacket}}; +use crate::{model::{Channel, User}, tcp::{control::ControlChannel, proto}, udp::proto::{PingPacket, PongPacket}}; #[derive(Debug)] pub struct Session { options: Arc, users: Arc>>, + channels: Arc>>, // sync: watch::Receiver, run: Arc, events: Arc>, @@ -96,6 +97,7 @@ impl Session { options: Arc, run: Arc, users: Arc>>, + channels: Arc>>, events: Arc>, ) -> std::io::Result<()> { let channel = Arc::new(ControlChannel::new(&options.host, Some(options.port)).await?); @@ -136,6 +138,18 @@ impl Session { users.write().await.remove(&user.session); let _ = events.send(SessionEvent::RemoveUser(user.session)); }, + Ok(proto::Packet::ChannelRemove(channel)) => { + tracing::debug!("removing channel: {:?}", channel); + channels.write().await.remove(&channel.channel_id); + }, + Ok(proto::Packet::ChannelState(channel)) => { + tracing::debug!("updating channel state: {:?}", channel); + let mut channels = channels.write().await; + match channels.get_mut(&channel.channel_id()) { + Some(c) => c.update(channel), + None => { channels.insert(channel.channel_id(), Channel::from(channel)); }, + } + }, Ok(proto::Packet::UserState(user)) => { tracing::debug!("updating user state: {:?}", user); let mut users = users.write().await; @@ -152,6 +166,7 @@ impl Session { } } users.write().await.clear(); + channels.write().await.clear(); }); tasks.spawn(async move { @@ -173,9 +188,10 @@ impl Session { let username = username.unwrap_or_else(|| ".mumble-stats-api".to_string()); let (events, _) = broadcast::channel(64); - let s = Session { + let session = Session { events: Arc::new(events), users : Arc::new(RwLock::new(HashMap::new())), + channels : Arc::new(RwLock::new(HashMap::new())), run: Arc::new(AtomicBool::new(true)), options: Arc::new(SessionOptions { username, password, @@ -184,13 +200,16 @@ impl Session { }), }; - let options = s.options.clone(); - let run = s.run.clone(); - let users = s.users.clone(); - let events = s.events.clone(); + let options = session.options.clone(); + let run = session.run.clone(); + let users = session.users.clone(); + let channels = session.channels.clone(); + let events = session.events.clone(); tokio::spawn(async move { while run.load(std::sync::atomic::Ordering::Relaxed) { - if let Err(e) = Self::connect_session(options.clone(), run.clone(), users.clone(), events.clone()).await { + if let Err(e) = Self::connect_session( + options.clone(), run.clone(), users.clone(), channels.clone(), events.clone() + ).await { tracing::error!("could not connect to mumble: {e}"); } tokio::time::sleep(std::time::Duration::from_secs(10)).await; @@ -198,6 +217,6 @@ impl Session { } }); - s + session } }