From 5e989289bd68d31bd6a5b1fefd3bcf497b39b564 Mon Sep 17 00:00:00 2001 From: Jacob Date: Sun, 31 May 2026 14:24:09 -0400 Subject: [PATCH] feat: don't block bot startup waiting to initialize vcs --- src/main.rs | 11 ++++---- src/track_vcs.rs | 71 ++++++++++++++++++++++-------------------------- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8608ed6..397f119 100644 --- a/src/main.rs +++ b/src/main.rs @@ -285,14 +285,14 @@ async fn main() -> Result<(), MainError> { let discord_opt_in_command_name = discord_opt_in_command.name.into(); let discord_opt_out_command_name = discord_opt_out_command.name.into(); - let vcs = initialize_vcs(&discord_client).await; - let command_router = CommandRouter::from_iter(commands); let command_router = Arc::new(command_router); let discord_client = Arc::new(discord_client); let songbird = Arc::new(songbird); - let vcs_sender = VCsSender::new(vcs); + let vcs_sender = VCsSender::new(Default::default()); + + let initializing_vcs = initialize_vcs(&vcs_sender, &discord_client); let bot_data = bot_data.into_inner(); let recording_data = recording_data.into_inner(); @@ -327,7 +327,7 @@ async fn main() -> Result<(), MainError> { cancellation_token: cancellation_token.clone(), discord_application_id, discord_bot_owner_user_id, - discord_client, + discord_client: discord_client.clone(), discord_info_command_id, discord_info_command_name, discord_opt_in_command_id, @@ -340,7 +340,7 @@ async fn main() -> Result<(), MainError> { render_manager, songbird, user_manager, - vcs_sender, + vcs_sender: vcs_sender.clone(), }; let heat_seeking = tokio::spawn(heat_seek(state.clone())); @@ -394,6 +394,7 @@ async fn main() -> Result<(), MainError> { }); let finished_naturally = async move { + initializing_vcs.await; heat_seeking.await.unwrap(); run_shards.await; }; diff --git a/src/track_vcs.rs b/src/track_vcs.rs index 6586a11..3f46266 100644 --- a/src/track_vcs.rs +++ b/src/track_vcs.rs @@ -20,76 +20,69 @@ pub type VCsInGuild = pub type VCs = BTreeMap, VCsInGuild>; pub type VCsSender = watch::Sender; -#[tracing::instrument(skip(discord_client), ret)] +#[tracing::instrument(skip(vcs_sender, discord_client))] async fn initialize_user_in_vc( + vcs_sender: &VCsSender, discord_client: &twilight_http::Client, guild_id: Id, user_id: Id, -) -> Option<(Id, UserInVCData)> { +) { if let Ok(voice_state_res) = discord_client.user_voice_state(guild_id, user_id).await && let Ok(voice_state) = voice_state_res.model().await { tracing::info!(?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(voice_channel_id) = voice_state.channel_id { + 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(); - voice_state - .channel_id - .map(|channel_id| (channel_id, user_in_vc_data)) - } else { - None // TODO + vcs_sender.send_modify(|vcs| { + vcs.entry(guild_id) + .or_default() + .insert(voice_channel_id, user_id, user_in_vc_data); + }); + } } } -#[tracing::instrument(skip(discord_client), ret)] +#[tracing::instrument(skip(vcs_sender, discord_client))] async fn initialize_server_vcs( + vcs_sender: &VCsSender, discord_client: &twilight_http::Client, id: Id, -) -> VCsInGuild { +) { if let Ok(guild_members_res) = discord_client.guild_members(id).limit(999).await && let Ok(guild_members) = guild_members_res.model().await { - FuturesUnordered::from_iter(guild_members.into_iter().map(|member| async move { - ( - member.user.id, - initialize_user_in_vc(discord_client, id, member.user.id).await, - ) - })) - .filter_map( - |(user_id, channel_id_and_user_in_vc_data_option)| async move { - channel_id_and_user_in_vc_data_option - .map(|(channel_id, user_in_vc_data)| (channel_id, user_id, user_in_vc_data)) - }, + FuturesUnordered::from_iter( + guild_members.into_iter().map(|member| { + initialize_user_in_vc(vcs_sender, discord_client, id, member.user.id) + }), ) .collect() .await - } else { - Default::default() } } #[tracing::instrument(skip(discord_client), ret)] -pub async fn initialize_vcs(discord_client: &twilight_http::Client) -> VCs { +pub async fn initialize_vcs(vcs_sender: &VCsSender, discord_client: &twilight_http::Client) { if let Ok(guilds_res) = discord_client.current_user_guilds().limit(200).await && let Ok(guilds) = guilds_res.model().await { - FuturesUnordered::from_iter(guilds.into_iter().map(|guild| async move { - let guild_vcs = initialize_server_vcs(discord_client, guild.id).await; - - (guild.id, guild_vcs) - })) + FuturesUnordered::from_iter( + guilds + .into_iter() + .map(|guild| initialize_server_vcs(vcs_sender, discord_client, guild.id)), + ) .collect() .await - } else { - Default::default() } }