feat: make VCsWatcher, a watch channel of VCs

This commit is contained in:
2026-05-06 19:49:08 -04:00
parent fa88bd495f
commit fcd856b61a
6 changed files with 51 additions and 83 deletions

View File

@@ -1,6 +1,5 @@
use std::collections::BTreeMap;
use dashmap::DashMap;
use futures::{StreamExt, stream::FuturesUnordered};
use tokio::sync::watch;
use twilight_model::{
@@ -16,38 +15,9 @@ use crate::{OneToManyUniqueBTreeMapWithData, OneToOneBTreeMap, UserInVCData, Voi
pub type GuildVoiceChannelToTextChannel =
BTreeMap<Id<GuildMarker>, OneToOneBTreeMap<Id<ChannelMarker>, Id<ChannelMarker>>>;
type VCsInGuild = OneToManyUniqueBTreeMapWithData<Id<ChannelMarker>, Id<UserMarker>, UserInVCData>;
#[derive(Debug, Default)]
pub struct VCs(DashMap<Id<GuildMarker>, watch::Sender<VCsInGuild>>);
impl Extend<(Id<GuildMarker>, VCsInGuild)> for VCs {
fn extend<T: IntoIterator<Item = (Id<GuildMarker>, VCsInGuild)>>(&mut self, iter: T) {
for (id, guild_vcs) in iter {
self.0.insert(id, watch::Sender::new(guild_vcs));
}
}
}
impl VCs {
pub fn with_guild<R>(&self, id: Id<GuildMarker>, f: impl FnOnce(&VCsInGuild) -> R) -> R {
f(&*self.0.entry(id).or_default().borrow())
}
pub fn update_guild<R>(&self, id: Id<GuildMarker>, f: impl FnOnce(&mut VCsInGuild) -> R) -> R {
let mut ret_opt = None;
self.0.entry(id).or_default().send_modify(|guild_vcs| {
let ret = f(guild_vcs);
_ = ret_opt.insert(ret);
});
let ret = ret_opt.unwrap();
ret
}
pub fn subscribe_to_guild<R>(&self, id: Id<GuildMarker>) -> watch::Receiver<VCsInGuild> {
self.0.entry(id).or_default().subscribe()
}
}
pub type VCsInGuild = OneToManyUniqueBTreeMapWithData<Id<ChannelMarker>, Id<UserMarker>, UserInVCData>;
pub type VCs = BTreeMap<Id<GuildMarker>, VCsInGuild>;
pub type VCsWatcher = watch::Sender<VCs>;
#[tracing::instrument(skip(discord_client), ret)]
async fn initialize_user_in_vc(
@@ -123,7 +93,7 @@ pub async fn initialize_vcs(discord_client: &twilight_http::Client) -> VCs {
}
#[tracing::instrument(skip(vcs))]
pub fn update_vcs(voice_state_update: &VoiceStateUpdate, vcs: &VCs) {
pub fn update_vcs(voice_state_update: &VoiceStateUpdate, vcs: &mut VCs) {
let user_id = voice_state_update.user_id;
match voice_state_update.guild_id {
Some(guild_id) => match voice_state_update.channel_id {
@@ -138,9 +108,7 @@ pub fn update_vcs(voice_state_update: &VoiceStateUpdate, vcs: &VCs) {
.build();
let user_in_vc_data = voice_status.into();
vcs.update_guild(guild_id, |guild_vcs| {
guild_vcs.insert(channel_id, user_id, user_in_vc_data)
});
vcs.entry(guild_id).or_default().insert(channel_id, user_id, user_in_vc_data);
tracing::info!(
?guild_id,
@@ -151,7 +119,7 @@ pub fn update_vcs(voice_state_update: &VoiceStateUpdate, vcs: &VCs) {
}
None => {
vcs.update_guild(guild_id, |guild_vcs| guild_vcs.remove_right(&user_id));
vcs.entry(guild_id).or_default().remove_right(&user_id);
tracing::info!(?guild_id, ?user_id, "disconnected");
}