diff --git a/src/command/join.rs b/src/command/join.rs index d871cc9..35c86e7 100644 --- a/src/command/join.rs +++ b/src/command/join.rs @@ -33,6 +33,16 @@ pub async fn handle(state: State, interaction: Interaction) { let guild_vcs = vcs.get(&guild_id).expect("TODO"); tracing::error!(?guild_vcs, "TODO"); - let user_in_vc_data = guild_vcs.get_left_and_data_for(&user_id); + let (&channel_id, user_in_vc_data) = guild_vcs.get_left_and_data_for(&user_id).expect("TODO"); tracing::error!(?user_in_vc_data, "TODO"); + + let call = tokio::spawn({ + let songbird = state.songbird.clone(); + async move { songbird.join(guild_id, channel_id).await } + }) + .await + .unwrap() + .expect("TODO"); + + tracing::error!(?call, "TODO"); } diff --git a/src/command/mod.rs b/src/command/mod.rs index ad0ce9a..3254fd6 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -2,6 +2,7 @@ use std::{fmt::Debug, sync::Arc}; use futures::future::BoxFuture; use patricia_tree::StringPatriciaMap; +use songbird::Songbird; use twilight_model::application::{command::Command, interaction::Interaction}; use crate::VCs; @@ -13,6 +14,7 @@ mod opt_out; #[derive(Debug, Clone)] pub struct State { pub vcs: Arc, + pub songbird: Arc, } type Return = (); diff --git a/src/main.rs b/src/main.rs index 2bd8947..4eaef2e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,10 @@ use clap::Parser; -use fomo_reducer::{CommandRouter, State, VCs, all_commands, initialize_vcs, update_vcs}; +use fomo_reducer::{CommandRouter, State, all_commands, initialize_vcs, update_vcs}; use opendal::{IntoOperatorUri, Operator, OperatorUri}; use secrecy::{ExposeSecret, SecretString}; use snafu::Snafu; -use songbird::shards::TwilightMap; -use std::{collections::HashMap, fmt::Debug, str::FromStr, sync::Arc}; +use songbird::{Songbird, shards::TwilightMap}; +use std::{fmt::Debug, str::FromStr, sync::Arc}; use tracing_subscriber::{EnvFilter, fmt::format::FmtSpan}; use twilight_gateway::{Event, EventTypeFlags, Intents, Shard, ShardId, StreamExt}; use twilight_model::{ @@ -62,7 +62,11 @@ struct AppArgs { #[derive(Parser)] struct LoggingArgs { - #[arg(long = "logging-directives", env = "RUST_LOG", default_value = "warn,fomo_reducer=debug")] + #[arg( + long = "logging-directives", + env = "RUST_LOG", + default_value = "warn,fomo_reducer=debug" + )] env_filter: EnvFilter, } @@ -106,20 +110,18 @@ async fn main() -> Result<(), MainError> { .install_default() .unwrap(); - let shard_id = ShardId::new(0, 1); - let intents = Intents::GUILD_VOICE_STATES; - let mut shard = Shard::new(shard_id, discord_token.expose_secret().to_owned(), intents); - - let senders = TwilightMap::new(FromIterator::from_iter([( - shard.id().number(), - shard.sender(), - )])); - - let event_types = EventTypeFlags::GUILD_VOICE_STATES | EventTypeFlags::INTERACTION_CREATE; - let mut next_event = shard.next_event(event_types); - let discord_client = twilight_http::Client::new(discord_token.expose_secret().to_owned()); + let user = discord_client + .current_user() + .await + .expect("couldn't fetch current user") // TODO + .model() + .await + .expect("couldn't deserialize current user"); // TODO + + let user_id = user.id; + let current_application = discord_client .current_user_application() .await @@ -132,6 +134,22 @@ async fn main() -> Result<(), MainError> { let application_id = current_application.id; + let shard_id = ShardId::new(0, 1); + let intents = Intents::GUILD_VOICE_STATES; + let mut shard = Shard::new(shard_id, discord_token.expose_secret().to_owned(), intents); + + let senders = TwilightMap::new(FromIterator::from_iter([( + shard.id().number(), + shard.sender(), + )])); + + let senders = Arc::new(senders); + + let songbird = Songbird::twilight(senders, user_id); + + let event_types = EventTypeFlags::GUILD_VOICE_STATES | EventTypeFlags::INTERACTION_CREATE; + let mut next_event = shard.next_event(event_types); + let interaction_client = discord_client.interaction(application_id); let commands = all_commands(); @@ -155,12 +173,15 @@ async fn main() -> Result<(), MainError> { let vcs = initialize_vcs(&discord_client).await; let vcs = Arc::new(vcs); + + let songbird = Arc::new(songbird); + + let state = State { vcs, songbird }; + while let Some(event_res) = next_event.await { match event_res { Ok(event) => { - tracing::debug!(?vcs, "before handling"); - handle_event(&command_router, vcs.clone(), event).await; - tracing::debug!(?vcs, "after handling"); + handle_event(&command_router, state.clone(), event).await; } Err(error) => { tracing::error!(?error); @@ -173,11 +194,12 @@ async fn main() -> Result<(), MainError> { Ok(()) } -#[tracing::instrument(skip(command_router, vcs))] -async fn handle_event(command_router: &CommandRouter, vcs: Arc, event: Event) { +#[tracing::instrument(skip(command_router))] +async fn handle_event(command_router: &CommandRouter, state: State, event: Event) { + state.songbird.process(&event).await; match event { Event::VoiceStateUpdate(voice_state_update) => { - update_vcs(&voice_state_update, &vcs); + update_vcs(&voice_state_update, &state.vcs); } Event::InteractionCreate(interaction_create) => { let InteractionCreate(interaction) = *interaction_create; @@ -188,7 +210,6 @@ async fn handle_event(command_router: &CommandRouter, vcs: Arc, event: Even } Some(InteractionData::ApplicationCommand(command_data)) => { let command_name = &command_data.name.clone(); - let state = State { vcs }; command_router .handle(state, command_name, interaction) .await;