2024-01-30 17:19:34 +01:00
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
2023-11-19 19:12:29 +01:00
|
|
|
use futures_util::SinkExt;
|
|
|
|
use log::*;
|
|
|
|
|
|
|
|
use std::fmt::Debug;
|
|
|
|
|
Primitive voice implementation (feature/voice) (#457)
* Add Webrtc Identify & Ready
* Add more webrtc typings
* Attempt an untested voice gateway implementation
* fmt
* Merge with main
* Same allow as for voice as normal gateway
* Test error observer
* Minor updates
* More derives
* Even more derives
* Small types update
* e
* Minor doc fixes
* Modernise voice gateway
* Add default impl for voicegatewayerror
* Make voice event fields pub
* Event updates via the scientific method
* ??
* Fix bad request in voice gateway init
* Voice gateway updates
* Fix error failing to 'deserialize' properly
* Update voice identify
* Clarify FIXME related to #430
* Update to v7
* Create seperate voice_gateway.rs and voice_udp.rs
* Restructure voice to new module
* fix: deserialization error in speaking bitflags
* feat: kinda janky ip discovery impl
* feat: return ip discovery data + minor update
* feat: packet parsing!
* fix: voice works again
* feat: add voice_media_sink_wants
(comitting uncommited changes to merge)
* chore: rename events/webrtc to events/voice_gateway
* Add UdpHandle
* chore: clippy + other misc updates
* fix: attempt to fix failing wasm build
* chore: yes clippy, that is indeed an unneeded return statement
* feat: add VoiceData struct
* feat: add VoiceData reference to UdpHandler
* feat: decryption?
* chore: formatting
* feat: add ssrc definition (op 12)
* feat: add untested sending & asbtract nonce generation
* feat: Public api! (sorta)
* small updates
* feat: add sequence number
* chore: yes
* feat: merge VoiceHandler into official development
* chore: yes clippy, you are special
* fix: duplicated gateway events
* feat: first try at vgw wasm compat
* fix: blunder
* fix: gateway connect using wrong url
* fix: properly using encrypted data, bad practice for buffer creation
* chore: split voice udp
* feat: udp error handling, create udp/backends
* fix: its the same
* chore: clarify UDP on WASM
* api: split voice gateway and udp features, test for voice gateway in WASM
* feat: new encryption modes, minor code quality
* docs: document voice encryption modes
* chore: unused imports
* chore: update getrandom version to match wasm version
* chore: update on packet size FIXME
* drop buf asap
* Okay can't do that actually
* tests: add nonce test
* normal tests work?
* docs: fix doc warning, fix incorrect refrences to 'webrtc'
* chore: json isn't a doc test
* tests: better gateway auth test
* testing tests
* update voice heartbeat, fix the new test issue
* committed too much
* fix: unused import
* fix: use ip discovery address as string, not as Vec<u8>
* chore: less obnoxious logging
* chore: better unimplemented voice modes handling
* chore: remove unused variable
* chore: use matches macro
* add voice examples, make gateway ones clearer
* rename voice example
* chore: remove unused VoiceHandler
* fix: implement gateway Reconnect and InvalidSession
* Typo
Co-authored-by: Flori <39242991+bitfl0wer@users.noreply.github.com>
* Fix a bunch of typos
Co-authored-by: Flori <39242991+bitfl0wer@users.noreply.github.com>
* fix: error handling while loading native certs
* fix: guh
* use be for nonce bytes
* fix: refactor gw and vgw closures
* remove outdated docs
---------
Co-authored-by: Flori <39242991+bitfl0wer@users.noreply.github.com>
2024-04-16 17:18:21 +02:00
|
|
|
use super::{events::Events, *};
|
2024-04-28 14:15:57 +02:00
|
|
|
use crate::types::{self, Composite, Shared};
|
2023-11-19 19:12:29 +01:00
|
|
|
|
|
|
|
/// Represents a handle to a Gateway connection. A Gateway connection will create observable
|
|
|
|
/// [`GatewayEvents`](GatewayEvent), which you can subscribe to. Gateway events include all currently
|
|
|
|
/// implemented types with the trait [`WebSocketEvent`]
|
|
|
|
/// Using this handle you can also send Gateway Events directly.
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct GatewayHandle {
|
|
|
|
pub url: String,
|
|
|
|
pub events: Arc<Mutex<Events>>,
|
2023-11-20 13:40:55 +01:00
|
|
|
pub websocket_send: Arc<Mutex<Sink>>,
|
2023-11-19 19:12:29 +01:00
|
|
|
/// Tells gateway tasks to close
|
|
|
|
pub(super) kill_send: tokio::sync::broadcast::Sender<()>,
|
|
|
|
pub(crate) store: Arc<Mutex<HashMap<Snowflake, Arc<RwLock<ObservableObject>>>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GatewayHandle {
|
|
|
|
/// Sends json to the gateway with an opcode
|
|
|
|
async fn send_json_event(&self, op_code: u8, to_send: serde_json::Value) {
|
|
|
|
let gateway_payload = types::GatewaySendPayload {
|
|
|
|
op_code,
|
|
|
|
event_data: Some(to_send),
|
|
|
|
sequence_number: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let payload_json = serde_json::to_string(&gateway_payload).unwrap();
|
|
|
|
let message = GatewayMessage(payload_json);
|
|
|
|
|
|
|
|
self.websocket_send
|
|
|
|
.lock()
|
|
|
|
.await
|
|
|
|
.send(message.into())
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
2024-01-21 20:13:00 +01:00
|
|
|
/// Recursively observes a [`Shared`] object, by making sure all [`Composite `] fields within
|
|
|
|
/// that object and its children are being watched.
|
|
|
|
///
|
|
|
|
/// Observing means, that if new information arrives about the observed object or its children,
|
|
|
|
/// the object automatically gets updated, without you needing to request new information about
|
|
|
|
/// the object in question from the API, which is expensive and can lead to rate limiting.
|
|
|
|
///
|
|
|
|
/// The [`Shared`] object returned by this method points to a different object than the one
|
|
|
|
/// being supplied as a &self function argument.
|
2023-11-19 19:12:29 +01:00
|
|
|
pub async fn observe<T: Updateable + Clone + Debug + Composite<T>>(
|
|
|
|
&self,
|
2024-01-21 17:07:19 +01:00
|
|
|
object: Shared<T>,
|
|
|
|
) -> Shared<T> {
|
2023-11-19 19:12:29 +01:00
|
|
|
let mut store = self.store.lock().await;
|
|
|
|
let id = object.read().unwrap().id();
|
|
|
|
if let Some(channel) = store.get(&id) {
|
|
|
|
let object = channel.clone();
|
|
|
|
drop(store);
|
|
|
|
object
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.downcast_ref::<T>()
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
panic!(
|
|
|
|
"Snowflake {} already exists in the store, but it is not of type T.",
|
|
|
|
id
|
|
|
|
)
|
|
|
|
});
|
|
|
|
let ptr = Arc::into_raw(object.clone());
|
|
|
|
// SAFETY:
|
|
|
|
// - We have just checked that the typeid of the `dyn Any ...` matches that of `T`.
|
|
|
|
// - This operation doesn't read or write any shared data, and thus cannot cause a data race
|
|
|
|
// - The reference count is not being modified
|
|
|
|
let downcasted = unsafe { Arc::from_raw(ptr as *const RwLock<T>).clone() };
|
|
|
|
let object = downcasted.read().unwrap().clone();
|
|
|
|
|
|
|
|
let watched_object = object.watch_whole(self).await;
|
|
|
|
*downcasted.write().unwrap() = watched_object;
|
|
|
|
downcasted
|
|
|
|
} else {
|
|
|
|
let id = object.read().unwrap().id();
|
|
|
|
let object = object.read().unwrap().clone();
|
|
|
|
let object = object.clone().watch_whole(self).await;
|
|
|
|
let wrapped = Arc::new(RwLock::new(object));
|
|
|
|
store.insert(id, wrapped.clone());
|
|
|
|
wrapped
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Recursively observes and updates all updateable fields on the struct T. Returns an object `T`
|
|
|
|
/// with all of its observable fields being observed.
|
|
|
|
pub async fn observe_and_into_inner<T: Updateable + Clone + Debug + Composite<T>>(
|
|
|
|
&self,
|
2024-01-21 17:07:19 +01:00
|
|
|
object: Shared<T>,
|
2023-11-19 19:12:29 +01:00
|
|
|
) -> T {
|
|
|
|
let channel = self.observe(object.clone()).await;
|
|
|
|
let object = channel.read().unwrap().clone();
|
|
|
|
object
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends an identify event to the gateway
|
|
|
|
pub async fn send_identify(&self, to_send: types::GatewayIdentifyPayload) {
|
|
|
|
let to_send_value = serde_json::to_value(&to_send).unwrap();
|
|
|
|
|
|
|
|
trace!("GW: Sending Identify..");
|
|
|
|
|
|
|
|
self.send_json_event(GATEWAY_IDENTIFY, to_send_value).await;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends a resume event to the gateway
|
|
|
|
pub async fn send_resume(&self, to_send: types::GatewayResume) {
|
|
|
|
let to_send_value = serde_json::to_value(&to_send).unwrap();
|
|
|
|
|
|
|
|
trace!("GW: Sending Resume..");
|
|
|
|
|
|
|
|
self.send_json_event(GATEWAY_RESUME, to_send_value).await;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends an update presence event to the gateway
|
|
|
|
pub async fn send_update_presence(&self, to_send: types::UpdatePresence) {
|
|
|
|
let to_send_value = serde_json::to_value(&to_send).unwrap();
|
|
|
|
|
|
|
|
trace!("GW: Sending Update Presence..");
|
|
|
|
|
|
|
|
self.send_json_event(GATEWAY_UPDATE_PRESENCE, to_send_value)
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends a request guild members to the server
|
|
|
|
pub async fn send_request_guild_members(&self, to_send: types::GatewayRequestGuildMembers) {
|
|
|
|
let to_send_value = serde_json::to_value(&to_send).unwrap();
|
|
|
|
|
|
|
|
trace!("GW: Sending Request Guild Members..");
|
|
|
|
|
|
|
|
self.send_json_event(GATEWAY_REQUEST_GUILD_MEMBERS, to_send_value)
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends an update voice state to the server
|
|
|
|
pub async fn send_update_voice_state(&self, to_send: types::UpdateVoiceState) {
|
|
|
|
let to_send_value = serde_json::to_value(to_send).unwrap();
|
|
|
|
|
|
|
|
trace!("GW: Sending Update Voice State..");
|
|
|
|
|
|
|
|
self.send_json_event(GATEWAY_UPDATE_VOICE_STATE, to_send_value)
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends a call sync to the server
|
|
|
|
pub async fn send_call_sync(&self, to_send: types::CallSync) {
|
|
|
|
let to_send_value = serde_json::to_value(&to_send).unwrap();
|
|
|
|
|
|
|
|
trace!("GW: Sending Call Sync..");
|
|
|
|
|
|
|
|
self.send_json_event(GATEWAY_CALL_SYNC, to_send_value).await;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sends a Lazy Request
|
|
|
|
pub async fn send_lazy_request(&self, to_send: types::LazyRequest) {
|
|
|
|
let to_send_value = serde_json::to_value(&to_send).unwrap();
|
|
|
|
|
|
|
|
trace!("GW: Sending Lazy Request..");
|
|
|
|
|
|
|
|
self.send_json_event(GATEWAY_LAZY_REQUEST, to_send_value)
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Closes the websocket connection and stops all gateway tasks;
|
|
|
|
///
|
2024-01-31 22:27:53 +01:00
|
|
|
/// Essentially pulls the plug on the gateway, leaving it possible to resume;
|
2023-11-19 19:12:29 +01:00
|
|
|
pub async fn close(&self) {
|
|
|
|
self.kill_send.send(()).unwrap();
|
|
|
|
self.websocket_send.lock().await.close().await.unwrap();
|
|
|
|
}
|
|
|
|
}
|