feat: make VCsWatcher, a watch channel of VCs
This commit is contained in:
@@ -67,10 +67,10 @@ fn get_guild_and_voice_channel_id(
|
||||
.and_then(|member| member.user.as_ref().map(|user| user.id))
|
||||
.context(NoUserSnafu)?;
|
||||
|
||||
let voice_channel_id = vcs
|
||||
.with_guild(guild_id, |guild_vcs| {
|
||||
guild_vcs.get_left_for(&user_id).copied()
|
||||
})
|
||||
let &voice_channel_id = vcs
|
||||
.get(&guild_id)
|
||||
.context(UserNotInVCSnafu)?
|
||||
.get_left_for(&user_id)
|
||||
.context(UserNotInVCSnafu)?;
|
||||
|
||||
Ok((guild_id, voice_channel_id))
|
||||
@@ -236,9 +236,9 @@ impl EventHandler for Handler {
|
||||
|
||||
#[tracing::instrument(skip(state))]
|
||||
pub async fn handle(state: State, interaction: Interaction) {
|
||||
let vcs = state.vcs;
|
||||
|
||||
let (guild_id, voice_channel_id) = match get_guild_and_voice_channel_id(&interaction, &vcs) {
|
||||
let guild_and_voice_channel_id_res = get_guild_and_voice_channel_id(&interaction, &state.vcs_watcher.borrow());
|
||||
let (guild_id, voice_channel_id) =
|
||||
match guild_and_voice_channel_id_res {
|
||||
Ok((guild_id, voice_channel_id)) => (guild_id, voice_channel_id),
|
||||
Err(error) => {
|
||||
state
|
||||
|
||||
@@ -55,10 +55,10 @@ pub fn get_user_and_guild_and_voice_channel_id(
|
||||
|
||||
let guild_id = interaction.guild_id.context(NotInGuildSnafu)?;
|
||||
|
||||
let voice_channel_id = vcs
|
||||
.with_guild(guild_id, |guild_vcs| {
|
||||
guild_vcs.get_left_for(&bot_user_id).copied()
|
||||
})
|
||||
let &voice_channel_id = vcs
|
||||
.get(&guild_id)
|
||||
.context(BotNotInVCSnafu)?
|
||||
.get_left_for(&bot_user_id)
|
||||
.context(BotNotInVCSnafu)?;
|
||||
|
||||
Ok((user_id, guild_id, voice_channel_id))
|
||||
@@ -80,11 +80,12 @@ fn get_guild_and_vc_error_to_embed(error: GetGuildAndVoiceChannelIdError) -> Emb
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn handle(state: State, interaction: Interaction) {
|
||||
let (user_id, guild_id, voice_channel_id) = match get_user_and_guild_and_voice_channel_id(
|
||||
let user_and_guild_and_voice_channel_id_res = get_user_and_guild_and_voice_channel_id(
|
||||
state.discord_user_id,
|
||||
&interaction,
|
||||
&state.vcs,
|
||||
) {
|
||||
&state.vcs_watcher.borrow(),
|
||||
);
|
||||
let (user_id, guild_id, voice_channel_id) = match user_and_guild_and_voice_channel_id_res {
|
||||
Ok((user_id, guild_id, voice_channel_id)) => (user_id, guild_id, voice_channel_id),
|
||||
Err(error) => {
|
||||
state
|
||||
|
||||
@@ -16,7 +16,7 @@ use twilight_model::{
|
||||
},
|
||||
};
|
||||
|
||||
use crate::{BotDataManager, GuildVoiceChannelToTextChannel, UserDataManager, VCs};
|
||||
use crate::{BotDataManager, GuildVoiceChannelToTextChannel, UserDataManager, VCs, track_vcs::VCsWatcher};
|
||||
|
||||
pub mod info;
|
||||
pub mod join;
|
||||
@@ -42,7 +42,7 @@ pub struct State {
|
||||
pub recording_data: Operator,
|
||||
pub songbird: Arc<Songbird>,
|
||||
pub user_data_manager: UserDataManager,
|
||||
pub vcs: Arc<VCs>,
|
||||
pub vcs_watcher: VCsWatcher,
|
||||
}
|
||||
|
||||
type Return = ();
|
||||
|
||||
@@ -20,6 +20,6 @@ pub use one_to_many_with_data::OneToManyUniqueBTreeMapWithData;
|
||||
pub use one_to_one::OneToOneBTreeMap;
|
||||
pub use operator_ext::OperatorExt;
|
||||
pub use storage::Storage;
|
||||
pub use track_vcs::{GuildVoiceChannelToTextChannel, VCs, initialize_vcs, update_vcs};
|
||||
pub use track_vcs::{GuildVoiceChannelToTextChannel, VCs, VCsWatcher, initialize_vcs, update_vcs};
|
||||
pub use user_data::UserDataManager;
|
||||
pub use vc_user::{UserInVCData, VoiceStatus};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use clap::Parser;
|
||||
use fomo_reducer::{
|
||||
BotDataManager, CommandRouter, GuildVoiceChannelToTextChannel, State, Storage, UserDataManager,
|
||||
all_commands, command, initialize_vcs, update_vcs,
|
||||
BotDataManager, CommandRouter, GuildVoiceChannelToTextChannel, State, Storage, UserDataManager, VCsWatcher, all_commands, command, initialize_vcs, update_vcs
|
||||
};
|
||||
use secrecy::{ExposeSecret, SecretString};
|
||||
use snafu::{OptionExt, ResultExt, Snafu};
|
||||
@@ -316,7 +315,7 @@ async fn main() -> Result<(), MainError> {
|
||||
|
||||
let discord_client = Arc::new(discord_client);
|
||||
let songbird = Arc::new(songbird);
|
||||
let vcs = Arc::new(vcs);
|
||||
let vcs_watcher = VCsWatcher::new(vcs);
|
||||
|
||||
let bot_data = bot_data.into_inner();
|
||||
let recording_data = recording_data.into_inner();
|
||||
@@ -358,7 +357,7 @@ async fn main() -> Result<(), MainError> {
|
||||
recording_data,
|
||||
songbird,
|
||||
user_data_manager,
|
||||
vcs,
|
||||
vcs_watcher,
|
||||
};
|
||||
|
||||
if let Some(discord_status) = discord_status {
|
||||
@@ -455,7 +454,7 @@ async fn handle_event(command_router: Arc<CommandRouter>, state: State, event: E
|
||||
|
||||
match event {
|
||||
Event::VoiceStateUpdate(voice_state_update) => {
|
||||
update_vcs(&voice_state_update, &state.vcs);
|
||||
state.vcs_watcher.send_modify(|vcs| update_vcs(&voice_state_update, vcs));
|
||||
}
|
||||
Event::InteractionCreate(interaction_create) => {
|
||||
let InteractionCreate(interaction) = *interaction_create;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user