Skip to content

Commit

Permalink
GH-85: Add support for new mumble proto
Browse files Browse the repository at this point in the history
- Add timestamp and uid to text messages
- Add multi profile option
- Add compression for audio
  • Loading branch information
SetZero committed Jan 27, 2024
1 parent 5ade74f commit 404b5c9
Show file tree
Hide file tree
Showing 34 changed files with 420 additions and 130 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,5 @@ dist-ssr

src-tauri/data
src-tauri/src/proto/Mumble.proto
src-tauri/src/proto/MumbleUDP.proto
src-tauri/gen
6 changes: 5 additions & 1 deletion public/locales/en/audio.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,9 @@
"Audio deactivation at": "Audio deactivation at {{threshold}}",
"Amplification dB": "Amplification +{{amplification}}dB",
"Echo Cancelation": "Echo Cancelation",
"Noise Suppression": "Noise Suppression"
"Noise Suppression": "Noise Suppression",
"Compressor Threshold": "Compressor Threshold {{threshold}}dB",
"Compressor Ratio": "Compressor Ratio {{ratio}}:1",
"Attack Time": "Attack Time {{duration}}",
"Release Time": "Release Time {{duration}}"
}
1 change: 1 addition & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ scraper = "0.18.1"
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
symphonia = "0.5.3"
mime_guess = "2.0.4"
uuid = "1.7.0"

[dev-dependencies]
tempfile = "3.5.0"
Expand Down
18 changes: 16 additions & 2 deletions src-tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ const MUMBLE_PROTO_SHA256: &str =
"0f86d85938ff2268e3eb05ce0120805fb049ad0d062f4d01c6657b048dcc9245";
const PATCHED_MUMBLE_PROTO_HASH: &str =
"ebadea7bcb720da05149076b1b0ec7a9ff1107a5107a4137b75e8e45fb52f68d";
const DOWNLOAD_MUMBLE_UDP_PROTO_DIR: &str =
"https://raw.githubusercontent.com/mumble-voip/mumble/6a48c0478477054b4e7356b0bd7dc9da24cf0880/src/MumbleUDP.proto";
const MUMBLE_UDP_PROTO_SHA256: &str =
"8087983b0d9a12e11380cad99870a0ef3cee7550b13a114a733aa835acd3d040";

