Skip to main content

antenna_client_web/peer/
mod.rs

1use std::{cell::RefCell, collections::HashSet, rc::Rc};
2
3use crate::{Driver, JsEventCallback, Storage};
4use antenna_client_shared::{Event, IceServerConfig, RtcCallbacks, STORAGE_IDENTITY_KEY};
5use antenna_protocol::{PeerID, UserMsgPayload};
6use anyhow::Result;
7use wasm_bindgen::closure::Closure;
8
9/// User-facing handle to a mesh peer running in the browser.
10pub struct Peer<Msg>
11where
12    Msg: UserMsgPayload + 'static,
13{
14    driver: Rc<RefCell<Driver<Msg>>>,
15    callbacks: Rc<RefCell<RtcCallbacks<Msg>>>,
16    _callback_buffer: Vec<JsEventCallback>,
17}
18
19impl<Msg> Drop for Peer<Msg>
20where
21    Msg: UserMsgPayload + 'static,
22{
23    fn drop(&mut self) {
24        self.leave();
25    }
26}
27
28impl<Msg> Default for Peer<Msg>
29where
30    Msg: UserMsgPayload + 'static,
31{
32    fn default() -> Self {
33        Self::new()
34    }
35}
36
37impl<Msg> Peer<Msg>
38where
39    Msg: UserMsgPayload + 'static,
40{
41    pub fn new() -> Self {
42        Self::with_ice_servers(IceServerConfig::default_stun())
43    }
44
45    pub fn with_ice_servers(ice_servers: Vec<IceServerConfig>) -> Self {
46        Self::with_storage(ice_servers, Storage::new(STORAGE_IDENTITY_KEY))
47    }
48
49    pub fn with_storage(ice_servers: Vec<IceServerConfig>, storage: Storage) -> Self {
50        let callbacks = Rc::new(RefCell::new(RtcCallbacks::new()));
51        let driver = Rc::new(RefCell::new(Driver::new(
52            ice_servers,
53            callbacks.clone(),
54            storage,
55        )));
56
57        let window = web_sys::window().expect("no global window");
58        let cb = Closure::<dyn FnMut()>::new({
59            let driver = driver.clone();
60            move || {
61                Driver::leave(driver.clone());
62            }
63        });
64        let _callback_buffer = vec![JsEventCallback::new(window.into(), "beforeunload", cb)];
65
66        Self {
67            driver,
68            callbacks,
69            _callback_buffer,
70        }
71    }
72
73    pub fn my_id(&self) -> PeerID {
74        *self.driver.borrow().id()
75    }
76
77    pub fn subscribe(&self, subscription: Event<Msg>) -> u64 {
78        self.callbacks.borrow_mut().subscribe(subscription)
79    }
80
81    pub fn unsubscribe(&self, id: u64) -> bool {
82        self.callbacks.borrow_mut().unsubscribe(id)
83    }
84
85    pub async fn start(&self) -> Result<String> {
86        Driver::start(self.driver.clone()).await
87    }
88
89    pub async fn receive_offer(&self, offer: &str) -> Result<String> {
90        Driver::receive_offer(self.driver.clone(), offer).await
91    }
92
93    pub async fn receive_answer(&self, answer: &str) -> Result<()> {
94        Driver::receive_answer(self.driver.clone(), answer).await
95    }
96
97    pub fn send(&self, peer_id: PeerID, data: Msg) {
98        Driver::send(self.driver.clone(), peer_id, data);
99    }
100
101    pub fn broadcast(&self, data: Msg) {
102        Driver::broadcast(self.driver.clone(), data);
103    }
104
105    pub fn leave(&self) {
106        Driver::leave(self.driver.clone());
107    }
108
109    pub fn is_connected(&self, peer_id: PeerID) -> bool {
110        self.driver.borrow().is_connected(&peer_id)
111    }
112
113    pub fn connected_peers(&self) -> HashSet<String> {
114        self.driver
115            .borrow()
116            .connected_peers()
117            .iter()
118            .map(|p| p.to_string())
119            .collect()
120    }
121}