feat: update to songbird 0.6, make joining calls work by spawning everything as required in songbird's documentation

This commit is contained in:
2026-04-07 23:08:20 -04:00
parent 1bd8b9b203
commit 288a784870
6 changed files with 1059 additions and 48 deletions

1053
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -49,7 +49,7 @@ rhai = "1.23.6"
rustls = "0.23" rustls = "0.23"
secrecy = { version = "0.10.3", features = ["serde"] } secrecy = { version = "0.10.3", features = ["serde"] }
snafu = { version = "0.8.9", features = ["futures"] } snafu = { version = "0.8.9", features = ["futures"] }
songbird = { version = "0.5.0", default-features = false, features = [ songbird = { version = "0.6.0", default-features = false, features = [
"driver", "driver",
"gateway", "gateway",
"receive", "receive",
@@ -71,7 +71,3 @@ twilight-http = { version = "0.17", default-features = false, features = [
twilight-model = "0.17" twilight-model = "0.17"
twilight-util = { version = "0.17", features = ["builder"] } twilight-util = { version = "0.17", features = ["builder"] }
typed-builder = "0.23.2" typed-builder = "0.23.2"
[patch.crates-io]
audiopus_sys = { git = "https://github.com/amsam0/audiopus_sys", rev = "3955ddb2b7b87e772e1c7bb93b8726a864f8c8f9" }
songbird = { git = "https://gitea.katniss.top/jacob/songbird", branch = "twilight-0.17" }

View File

@@ -82,7 +82,7 @@ fn get_guild_and_channel_id(
Ok((guild_id, channel_id)) Ok((guild_id, channel_id))
} }
#[tracing::instrument] #[tracing::instrument(skip(state))]
pub async fn handle(state: State, interaction: Interaction) { pub async fn handle(state: State, interaction: Interaction) {
let vcs = state.vcs; let vcs = state.vcs;
@@ -126,13 +126,22 @@ pub async fn handle(state: State, interaction: Interaction) {
.await .await
.expect("TODO"); .expect("TODO");
let call = tokio::spawn({ let call = loop {
let songbird = state.songbird.clone(); tracing::error!("TODO: about to try joining");
async move { songbird.join(guild_id, channel_id).await }
}) match state.songbird.join(guild_id, channel_id).await {
.await Ok(call) => break call,
.unwrap() Err(error) => {
.expect("TODO"); tracing::error!(?error, "I'm still here");
if error.should_leave_server() {
state.songbird.leave(guild_id).await.expect("TODO");
} else if error.should_reconnect_driver() {
todo!();
}
}
}
};
let channel_mention = format!("<#{channel_id}>"); let channel_mention = format!("<#{channel_id}>");
@@ -150,4 +159,5 @@ pub async fn handle(state: State, interaction: Interaction) {
tracing::error!(?call, "TODO"); tracing::error!(?call, "TODO");
let call_guard = call.lock().await; let call_guard = call.lock().await;
tracing::error!(?call_guard, "TODO");
} }

View File

@@ -23,12 +23,12 @@ pub struct State {
} }
type Return = (); type Return = ();
type BoxedHandler = Box<dyn Fn(State, Interaction) -> BoxFuture<'static, Return>>; type BoxedHandler = Box<dyn Send + Sync + Fn(State, Interaction) -> BoxFuture<'static, Return>>;
fn box_handler<Handler, Fut>(handler: Handler) -> BoxedHandler fn box_handler<Handler, Fut>(handler: Handler) -> BoxedHandler
where where
Fut: Future<Output = Return> + Send + 'static, Fut: Future<Output = Return> + Send + 'static,
Handler: Fn(State, Interaction) -> Fut + 'static, Handler: Send + Sync + Fn(State, Interaction) -> Fut + 'static,
{ {
Box::new(move |state, interaction| Box::pin(handler(state, interaction))) Box::new(move |state, interaction| Box::pin(handler(state, interaction)))
} }
@@ -50,7 +50,7 @@ impl Router {
fn add_route<Fut, Handler>(&mut self, name: &str, handler: Handler) fn add_route<Fut, Handler>(&mut self, name: &str, handler: Handler)
where where
Fut: Future<Output = Return> + Send + 'static, Fut: Future<Output = Return> + Send + 'static,
Handler: Fn(State, Interaction) -> Fut + 'static, Handler: Send + Sync + Fn(State, Interaction) -> Fut + 'static,
{ {
self.add_route_already_boxed(name, box_handler(handler)); self.add_route_already_boxed(name, box_handler(handler));
} }

View File

@@ -170,6 +170,7 @@ async fn main() -> Result<(), MainError> {
.expect("failed to deserialize set commands"); // TODO .expect("failed to deserialize set commands"); // TODO
let command_router = CommandRouter::from_iter(commands); let command_router = CommandRouter::from_iter(commands);
let command_router = Arc::new(command_router);
let vcs = initialize_vcs(&discord_client).await; let vcs = initialize_vcs(&discord_client).await;
@@ -187,7 +188,7 @@ async fn main() -> Result<(), MainError> {
while let Some(event_res) = next_event.await { while let Some(event_res) = next_event.await {
match event_res { match event_res {
Ok(event) => { Ok(event) => {
handle_event(&command_router, state.clone(), event).await; handle_event(command_router.clone(), state.clone(), event).await;
} }
Err(error) => { Err(error) => {
tracing::error!(?error); tracing::error!(?error);
@@ -201,7 +202,7 @@ async fn main() -> Result<(), MainError> {
} }
#[tracing::instrument(skip(command_router))] #[tracing::instrument(skip(command_router))]
async fn handle_event(command_router: &CommandRouter, state: State, event: Event) { async fn handle_event(command_router: Arc<CommandRouter>, state: State, event: Event) {
state.songbird.process(&event).await; state.songbird.process(&event).await;
match event { match event {
Event::VoiceStateUpdate(voice_state_update) => { Event::VoiceStateUpdate(voice_state_update) => {
@@ -215,10 +216,12 @@ async fn handle_event(command_router: &CommandRouter, state: State, event: Event
tracing::warn!("missing expected interaction data"); tracing::warn!("missing expected interaction data");
} }
Some(InteractionData::ApplicationCommand(command_data)) => { Some(InteractionData::ApplicationCommand(command_data)) => {
let command_name = &command_data.name.clone(); let command_name = command_data.name.clone();
tokio::spawn(async move {
command_router command_router
.handle(state, command_name, interaction) .handle(state, &command_name, interaction)
.await; .await;
});
} }
Some(InteractionData::MessageComponent(component_data)) => { Some(InteractionData::MessageComponent(component_data)) => {

View File

@@ -87,6 +87,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: &VCs) {
let user_id = voice_state_update.user_id; let user_id = voice_state_update.user_id;
match voice_state_update.guild_id { match voice_state_update.guild_id {