diff options
| author | Gustav Sörnäs <gustav@sornas.net> | 2020-10-16 01:35:59 +0200 |
|---|---|---|
| committer | Gustav Sörnäs <gustav@sornas.net> | 2020-10-16 01:35:59 +0200 |
| commit | 18a3c0b3cf8254b70857e31ddd2b6213b10db156 (patch) | |
| tree | 07f7020aaf096b0ed58792ad78527d34f94e4f96 /mumlib | |
| parent | 8e4eb0afcd0541c6732ebec71af76f3962f590cc (diff) | |
| parent | d35c9171271110339504abd96065dc25e1290500 (diff) | |
| download | mum-18a3c0b3cf8254b70857e31ddd2b6213b10db156.tar.gz | |
Merge branch 'cli' into 'main'
mumctl
See merge request gustav/mum!2
Diffstat (limited to 'mumlib')
| -rw-r--r-- | mumlib/Cargo.toml | 15 | ||||
| -rw-r--r-- | mumlib/src/command.rs | 31 | ||||
| -rw-r--r-- | mumlib/src/lib.rs | 35 | ||||
| -rw-r--r-- | mumlib/src/state.rs | 217 |
4 files changed, 298 insertions, 0 deletions
diff --git a/mumlib/Cargo.toml b/mumlib/Cargo.toml new file mode 100644 index 0000000..a2627d4 --- /dev/null +++ b/mumlib/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "mumlib" +version = "0.1.0" +authors = ["Gustav Sörnäs <gustav@sornas.net>", + "Eskil Queseth <eskilq@kth.se>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +colored = "2.0" +fern = "0.5" +log = "0.4" +mumble-protocol = "0.3" +serde = { version = "1.0", features = ["derive"] } diff --git a/mumlib/src/command.rs b/mumlib/src/command.rs new file mode 100644 index 0000000..b2ac321 --- /dev/null +++ b/mumlib/src/command.rs @@ -0,0 +1,31 @@ +use crate::state::{Channel, Server}; + +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum Command { + ChannelJoin { + channel_id: u32, + }, + ChannelList, + ServerConnect { + host: String, + port: u16, + username: String, + accept_invalid_cert: bool, + }, + ServerDisconnect, + Status, +} + +#[derive(Debug, Deserialize, Serialize)] +pub enum CommandResponse { + ChannelList { + channels: HashMap<u32, Channel>, + }, + Status { + username: Option<String>, + server_state: Server, + }, +} diff --git a/mumlib/src/lib.rs b/mumlib/src/lib.rs new file mode 100644 index 0000000..ebf2019 --- /dev/null +++ b/mumlib/src/lib.rs @@ -0,0 +1,35 @@ +pub mod command; +pub mod state; + +use colored::*; +use log::*; + +pub fn setup_logger() { + fern::Dispatch::new() + .format(|out, message, record| { + let message = message.to_string(); + out.finish(format_args!( + "{} {}:{}{}{}", + //TODO runtime flag that disables color + match record.level() { + Level::Error => "ERROR".red(), + Level::Warn => "WARN ".yellow(), + Level::Info => "INFO ".normal(), + Level::Debug => "DEBUG".green(), + Level::Trace => "TRACE".normal(), + }, + record.file().unwrap(), + record.line().unwrap(), + if message.chars().any(|e| e == '\n') { + "\n" + } else { + " " + }, + message + )) + }) + .level(log::LevelFilter::Debug) + .chain(std::io::stderr()) + .apply() + .unwrap(); +} diff --git a/mumlib/src/state.rs b/mumlib/src/state.rs new file mode 100644 index 0000000..f90634e --- /dev/null +++ b/mumlib/src/state.rs @@ -0,0 +1,217 @@ +use log::*; +use mumble_protocol::control::msgs; +use serde::{Deserialize, Serialize}; +use std::collections::hash_map::Entry; +use std::collections::HashMap; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Server { + channels: HashMap<u32, Channel>, + users: HashMap<u32, User>, + pub welcome_text: Option<String>, +} + +impl Server { + pub fn new() -> Self { + Self { + channels: HashMap::new(), + users: HashMap::new(), + welcome_text: None, + } + } + + pub fn parse_server_sync(&mut self, mut msg: msgs::ServerSync) { + if msg.has_welcome_text() { + self.welcome_text = Some(msg.take_welcome_text()); + } + } + + pub fn parse_channel_state(&mut self, msg: msgs::ChannelState) { + if !msg.has_channel_id() { + warn!("Can't parse channel state without channel id"); + return; + } + match self.channels.entry(msg.get_channel_id()) { + Entry::Vacant(e) => { + e.insert(Channel::new(msg)); + } + Entry::Occupied(mut e) => e.get_mut().parse_channel_state(msg), + } + } + + pub fn parse_channel_remove(&mut self, msg: msgs::ChannelRemove) { + if !msg.has_channel_id() { + warn!("Can't parse channel remove without channel id"); + return; + } + match self.channels.entry(msg.get_channel_id()) { + Entry::Vacant(_) => { + warn!("Attempted to remove channel that doesn't exist"); + } + Entry::Occupied(e) => { + e.remove(); + } + } + } + + pub fn parse_user_state(&mut self, msg: msgs::UserState) { + if !msg.has_session() { + warn!("Can't parse user state without session"); + return; + } + match self.users.entry(msg.get_session()) { + Entry::Vacant(e) => { + e.insert(User::new(msg)); + } + Entry::Occupied(mut e) => e.get_mut().parse_user_state(msg), + } + } + + pub fn channels(&self) -> &HashMap<u32, Channel> { + &self.channels + } + + pub fn users(&self) -> &HashMap<u32, User> { + &self.users + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Channel { + description: Option<String>, + links: Vec<u32>, + max_users: u32, + name: String, + parent: Option<u32>, + position: i32, +} + +impl Channel { + pub fn new(mut msg: msgs::ChannelState) -> Self { + Self { + description: if msg.has_description() { + Some(msg.take_description()) + } else { + None + }, + links: Vec::new(), + max_users: msg.get_max_users(), + name: msg.take_name(), + parent: if msg.has_parent() { + Some(msg.get_parent()) + } else { + None + }, + position: msg.get_position(), + } + } + + pub fn parse_channel_state(&mut self, mut msg: msgs::ChannelState) { + if msg.has_description() { + self.description = Some(msg.take_description()); + } + self.links = msg.take_links(); + if msg.has_max_users() { + self.max_users = msg.get_max_users(); + } + if msg.has_name() { + self.name = msg.take_name(); + } + if msg.has_parent() { + self.parent = Some(msg.get_parent()); + } + if msg.has_position() { + self.position = msg.get_position(); + } + } + + pub fn name(&self) -> &str { + &self.name + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct User { + channel: u32, + comment: Option<String>, + hash: Option<String>, + name: String, + priority_speaker: bool, + recording: bool, + + suppress: bool, // by me + self_mute: bool, // by self + self_deaf: bool, // by self + mute: bool, // by admin + deaf: bool, // by admin +} + +impl User { + pub fn new(mut msg: msgs::UserState) -> Self { + Self { + channel: msg.get_channel_id(), + comment: if msg.has_comment() { + Some(msg.take_comment()) + } else { + None + }, + hash: if msg.has_hash() { + Some(msg.take_hash()) + } else { + None + }, + name: msg.take_name(), + priority_speaker: msg.has_priority_speaker() && msg.get_priority_speaker(), + recording: msg.has_recording() && msg.get_recording(), + suppress: msg.has_suppress() && msg.get_suppress(), + self_mute: msg.has_self_mute() && msg.get_self_mute(), + self_deaf: msg.has_self_deaf() && msg.get_self_deaf(), + mute: msg.has_mute() && msg.get_mute(), + deaf: msg.has_deaf() && msg.get_deaf(), + } + } + + pub fn parse_user_state(&mut self, mut msg: msgs::UserState) { + if msg.has_channel_id() { + self.channel = msg.get_channel_id(); + } + if msg.has_comment() { + self.comment = Some(msg.take_comment()); + } + if msg.has_hash() { + self.hash = Some(msg.take_hash()); + } + if msg.has_name() { + self.name = msg.take_name(); + } + if msg.has_priority_speaker() { + self.priority_speaker = msg.get_priority_speaker(); + } + if msg.has_recording() { + self.recording = msg.get_recording(); + } + if msg.has_suppress() { + self.suppress = msg.get_suppress(); + } + if msg.has_self_mute() { + self.self_mute = msg.get_self_mute(); + } + if msg.has_self_deaf() { + self.self_deaf = msg.get_self_deaf(); + } + if msg.has_mute() { + self.mute = msg.get_mute(); + } + if msg.has_deaf() { + self.deaf = msg.get_deaf(); + } + } + + pub fn name(&self) -> &str { + &self.name + } + + pub fn channel(&self) -> u32 { + self.channel + } +} |
