use std::sync::Arc;
use std::time::Duration;
use crate::client::{Client, Inner};
use crate::error::{Error, Result};
#[cfg(feature = "native")]
use std::sync::{mpsc, Mutex};
#[cfg(not(feature = "native"))]
use futures_channel::mpsc;
#[cfg(not(feature = "native"))]
use futures_util::lock::Mutex;
#[cfg(not(feature = "native"))]
use futures_util::StreamExt;
pub struct PacketConn {
inner: Arc<Inner>,
name: String,
#[cfg(feature = "native")]
rx: Mutex<mpsc::Receiver<(Vec<u8>, String)>>,
#[cfg(not(feature = "native"))]
rx: Mutex<mpsc::UnboundedReceiver<(Vec<u8>, String)>>,
}
impl Client {
pub fn listen_packet(&self, name: &str) -> PacketConn {
#[cfg(feature = "native")]
let (tx, rx) = mpsc::channel::<(Vec<u8>, String)>();
#[cfg(not(feature = "native"))]
let (tx, rx) = mpsc::unbounded::<(Vec<u8>, String)>();
let handler = move |msg: &spotproto::Message| {
if !msg.is_encrypted() {
return Err("invalid message: must be encrypted".to_string());
}
#[cfg(feature = "native")]
let _ = tx.send((msg.body.clone(), msg.sender.clone()));
#[cfg(not(feature = "native"))]
let _ = tx.unbounded_send((msg.body.clone(), msg.sender.clone()));
Ok(None)
};
self.inner()
.handlers
.write()
.unwrap()
.insert(name.to_string(), Arc::new(handler));
PacketConn {
inner: self.inner().clone(),
name: name.to_string(),
rx: Mutex::new(rx),
}
}
}
#[cfg(feature = "native")]
impl PacketConn {
pub fn recv(&self, timeout: Option<Duration>) -> Result<(Vec<u8>, String)> {
let rx = self.rx.lock().unwrap();
match timeout {
Some(dur) => rx.recv_timeout(dur).map_err(|e| match e {
mpsc::RecvTimeoutError::Timeout => Error::Timeout,
mpsc::RecvTimeoutError::Disconnected => Error::Closed,
}),
None => rx.recv().map_err(|_| Error::Closed),
}
}
pub fn send_to(&self, addr: &str, payload: &[u8], timeout: Duration) -> Result<()> {
self.inner.send_to_with_from(
addr,
payload,
&format!("/{}", self.name),
std::time::Instant::now() + timeout,
)
}
pub fn local_addr(&self) -> String {
format!("{}/{}", self.inner.target_id(), self.name)
}
}
#[cfg(not(feature = "native"))]
impl PacketConn {
pub async fn recv(&self, timeout: Option<Duration>) -> Result<(Vec<u8>, String)> {
let mut rx = self.rx.lock().await;
match timeout {
Some(dur) => match crate::conn_wasm::with_timeout(rx.next(), dur).await {
Some(Some(item)) => Ok(item),
Some(None) => Err(Error::Closed),
None => Err(Error::Timeout),
},
None => rx.next().await.ok_or(Error::Closed),
}
}
pub async fn send_to(&self, addr: &str, payload: &[u8], timeout: Duration) -> Result<()> {
self.inner
.send_to_with_from(addr, payload, &format!("/{}", self.name), timeout)
.await
}
pub fn local_addr(&self) -> String {
format!("{}/{}", self.inner.target_id(), self.name)
}
}
impl Drop for PacketConn {
fn drop(&mut self) {
self.inner.handlers.write().unwrap().remove(&self.name);
}
}