type VCsInServer = OneToManyUniqueBTreeMapWithData, Id, UserInVCData>; pub type VCs = BTreeMap, VCsInServer>; use std::collections::BTreeMap; use twilight_model::{ gateway::payload::incoming::VoiceStateUpdate, id::{ Id, marker::{ChannelMarker, GuildMarker, UserMarker}, }, }; use crate::{OneToManyUniqueBTreeMapWithData, UserInVCData, VoiceStatus}; #[tracing::instrument(skip(discord_client), ret)] pub async fn initialize_vcs(discord_client: &twilight_http::Client) -> VCs { let mut vcs = VCs::default(); if let Ok(guilds_res) = discord_client.current_user_guilds().limit(200).await && let Ok(guilds) = guilds_res.model().await { for guild in guilds { if let Ok(guild_members_res) = discord_client.guild_members(guild.id).limit(999).await && let Ok(guild_members) = guild_members_res.model().await { for member in guild_members { if let Ok(voice_state_res) = discord_client .user_voice_state(guild.id, member.user.id) .await && let Ok(voice_state) = voice_state_res.model().await { tracing::info!(?member.user.id, ?voice_state); let voice_status = VoiceStatus::builder() .self_deafened(voice_state.self_deaf) .self_muted(voice_state.self_mute) .server_deafened(voice_state.deaf) .server_muted(voice_state.mute) .camming(voice_state.self_video) .streaming(voice_state.self_stream) .build(); let user_in_vc_data = voice_status.into(); if let Some(channel_id) = voice_state.channel_id { vcs.entry(guild.id).or_default().insert( channel_id, member.user.id, user_in_vc_data, ); } } } } } } 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 { Some(channel_id) => { let voice_status = VoiceStatus::builder() .self_deafened(voice_state_update.self_deaf) .self_muted(voice_state_update.self_mute) .server_deafened(voice_state_update.deaf) .server_muted(voice_state_update.mute) .camming(voice_state_update.self_video) .streaming(voice_state_update.self_stream) .build(); let user_in_vc_data = voice_status.into(); vcs.entry(guild_id) .or_default() .insert(channel_id, user_id, user_in_vc_data); tracing::info!( ?guild_id, ?channel_id, ?user_id, "connected or otherwise changed state while connected" ); } None => { if let Some(channel_vcers) = vcs.get_mut(&guild_id) { channel_vcers.remove_right(&user_id); } tracing::info!(?guild_id, ?user_id, "disconnected"); } }, None => { tracing::error!("why doesn't this have a guild id attached?!"); } } }