mod callbacks;
mod websocket_handler;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use wasm_bindgen::JsValue;
use wasm_peers_protocol::{SessionId, UserId};
use web_sys::{RtcDataChannel, RtcPeerConnection, WebSocket};
use crate::one_to_many::callbacks::{set_websocket_on_message, set_websocket_on_open};
use crate::ConnectionType;
#[derive(Debug, Clone)]
struct Connection {
peer_connection: RtcPeerConnection,
data_channel: Option<RtcDataChannel>,
}
impl Connection {
fn new(peer_connection: RtcPeerConnection, data_channel: Option<RtcDataChannel>) -> Self {
Connection {
peer_connection,
data_channel,
}
}
}
#[derive(Debug)]
struct NetworkManagerInner {
session_id: SessionId,
websocket: WebSocket,
connection_type: ConnectionType,
is_host: bool,
connections: HashMap<UserId, Connection>,
}
#[derive(Debug, Clone)]
pub(crate) struct NetworkManager {
inner: Rc<RefCell<NetworkManagerInner>>,
}
impl NetworkManager {
pub(crate) fn new(
signaling_server_url: &str,
session_id: SessionId,
connection_type: ConnectionType,
is_host: bool,
) -> Result<Self, JsValue> {
let websocket = WebSocket::new(signaling_server_url)?;
websocket.set_binary_type(web_sys::BinaryType::Arraybuffer);
Ok(NetworkManager {
inner: Rc::new(RefCell::new(NetworkManagerInner {
session_id,
websocket,
connection_type,
is_host,
connections: HashMap::new(),
})),
})
}
pub(crate) fn start(
&mut self,
on_open_callback: impl FnMut(UserId) + Clone + 'static,
on_message_callback: impl FnMut(UserId, String) + Clone + 'static,
) {
let websocket = self.inner.borrow().websocket.clone();
let session_id = self.inner.borrow().session_id.clone();
let is_host = self.inner.borrow().is_host;
set_websocket_on_open(&websocket, session_id, is_host);
set_websocket_on_message(
&websocket,
self.clone(),
on_open_callback,
on_message_callback,
is_host,
);
}
pub(crate) fn send_message(&self, user_id: UserId, message: &str) -> Result<(), JsValue> {
self.inner
.borrow()
.connections
.get(&user_id)
.ok_or_else(|| JsValue::from_str(&format!("no connection for user {}", user_id)))?
.data_channel
.as_ref()
.ok_or_else(|| {
JsValue::from_str(&format!("no data channel setup yet for user {}", user_id))
})?
.send_with_str(&format!("x{}", message))
}
pub(crate) fn send_message_to_all(&self, message: &str) {
for data_channel in self
.inner
.borrow()
.connections
.values()
.filter_map(|connection| connection.data_channel.as_ref())
{
let _ = data_channel
.send_with_str(&format!("x{}", message));
}
}
}
#[derive(Debug, Clone)]
pub struct MiniServer {
inner: NetworkManager,
}
impl MiniServer {
pub fn new(
signaling_server_url: &str,
session_id: SessionId,
connection_type: ConnectionType,
) -> Result<Self, JsValue> {
Ok(MiniServer {
inner: NetworkManager::new(signaling_server_url, session_id, connection_type, true)?,
})
}
pub fn start(
&mut self,
on_open_callback: impl FnMut(UserId) + Clone + 'static,
on_message_callback: impl FnMut(UserId, String) + Clone + 'static,
) {
self.inner.start(on_open_callback, on_message_callback);
}
pub fn send_message(&self, user_id: UserId, message: &str) -> Result<(), JsValue> {
self.inner.send_message(user_id, message)
}
pub fn send_message_to_all(&self, message: &str) {
self.inner.send_message_to_all(message)
}
}
#[derive(Debug, Clone)]
pub struct MiniClient {
inner: NetworkManager,
}
impl MiniClient {
pub fn new(
signaling_server_url: &str,
session_id: SessionId,
connection_type: ConnectionType,
) -> Result<Self, JsValue> {
Ok(MiniClient {
inner: NetworkManager::new(signaling_server_url, session_id, connection_type, false)?,
})
}
pub fn start(
&mut self,
mut on_open_callback: impl FnMut() + Clone + 'static,
mut on_message_callback: impl FnMut(String) + Clone + 'static,
) {
let on_open_callback = move |_| on_open_callback();
let on_message_callback = move |_, message| on_message_callback(message);
self.inner.start(on_open_callback, on_message_callback);
}
pub fn send_message_to_host(&self, message: &str) -> Result<(), JsValue> {
self.inner.send_message_to_all(message);
Ok(())
}
}