aboutsummaryrefslogtreecommitdiff
path: root/client-native-lib/src/instance.rs
diff options
context:
space:
mode:
Diffstat (limited to 'client-native-lib/src/instance.rs')
-rw-r--r--client-native-lib/src/instance.rs136
1 files changed, 136 insertions, 0 deletions
diff --git a/client-native-lib/src/instance.rs b/client-native-lib/src/instance.rs
new file mode 100644
index 0000000..b3688c3
--- /dev/null
+++ b/client-native-lib/src/instance.rs
@@ -0,0 +1,136 @@
+/*
+ This file is part of keks-meet (https://codeberg.org/metamuffin/keks-meet)
+ which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
+ Copyright (C) 2022 metamuffin <metamuffin@disroot.org>
+*/
+use crate::{
+ build_api,
+ crypto::{self, Key},
+ peer::Peer,
+ protocol::{self, ClientboundPacket, RelayMessage, RelayMessageWrapper, ServerboundPacket},
+ signaling::{self, SignalingConnection},
+ Config, EventHandler, LocalResource,
+};
+use futures_util::{SinkExt, StreamExt};
+use log::{debug, info, warn};
+use std::{collections::HashMap, sync::Arc};
+use tokio::sync::RwLock;
+use webrtc::api::API;
+
+pub struct Instance {
+ pub event_handler: Box<dyn EventHandler>,
+ pub conn: SignalingConnection,
+ pub config: Config,
+ pub api: API,
+ pub key: Key,
+ local_resources: RwLock<HashMap<String, Box<dyn LocalResource>>>,
+ my_id: RwLock<Option<usize>>,
+ pub peers: RwLock<HashMap<usize, Arc<Peer>>>,
+}
+impl Instance {
+ pub async fn new(config: Config, event_handler: Box<dyn EventHandler>) -> Arc<Self> {
+ let conn = signaling::SignalingConnection::new(&config.signaling_uri, &config.secret).await;
+ let key = crypto::Key::derive(&config.secret);
+
+ Arc::new(Self {
+ event_handler,
+ api: build_api(),
+ my_id: RwLock::new(None),
+ peers: Default::default(),
+ local_resources: Default::default(),
+ config,
+ conn,
+ key,
+ })
+ }
+
+ pub async fn my_id(&self) -> usize {
+ self.my_id.read().await.expect("not initialized yet")
+ }
+
+ pub async fn receive_loop(self: Arc<Self>) {
+ while let Some(packet) = self.conn.recv.write().await.next().await {
+ debug!("{packet:?}");
+ let inst = self.clone();
+ inst.on_message(packet).await
+ }
+ }
+
+ pub async fn on_message(self: Arc<Self>, packet: ClientboundPacket) {
+ match packet {
+ protocol::ClientboundPacket::Init { your_id, version } => {
+ info!("server is running {version:?}");
+ *self.my_id.write().await = Some(your_id);
+ }
+ protocol::ClientboundPacket::ClientJoin { id } => {
+ if id == self.my_id().await {
+ // we joined - YAY!
+ } else {
+ let peer = Peer::create(self.clone(), id).await;
+ self.peers.write().await.insert(id, peer.clone());
+ peer.send_relay(RelayMessage::Identify {
+ username: self.config.username.clone(),
+ })
+ .await;
+ }
+ }
+ protocol::ClientboundPacket::ClientLeave { id } => {
+ self.peers
+ .write()
+ .await
+ .remove(&id)
+ .unwrap()
+ .on_leave()
+ .await;
+ }
+ protocol::ClientboundPacket::Message { sender, message } => {
+ let message = self.key.decrypt(&message);
+ let p = serde_json::from_str::<RelayMessageWrapper>(&message).unwrap();
+ self.on_relay(sender, p.inner).await;
+ }
+ }
+ }
+
+ pub async fn on_relay(&self, sender: usize, p: RelayMessage) {
+ if let Some(peer) = self.peers.read().await.get(&sender).cloned() {
+ peer.on_relay(p).await
+ } else {
+ warn!("got a packet from a non-existent peer")
+ }
+ }
+
+ pub async fn send_relay(&self, recipient: usize, inner: RelayMessage) {
+ self.conn
+ .send
+ .write()
+ .await
+ .send(ServerboundPacket::Relay {
+ recipient: Some(recipient),
+ message: self.key.encrypt(
+ &serde_json::to_string(&RelayMessageWrapper {
+ sender: self.my_id.read().await.expect("not ready to relay yet.."),
+ inner,
+ })
+ .unwrap(),
+ ),
+ })
+ .await
+ .unwrap()
+ }
+
+ pub async fn add_local_resource(&self, res: Box<dyn LocalResource>) {
+ for (pid, peer) in self.peers.read().await.iter() {
+ peer.send_relay(RelayMessage::Provide(res.info()));
+ }
+ self.local_resources
+ .write()
+ .await
+ .insert(res.info().id, res);
+ }
+ pub async fn remove_local_resource(&self, id: String) {
+ self.local_resources.write().await.remove(&id);
+ for (pid, peer) in self.peers.read().await.iter() {
+ peer.send_relay(RelayMessage::ProvideStop { id: id.clone() });
+ }
+ }
+}