watch-party-2/src/rooms.rs

96 lines
2.2 KiB
Rust

use std::{collections::HashMap, sync::Arc};
use axum::extract::ws::{Message, WebSocket};
use dashmap::DashMap;
use futures::{stream::SplitSink, SinkExt};
use once_cell::sync::Lazy;
use tokio::sync::{Mutex, MutexGuard};
use uuid::Uuid;
use crate::sources::MediaSource;
#[derive(Clone)]
pub struct RoomRef {
room: Arc<Mutex<Room>>,
}
impl RoomRef {
fn new(room: Room) -> Self {
RoomRef {
room: Arc::new(Mutex::new(room)),
}
}
pub async fn get(&self) -> MutexGuard<Room> {
self.room.lock().await
}
pub async fn add_member(&self, member: Member) {
let mut room = self.room.lock().await;
room.members.insert(member.id, member);
}
pub async fn broadcast(&self, message: Message) {
let mut room = self.room.lock().await;
for member in room.members.values_mut() {
member.send(message.clone()).await
}
}
pub async fn list_chat_members(&self) -> Vec<ChatIdentity> {
let room = self.room.lock().await;
room.members
.values()
.flat_map(|m| &m.chat_identity)
.cloned()
.collect()
}
}
static ROOMS: Lazy<DashMap<Uuid, RoomRef>> = Lazy::new(DashMap::new);
pub async fn create_room(playlist: Vec<MediaSource>) -> RoomRef {
let id = Uuid::new_v4();
let room = Room {
id,
playlist,
currently_playing: 0,
members: HashMap::new(),
};
let room_ref = RoomRef::new(room);
ROOMS.insert(id, room_ref.clone());
room_ref
}
pub async fn find_room(id: Uuid) -> Option<RoomRef> {
ROOMS.get(&id).as_deref().cloned()
}
pub struct Room {
pub id: Uuid,
pub playlist: Vec<MediaSource>,
pub currently_playing: usize,
pub members: HashMap<Uuid, Member>,
}
#[derive(Clone)]
pub struct ChatIdentity {
pub nickname: String,
pub color: String,
}
pub struct Member {
pub id: Uuid,
pub chat_identity: Option<ChatIdentity>,
pub connections: Vec<SplitSink<WebSocket, Message>>,
}
impl Member {
pub async fn send(&mut self, message: Message) {
for conn in self.connections.iter_mut() {
let _ = conn.send(message.clone()).await;
}
}
}