use std::collections::{HashMap, HashSet};
use super::conference::ConferenceMembership;
use super::state::SessionState;
use super::tracker::SessionTracker;
fn deindex(map: &mut HashMap<String, HashSet<String>>, key: &str, uuid: &str) {
if let Some(set) = map.get_mut(key) {
set.remove(uuid);
if set.is_empty() {
map.remove(key);
}
}
}
struct Change<T> {
old: Option<T>,
new: Option<T>,
}
fn reindex(map: &mut HashMap<String, HashSet<String>>, uuid: &str, change: Change<String>) {
if change.old == change.new {
return;
}
if let Some(old) = change.old {
deindex(map, &old, uuid);
}
if let Some(new) = change.new {
map.entry(new).or_default().insert(uuid.to_string());
}
}
#[derive(Default)]
pub(super) struct IndexedFields {
channel_name: Option<String>,
pending_bridge_target: Option<String>,
other_leg_uuid: Option<String>,
conference: Option<ConferenceMembership>,
}
impl IndexedFields {
pub(super) fn of(state: &SessionState) -> Self {
IndexedFields {
channel_name: state.channel_name.clone(),
pending_bridge_target: state.pending_bridge_target.clone(),
other_leg_uuid: state.other_leg_uuid.clone(),
conference: state.conference.clone(),
}
}
}
impl<I: Iterator<Item = String>> SessionTracker<I> {
pub(super) fn mutate_indexed(&mut self, uuid: &str, edit: impl FnOnce(&mut SessionState)) {
let state = self.sessions.entry(uuid.to_string()).or_default();
let old = IndexedFields::of(state);
edit(state);
let new = IndexedFields::of(state);
self.apply_index_changes(uuid, old, new);
}
pub(super) fn apply_index_changes(
&mut self,
uuid: &str,
old: IndexedFields,
new: IndexedFields,
) {
reindex(
&mut self.by_channel_name,
uuid,
Change {
old: old.channel_name,
new: new.channel_name,
},
);
reindex(
&mut self.by_pending_target,
uuid,
Change {
old: old.pending_bridge_target,
new: new.pending_bridge_target,
},
);
if old.other_leg_uuid != new.other_leg_uuid {
match new.other_leg_uuid {
Some(new_leg) => self.index_other_leg(uuid, old.other_leg_uuid, &new_leg),
None => {
if let Some(old_leg) = old.other_leg_uuid {
self.deindex_other_leg(&old_leg, uuid);
}
}
}
}
let same_seat = matches!(
(&old.conference, &new.conference),
(Some(o), Some(n)) if o.name == n.name && o.instance == n.instance
);
if !same_seat {
if let Some(old_conf) = old.conference {
self.conferences.leave(&old_conf.name, uuid);
}
if let Some(new_conf) = new.conference {
self.conferences
.join(&new_conf.name, &new_conf.instance, uuid);
}
}
}
fn index_other_leg(&mut self, uuid: &str, old_leg: Option<String>, new_leg: &str) {
if let Some(old) = old_leg {
if old != new_leg {
self.deindex_other_leg(&old, uuid);
}
}
self.by_other_leg
.insert(new_leg.to_string(), uuid.to_string());
}
fn deindex_other_leg(&mut self, key: &str, uuid: &str) {
if self.by_other_leg.get(key).is_some_and(|u| u == uuid) {
self.by_other_leg.remove(key);
}
}
}