feat: ability to join call with user

This commit is contained in:
2026-04-02 15:38:05 -04:00
parent 7f569629db
commit 663586a65c
3 changed files with 57 additions and 24 deletions

View File

@@ -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");
}

View File

@@ -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<VCs>,
pub songbird: Arc<Songbird>,
}
type Return = ();

View File

@@ -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<VCs>, 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<VCs>, 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;