fn apply(diff: Patch, old: &str) -> String {
let old_lines = old.lines().collect::<Vec<&str>>();
Expand Down Expand Up @@ -81,6 +85,7 @@ async fn download_file(

fn main() -> io::Result<()> {
let mumble_proto = Path::new("src/proto/Mumble.proto");
let mumble_udp_proto = Path::new("src/proto/MumbleUDP.proto");
let patch_file = Path::new("src/proto/Mumble.proto.patch");

let mumble_proto_bytes = read_file_as_bytes(mumble_proto).unwrap_or_default();
Expand All @@ -90,20 +95,29 @@ fn main() -> io::Result<()> {
if hash != PATCHED_MUMBLE_PROTO_HASH {
let rt = Runtime::new()?;
rt.block_on(async {
let resonse_file =
let response_file =
download_file(DOWNLOAD_MUMBLE_PROTO_DIR, MUMBLE_PROTO_SHA256, mumble_proto)
.await
.expect("Failed to download Mumble.proto");
let response_str = str::from_utf8(&resonse_file).expect("Failed to parse response");
let response_str = str::from_utf8(&response_file).expect("Failed to parse response");

let patch_output = read_file_as_bytes(patch_file).expect("Failed to read file");
let patch = Patch::from_single(patch_output.as_str()).expect("Failed to parse patch");
let new_content = apply(patch, response_str);
write_to_file(new_content.as_bytes(), mumble_proto);

download_file(
DOWNLOAD_MUMBLE_UDP_PROTO_DIR,
MUMBLE_UDP_PROTO_SHA256,
mumble_udp_proto,
)
.await
.expect("Failed to download MumbleUDP.proto");
});
}

prost_build::compile_protos(&["src/proto/Mumble.proto"], &["src/"])?;
prost_build::compile_protos(&["src/proto/MumbleUDP.proto"], &["src/"])?;
tauri_build::build();

Ok(())
Expand Down
3 changes: 2 additions & 1 deletion src-tauri/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,12 @@ pub async fn logout(state: State<'_, ConnectionState>) -> Result<(), String> {
#[tauri::command]
pub async fn like_message(
message_id: String,
reciever: Vec<u32>,
state: State<'_, ConnectionState>,
) -> Result<(), String> {
let guard = state.connection.lock().await;
if let Some(guard) = guard.as_ref() {
if let Err(e) = guard.like_message(&message_id) {
if let Err(e) = guard.like_message(&message_id, reciever) {
return Err(format!("{e:?}"));
}
}
Expand Down
20 changes: 11 additions & 9 deletions src-tauri/src/commands/settings_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ use std::{
sync::RwLock,
};

use reqwest::Identity;
use tauri::State;
use tracing::{info, trace};

use crate::{utils::{constants::get_project_dirs, server::{Server, UserIdentity}}, errors::certificate_error::CertificateError};
use crate::{
errors::certificate_error::CertificateError,
utils::{constants::get_project_dirs, server::Server},
};

use super::utils::settings::FrontendSettings;

Expand Down Expand Up @@ -168,24 +170,24 @@ pub fn get_frontend_settings(
Ok(settings_data)
}


#[tauri::command]
pub fn get_identity_certs() -> Result<Vec<String>, String> {
let project_dirs = get_project_dirs()
.ok_or_else(|| CertificateError::new("Unable to load project dir")).map_err(|e| format!("{:?}", e))?;
.ok_or_else(|| CertificateError::new("Unable to load project dir"))
.map_err(|e| format!("{e:?}"))?;
let data_dir = project_dirs.data_dir();

if !data_dir.exists() {
std::fs::create_dir_all(&data_dir).map_err(|e| format!("{:?}", e))?;
std::fs::create_dir_all(data_dir).map_err(|e| format!("{e:?}"))?;
}

let mut certs = Vec::new();

let dir_entries = fs::read_dir(&data_dir)
.map_err(|e| format!("Error reading directory: {}", e))?;
let dir_entries =
fs::read_dir(data_dir).map_err(|e| format!("Error reading directory: {e}"))?;

for entry in dir_entries {
let entry = entry.map_err(|e| format!("Error reading directory entry: {}", e))?;
let entry = entry.map_err(|e| format!("Error reading directory entry: {e}"))?;
let file_name = entry.file_name();
let file_name_str = file_name.to_string_lossy();

Expand All @@ -199,4 +201,4 @@ pub fn get_identity_certs() -> Result<Vec<String>, String> {
}

Ok(certs)
}
}
9 changes: 9 additions & 0 deletions src-tauri/src/commands/utils/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ pub struct VoiceActivationOptions {
pub voice_hysteresis_upper_threshold: f32,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CompressorOptions {
pub attack_time: usize,
pub release_time: usize,
pub threshold: f32,
pub ratio: f32,
}

#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
pub enum InputMode {
VoiceActivation = 0,
Expand All @@ -42,6 +50,7 @@ pub struct AudioOptions {
pub amplification: f32,
pub input_mode: InputMode,
pub voice_activation_options: Option<VoiceActivationOptions>,
pub compressor_options: Option<CompressorOptions>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
Expand Down
7 changes: 4 additions & 3 deletions src-tauri/src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use self::threads::ConnectionThread;

const QUEUE_SIZE: usize = 256;
const BUFFER_SIZE: usize = 8192;
const FANCY_MUMBLE_DATA_ID: &str = "fancy_mumble";

struct ServerData {
username: String,
Expand Down Expand Up @@ -162,12 +163,12 @@ impl Connection {
}

//TODO: Move to output Thread
pub fn like_message(&self, message_id: &str) -> AnyError<()> {
pub fn like_message(&self, message_id: &str, reciever: Vec<u32>) -> AnyError<()> {
let like_message = mumble::proto::PluginDataTransmission {
sender_session: None,
receiver_sessions: Vec::new(),
receiver_sessions: reciever,
data: Some(message_id.as_bytes().to_vec()),
data_id: None,
data_id: Some(FANCY_MUMBLE_DATA_ID.to_owned()),
};
self.tx_out.send(message_builder(&like_message)?)?;

Expand Down
1 change: 0 additions & 1 deletion src-tauri/src/connection/threads/input_thread.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::sync::atomic::Ordering;

use crate::connection::Connection;
use crate::connection::traits::Shutdown;
use crate::protocol::message_router::MessageRouter;
use crate::protocol::stream_reader::StreamReader;
use tokio::select;
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/src/connection/threads/output_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ impl OutputThread for Connection {
channel_id: result.channel_id.iter().copied().collect(),
tree_id: Vec::new(),
message: result.message,
message_id: None,
timestamp: None,
};
trace!("Sending message: {:?}", message);
let buffer = message_builder(&message).unwrap_or_default();
Expand Down
7 changes: 4 additions & 3 deletions src-tauri/src/connection/threads/ping_thread.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::{
connection::{Connection, PingThread, threads::MAX_PING_FAILURES},
connection::{threads::MAX_PING_FAILURES, Connection, PingThread},
mumble,
utils::{messages::message_builder, frontend::send_to_frontend}, protocol::serialize::message_container::FrontendMessage,
protocol::serialize::message_container::FrontendMessage,
utils::{frontend::send_to_frontend, messages::message_builder},
};
use std::{
sync::atomic::Ordering,
Expand Down Expand Up @@ -67,7 +68,7 @@ impl PingThread for Connection {
deadman_counter += 1;
if deadman_counter > MAX_PING_FAILURES {
let message = FrontendMessage::new("ping_timeout", "Timeout while sending Ping");
send_to_frontend(&frontend_channel, &message)
send_to_frontend(&frontend_channel, &message);
}
},
}
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use crate::commands::{
enable_audio_info, get_audio_devices, like_message, logout, send_message,
set_audio_input_setting, set_audio_output_setting, set_user_image,
settings_cmd::{
get_identity_certs, get_frontend_settings, get_server_list, save_frontend_settings,
get_frontend_settings, get_identity_certs, get_server_list, save_frontend_settings,
save_server,
},
web_cmd::{get_open_graph_data_from_website, open_browser},
Expand Down
8 changes: 5 additions & 3 deletions src-tauri/src/manager/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ use std::{
};

use serde::Serialize;
use tracing::{debug, error, info};
use tracing::{debug, info};

use crate::{
errors::AnyError, mumble, protocol::serialize::message_container::FrontendMessage,
utils::{messages::message_builder, frontend::send_to_frontend},
errors::AnyError,
mumble,
protocol::serialize::message_container::FrontendMessage,
utils::{frontend::send_to_frontend, messages::message_builder},
};

use super::Update;
Expand Down
8 changes: 3 additions & 5 deletions src-tauri/src/manager/connection_state.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use serde::Serialize;
use tracing::error;

use crate::{protocol::serialize::message_container::FrontendMessage, utils::frontend::send_to_frontend};
use crate::{
protocol::serialize::message_container::FrontendMessage, utils::frontend::send_to_frontend,
};

use tokio::sync::broadcast::Sender;

Expand All @@ -18,7 +17,6 @@ impl Manager {
}
}


pub fn notify_disconnected(&self, message: &Option<String>) {
let msg = FrontendMessage::new("disconnected", message);

Expand Down
23 changes: 15 additions & 8 deletions src-tauri/src/manager/text_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use serde::Serialize;
use tokio::sync::broadcast::Sender;
use tracing::error;

use crate::{errors::AnyError, mumble, protocol::serialize::message_container::FrontendMessage};
use crate::{mumble, protocol::serialize::message_container::FrontendMessage};

use super::user::User;

Expand All @@ -19,6 +19,7 @@ struct TextMessage {
sender: SenderInfo,
message: String,
timestamp: u128,
id: Option<String>,
}

pub struct Manager {
Expand Down Expand Up @@ -64,21 +65,27 @@ impl Manager {
self.notify(Some(last));
}

pub fn add_text_message(
&mut self,
text_message: mumble::proto::TextMessage,
user: &User,
) -> AnyError<()> {
pub fn add_text_message(&mut self, text_message: mumble::proto::TextMessage, user: &User) {
let timestamp = text_message.timestamp.map_or_else(
|| {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis()
},
u128::from,
);

let message = TextMessage {
sender: SenderInfo {
user_id: user.id,
user_name: user.name.clone(),
},
message: text_message.message,
timestamp: SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis(),
timestamp,
id: text_message.message_id,
};
self.message_log.push(message);
self.notify_last();
Ok(())
}
}
31 changes: 15 additions & 16 deletions src-tauri/src/manager/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ use base64::{engine::general_purpose, Engine as _};
use std::collections::{hash_map::Entry, HashMap};

use serde::{Deserialize, Serialize};
use tracing::{debug, error, info, trace, warn};
use tracing::{debug, info, trace};

use crate::{
errors::AnyError,
mumble,
protocol::serialize::message_container::FrontendMessage,
utils::{
file::{read_data_from_cache, store_data_in_cache},
messages::message_builder, frontend::send_to_frontend,
frontend::send_to_frontend,
messages::message_builder,
},
};

Expand Down Expand Up @@ -66,10 +67,10 @@ pub struct UpdateableUserState {

#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct SyncInfo {
pub session: Option<u32>,
pub max_bandwidth: Option<u32>,
pub welcome_text: Option<String>,
pub permissions: Option<u64>,
pub session: Option<u32>,
pub max_bandwidth: Option<u32>,
pub welcome_text: Option<String>,
pub permissions: Option<u64>,
}

#[derive(Debug, Default, Serialize)]
Expand Down Expand Up @@ -100,7 +101,6 @@ impl Update<mumble::proto::UserState> for User {

pub struct Manager {
users: HashMap<u32, User>,
current_user_id: Option<u32>,
frontend_channel: Sender<String>,
server_channel: Sender<Vec<u8>>,
}
Expand All @@ -109,7 +109,6 @@ impl Manager {
pub fn new(send_to: Sender<String>, server_channel: Sender<Vec<u8>>) -> Self {
Self {
users: HashMap::new(),
current_user_id: None,
frontend_channel: send_to,
server_channel,
}
Expand Down Expand Up @@ -320,14 +319,14 @@ impl Manager {
}

pub fn notify_current_user(&mut self, sync_info: &mumble::proto::ServerSync) {
let sync_info = SyncInfo {
session: sync_info.session,
max_bandwidth: sync_info.max_bandwidth,
welcome_text: sync_info.welcome_text.clone(),
permissions: sync_info.permissions,
};
let message = FrontendMessage::new("sync_info", sync_info);
send_to_frontend(&self.frontend_channel, &message);
let sync_info = SyncInfo {
session: sync_info.session,
max_bandwidth: sync_info.max_bandwidth,
welcome_text: sync_info.welcome_text.clone(),
permissions: sync_info.permissions,
};
let message = FrontendMessage::new("sync_info", sync_info);
send_to_frontend(&self.frontend_channel, &message);
}
}

Expand Down
Loading

0 comments on commit 404b5c9

Please sign in to comment.