use crate::handle::ConnectionHandle;
use std::fmt::Debug;
use std::{collections::HashMap, sync::Arc};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::sync::mpsc::Sender;
#[derive(Debug)]
pub struct Room<T>
where
T: AsyncRead + AsyncWrite + Unpin + Send + Debug + 'static,
{
pub(crate) room_clients: HashMap<u64, ConnectionHandle<T>>,
pub(crate) room_name: String,
}
impl<T> Room<T>
where
T: AsyncRead + AsyncWrite + Unpin + Send + Debug + 'static,
{
pub fn new() -> Self {
Self {
room_clients: HashMap::new(),
room_name: String::new(),
}
}
pub async fn text(&self, text: &str) {
let clients: Vec<ConnectionHandle<T>> = self.room_clients.values().cloned().collect();
for h in clients {
if let Err(e) = h.send_text(text).await {
eprintln!(
"room[{}] text broadcast failed to {}: {}",
self.room_name,
h.id(),
e
);
}
}
}
pub async fn binary(&self, bytes: &[u8]) {
let payload = bytes.to_vec();
let clients: Vec<ConnectionHandle<T>> = self.room_clients.values().cloned().collect();
for h in clients {
if let Err(e) = h.send_binary(payload.clone()).await {
eprintln!(
"room[{}] binary broadcast failed to {}: {}",
self.room_name,
h.id(),
e
);
}
}
}
}
#[derive(Debug)]
pub enum RoomEvents<T>
where
T: AsyncRead + AsyncWrite + Unpin + Debug + Send + 'static,
{
JoinRoom {
client_id: u64,
handle: ConnectionHandle<T>,
room_name: String,
},
TextMessage {
client_id: u64,
room_name: String,
text: String,
},
EmitTextMessage {
client_id: u64,
room_name: String,
text: String,
},
BinaryMessage {
client_id: u64,
room_name: String,
bytes: Vec<u8>,
},
EmitBinaryMessage {
client_id: u64,
room_name: String,
bytes: Vec<u8>,
},
LeaveRoom {
client_id: u64,
room_name: String,
},
}
pub struct RoomMethods<'room_sender, T>
where
T: AsyncRead + AsyncWrite + Unpin + Debug + Send + 'static,
{
pub(crate) room_name: String,
pub(crate) room_sender: Arc<&'room_sender Sender<RoomEvents<T>>>,
pub(crate) id: u64,
}
impl<T> RoomMethods<'_, T>
where
T: AsyncRead + AsyncWrite + Unpin + Debug + Send + 'static,
{
pub async fn text(&self, text: &str) -> Result<(), std::io::Error> {
self.room_sender
.send(RoomEvents::TextMessage {
client_id: self.id,
room_name: self.room_name.clone(),
text: text.into(),
})
.await
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Failed to send text to room: {}", e),
)
})?;
Ok(())
}
pub async fn emit_text(&self, text: &str) -> Result<(), std::io::Error> {
self.room_sender
.send(RoomEvents::EmitTextMessage {
client_id: self.id,
room_name: self.room_name.clone(),
text: text.into(),
})
.await
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Failed to emit text to room: {}", e),
)
})?;
Ok(())
}
pub async fn binary(&self, bytes: &[u8]) -> Result<(), std::io::Error> {
self.room_sender
.send(RoomEvents::BinaryMessage {
client_id: self.id,
room_name: self.room_name.clone(),
bytes: bytes.into(),
})
.await
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Failed to send binary to room: {}", e),
)
})?;
Ok(())
}
pub async fn emit_binary(&self, bytes: &[u8]) -> Result<(), std::io::Error> {
self.room_sender
.send(RoomEvents::EmitBinaryMessage {
client_id: self.id,
room_name: self.room_name.clone(),
bytes: bytes.into(),
})
.await
.map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("Failed to emit binary to room: {}", e),
)
})?;
Ok(())
}
}