use std::sync::Arc;
use dashmap::DashMap;
use crate::types::steam_id::SteamID;
use super::lobby::{Lobby, Member};
#[derive(Debug, Default)]
pub struct LobbyCache {
lobbies: DashMap<u32, Arc<DashMap<SteamID, Lobby>>>,
}
impl LobbyCache {
pub fn new() -> Self {
Self {
lobbies: DashMap::new(),
}
}
pub fn get_lobby(&self, app_id: u32, lobby_steam_id: SteamID) -> Option<Lobby> {
self.app_lobbies(app_id)
.get(&lobby_steam_id)
.map(|lobby| lobby.clone())
}
pub fn cache_lobby(&self, app_id: u32, lobby: Lobby) {
self.app_lobbies(app_id).insert(lobby.steam_id(), lobby);
}
pub fn add_lobby_member(
&self,
app_id: u32,
lobby: &Lobby,
member_id: SteamID,
persona_name: &str,
) -> Option<Member> {
if lobby
.members()
.iter()
.any(|member| member.steam_id() == member_id)
{
return None;
}
let added_member = Member::new(member_id, persona_name, None);
let mut members = Vec::with_capacity(lobby.members().len() + 1);
members.extend_from_slice(lobby.members());
members.push(added_member.clone());
self.update_lobby_members(app_id, lobby, Some(members));
Some(added_member)
}
pub fn remove_lobby_member(
&self,
app_id: u32,
lobby: &Lobby,
member_id: SteamID,
) -> Option<Member> {
let removed_member = lobby
.members()
.iter()
.find(|member| member.steam_id() == member_id)
.cloned()?;
let members: Vec<Member> = lobby
.members()
.iter()
.filter(|member| member.steam_id() != removed_member.steam_id())
.cloned()
.collect();
if !members.is_empty() {
self.update_lobby_members(app_id, lobby, Some(members));
} else {
self.delete_lobby(app_id, lobby.steam_id());
}
Some(removed_member)
}
pub fn clear_lobby_members(&self, app_id: u32, lobby_steam_id: SteamID) {
let Some(lobby) = self.get_lobby(app_id, lobby_steam_id) else {
return;
};
self.update_lobby_members_with_owner(app_id, &lobby, lobby.owner_steam_id(), None);
}
pub fn update_lobby_owner(&self, app_id: u32, lobby_steam_id: SteamID, owner_steam_id: SteamID) {
let Some(lobby) = self.get_lobby(app_id, lobby_steam_id) else {
return;
};
let members = lobby.members().to_vec();
self.update_lobby_members_with_owner(app_id, &lobby, Some(owner_steam_id), Some(members));
}
pub fn update_lobby_members(
&self,
app_id: u32,
lobby: &Lobby,
members: Option<Vec<Member>>,
) {
self.update_lobby_members_with_owner(app_id, lobby, lobby.owner_steam_id(), members);
}
pub fn clear(&self) {
self.lobbies.clear();
}
fn update_lobby_members_with_owner(
&self,
app_id: u32,
lobby: &Lobby,
owner: Option<SteamID>,
members: Option<Vec<Member>>,
) {
self.cache_lobby(
app_id,
Lobby::new(
lobby.steam_id(),
lobby.lobby_type(),
lobby.lobby_flags(),
owner,
Some(lobby.metadata().clone()),
lobby.max_members(),
lobby.num_members(),
members,
lobby.distance(),
lobby.weight(),
),
);
}
fn app_lobbies(&self, app_id: u32) -> Arc<DashMap<SteamID, Lobby>> {
self.lobbies
.entry(app_id)
.or_insert_with(|| Arc::new(DashMap::new()))
.clone()
}
fn delete_lobby(&self, app_id: u32, lobby_steam_id: SteamID) -> Option<Lobby> {
let app_lobbies = self.lobbies.get(&app_id)?;
app_lobbies.remove(&lobby_steam_id).map(|(_, lobby)| lobby)
}
}