From 6e7f159adfa54aead6e0d887dadaa41b0ae16609 Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Wed, 27 Dec 2023 21:48:35 +0100 Subject: [PATCH] feat: merge VoiceHandler into official development --- src/voice/handler.rs | 134 +++++++++++++++++++++++++++++++++++++++++++ src/voice/mod.rs | 1 + 2 files changed, 135 insertions(+) create mode 100644 src/voice/handler.rs diff --git a/src/voice/handler.rs b/src/voice/handler.rs new file mode 100644 index 0000000..e757f9a --- /dev/null +++ b/src/voice/handler.rs @@ -0,0 +1,134 @@ +use std::{sync::Arc, net::SocketAddrV4}; + +use async_trait::async_trait; +use tokio::sync::{Mutex, RwLock}; + +use crate::{gateway::Observer, types::{VoiceServerUpdate, VoiceIdentify, VoiceReady, SessionDescription, GatewayReady, Snowflake, SelectProtocol, VoiceProtocol, SelectProtocolData, VoiceEncryptionMode}}; + +use super::{gateway::{VoiceGatewayHandle, VoiceGateway}, udp::UdpHandle, udp::UdpHandler, voice_data::VoiceData}; + +/// Handles inbetween connections between the gateway and udp modules +#[derive(Debug, Clone)] +pub struct VoiceHandler { + pub voice_gateway_connection: Arc>>, + pub voice_udp_connection: Arc>>, + pub data: Arc>, +} + +impl VoiceHandler { + /// Creates a new voicehandler, only initializing the data + pub fn new() -> VoiceHandler { + Self { + data: Arc::new(RwLock::new(VoiceData::default())), + voice_gateway_connection: Arc::new(Mutex::new(None)), + voice_udp_connection: Arc::new(Mutex::new(None)), + } + } +} + +#[async_trait] +// On [VoiceServerUpdate] we get our starting data and url for the voice gateway server. +impl Observer for VoiceHandler { + async fn update(&self, data: &VoiceServerUpdate) { + let mut data_lock = self.data.write().await; + data_lock.server_data = Some(data.clone()); + let user_id = data_lock.user_id.clone(); + let session_id = data_lock.session_id.clone(); + drop(data_lock); + + let voice_gateway_handle = VoiceGateway::spawn(data.endpoint.clone().unwrap()) + .await + .unwrap(); + + let server_id: Snowflake; + + if data.guild_id.is_some() { + server_id = data.guild_id.clone().unwrap(); + } else { + server_id = data.channel_id.clone().unwrap(); + } + + let voice_identify = VoiceIdentify { + server_id, + user_id, + session_id, + token: data.token.clone(), + video: Some(false), + }; + + voice_gateway_handle.send_identify(voice_identify).await; + + let cloned_gateway_handle = voice_gateway_handle.clone(); + + let mut voice_events = cloned_gateway_handle.events.lock().await; + + let self_reference = Arc::new(self.clone()); + + voice_events.voice_ready.subscribe(self_reference.clone()); + voice_events.session_description.subscribe(self_reference.clone()); + + *self.voice_gateway_connection.lock().await = Some(voice_gateway_handle); + } +} + +#[async_trait] +// On [VoiceReady] we get info for establishing a UDP connection, and we immedietly need said UDP +// connection for ip discovery. +impl Observer for VoiceHandler { + async fn update(&self, data: &VoiceReady) { + + let mut data_lock = self.data.write().await; + data_lock.ready_data = Some(data.clone()); + drop(data_lock); + + let udp_handle = UdpHandler::spawn( + self.data.clone(), + std::net::SocketAddr::V4(SocketAddrV4::new(data.ip.clone(), data.port)), + data.ssrc, + ) + .await; + + let ip_discovery = self.data.read().await.ip_discovery.clone().unwrap(); + + *self.voice_udp_connection.lock().await = Some(udp_handle.clone()); + + self.voice_gateway_connection + .lock() + .await + .clone() + .unwrap() + .send_select_protocol(SelectProtocol { + protocol: VoiceProtocol::Udp, + data: SelectProtocolData { + address: ip_discovery.address, + port: ip_discovery.port, + mode: VoiceEncryptionMode::Xsalsa20Poly1305, + }, + ..Default::default() + }) + .await; + } +} + +#[async_trait] +// Session descryption gives us final info regarding codecs and our encryption key +impl Observer for VoiceHandler { + async fn update(&self, data: &SessionDescription) { + + let mut data_write = self.data.write().await; + + data_write.session_description = Some(data.clone()); + + drop(data_write); + } +} + +#[async_trait] +impl Observer for VoiceHandler { + async fn update(&self, data: &GatewayReady) { + let mut lock = self.data.write().await; + lock.user_id = data.user.id.clone(); + lock.session_id = data.session_id.clone(); + drop(lock); + } +} diff --git a/src/voice/mod.rs b/src/voice/mod.rs index 8d84a0a..e672ea8 100644 --- a/src/voice/mod.rs +++ b/src/voice/mod.rs @@ -4,6 +4,7 @@ mod crypto; pub mod gateway; pub mod udp; pub mod voice_data; +pub mod handler; // Pub use this so users can interact with packet types if they want pub use discortp;