Support for Twilight 0.16 (#227)
This commit is contained in:
@@ -57,7 +57,7 @@ symphonia = { default-features = false, optional = true, version = "0.5.2" }
|
|||||||
symphonia-core = { optional = true, version = "0.5.2" }
|
symphonia-core = { optional = true, version = "0.5.2" }
|
||||||
tokio = { default-features = false, optional = true, version = "1.0" }
|
tokio = { default-features = false, optional = true, version = "1.0" }
|
||||||
tokio-tungstenite = { optional = true, version = "0.24", features = ["url"] }
|
tokio-tungstenite = { optional = true, version = "0.24", features = ["url"] }
|
||||||
tokio-websockets = { optional = true, version = "0.7", features = [
|
tokio-websockets = { optional = true, version = "0.11", features = [
|
||||||
"client",
|
"client",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"sha1_smol",
|
"sha1_smol",
|
||||||
@@ -66,8 +66,8 @@ tokio-websockets = { optional = true, version = "0.7", features = [
|
|||||||
tokio-util = { features = ["io"], optional = true, version = "0.7" }
|
tokio-util = { features = ["io"], optional = true, version = "0.7" }
|
||||||
tracing = { version = "0.1", features = ["log"] }
|
tracing = { version = "0.1", features = ["log"] }
|
||||||
tracing-futures = "0.2"
|
tracing-futures = "0.2"
|
||||||
twilight-gateway = { default-features = false, optional = true, version = "0.15.0" }
|
twilight-gateway = { default-features = false, optional = true, version = "0.16.0" }
|
||||||
twilight-model = { default-features = false, optional = true, version = "0.15.0" }
|
twilight-model = { default-features = false, optional = true, version = "0.16.0" }
|
||||||
typenum = { optional = true, version = "1.17.0" }
|
typenum = { optional = true, version = "1.17.0" }
|
||||||
url = { optional = true, version = "2" }
|
url = { optional = true, version = "2" }
|
||||||
uuid = { features = ["v4"], optional = true, version = "1" }
|
uuid = { features = ["v4"], optional = true, version = "1" }
|
||||||
@@ -145,7 +145,7 @@ native = [
|
|||||||
"stream_lib?/native-tls",
|
"stream_lib?/native-tls",
|
||||||
"tokio-tungstenite?/native-tls",
|
"tokio-tungstenite?/native-tls",
|
||||||
"tokio-websockets?/native-tls",
|
"tokio-websockets?/native-tls",
|
||||||
"twilight-gateway?/native",
|
"twilight-gateway?/native-tls",
|
||||||
]
|
]
|
||||||
tungstenite = ["dep:tokio-tungstenite"]
|
tungstenite = ["dep:tokio-tungstenite"]
|
||||||
tws = ["dep:tokio-websockets"]
|
tws = ["dep:tokio-websockets"]
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ resolver = "2"
|
|||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
reqwest = "0.12"
|
reqwest = "0.12"
|
||||||
serenity = { features = ["cache", "framework", "standard_framework", "voice", "http", "rustls_backend"], version = "0.12" }
|
serenity = { features = ["cache", "framework", "standard_framework", "voice", "http", "rustls_backend"], version = "0.12" }
|
||||||
songbird = { path = "../", version = "0.4" }
|
songbird = { path = "../", version = "0.4", default-features = false }
|
||||||
symphonia = { features = ["aac", "mp3", "isomp4", "alac"], version = "0.5.2" }
|
symphonia = { features = ["aac", "mp3", "isomp4", "alac"], version = "0.5.2" }
|
||||||
tokio = { features = ["macros", "rt-multi-thread", "signal", "sync"], version = "1" }
|
tokio = { features = ["macros", "rt-multi-thread", "signal", "sync"], version = "1" }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
songbird = { workspace = true, features = ["driver", "gateway", "twilight", "rustls", "tungstenite"] }
|
songbird = { workspace = true, features = ["driver", "gateway", "twilight", "rustls", "tws"] }
|
||||||
symphonia = { workspace = true }
|
symphonia = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
tracing-subscriber = { workspace = true }
|
tracing-subscriber = { workspace = true, default-features = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
twilight-gateway = "0.15"
|
twilight-gateway = "0.16.0"
|
||||||
twilight-http = "0.15"
|
twilight-http = "0.16.0"
|
||||||
twilight-model = "0.15"
|
twilight-model = "0.16.0"
|
||||||
twilight-standby = "0.15"
|
twilight-standby = "0.16.0"
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
//!
|
//!
|
||||||
//! [basic lavalink bot]: https://github.com/twilight-rs/twilight/tree/main/examples/lavalink-basic-bot.rs
|
//! [basic lavalink bot]: https://github.com/twilight-rs/twilight/tree/main/examples/lavalink-basic-bot.rs
|
||||||
|
|
||||||
use futures::StreamExt;
|
|
||||||
use songbird::{
|
use songbird::{
|
||||||
input::{Compose, YoutubeDl},
|
input::{Compose, YoutubeDl},
|
||||||
shards::TwilightMap,
|
shards::TwilightMap,
|
||||||
@@ -29,12 +28,7 @@ use songbird::{
|
|||||||
};
|
};
|
||||||
use std::{collections::HashMap, env, error::Error, future::Future, num::NonZeroU64, sync::Arc};
|
use std::{collections::HashMap, env, error::Error, future::Future, num::NonZeroU64, sync::Arc};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use twilight_gateway::{
|
use twilight_gateway::{Event, EventTypeFlags, Intents, Shard, StreamExt as _};
|
||||||
stream::{self, ShardEventStream},
|
|
||||||
Event,
|
|
||||||
Intents,
|
|
||||||
Shard,
|
|
||||||
};
|
|
||||||
use twilight_http::Client as HttpClient;
|
use twilight_http::Client as HttpClient;
|
||||||
use twilight_model::{
|
use twilight_model::{
|
||||||
channel::Message,
|
channel::Message,
|
||||||
@@ -68,7 +62,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
|
|||||||
// Initialize the tracing subscriber.
|
// Initialize the tracing subscriber.
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let (mut shards, state) = {
|
let (shards, state) = {
|
||||||
let token = env::var("DISCORD_TOKEN")?;
|
let token = env::var("DISCORD_TOKEN")?;
|
||||||
|
|
||||||
let http = HttpClient::new(token.clone());
|
let http = HttpClient::new(token.clone());
|
||||||
@@ -79,7 +73,7 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
|
|||||||
let config = twilight_gateway::Config::new(token.clone(), intents);
|
let config = twilight_gateway::Config::new(token.clone(), intents);
|
||||||
|
|
||||||
let shards: Vec<Shard> =
|
let shards: Vec<Shard> =
|
||||||
stream::create_recommended(&http, config, |_, builder| builder.build())
|
twilight_gateway::create_recommended(&http, config, |_, builder| builder.build())
|
||||||
.await?
|
.await?
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
@@ -103,28 +97,43 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut stream = ShardEventStream::new(shards.iter_mut());
|
let mut set = tokio::task::JoinSet::new();
|
||||||
loop {
|
for shard in shards {
|
||||||
let event = match stream.next().await {
|
set.spawn(tokio::spawn(runner(shard, state.clone())));
|
||||||
Some((_, Ok(event))) => event,
|
|
||||||
Some((_, Err(source))) => {
|
|
||||||
tracing::warn!(?source, "error receiving event");
|
|
||||||
|
|
||||||
if source.is_fatal() {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set.join_next().await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn runner(mut shard: Shard, state: Arc<StateRef>) {
|
||||||
|
while let Some(item) = shard.next_event(EventTypeFlags::all()).await {
|
||||||
|
let event = match item {
|
||||||
|
Ok(event) => event,
|
||||||
|
Err(source) => {
|
||||||
|
tracing::warn!(?source, "error receiving event");
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
None => break,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tokio::spawn({
|
||||||
|
let state = state.clone();
|
||||||
|
async move {
|
||||||
|
handle_event(event, state).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_event(event: Event, state: Arc<StateRef>) {
|
||||||
state.standby.process(&event);
|
state.standby.process(&event);
|
||||||
state.songbird.process(&event).await;
|
state.songbird.process(&event).await;
|
||||||
|
|
||||||
if let Event::MessageCreate(msg) = event {
|
if let Event::MessageCreate(msg) = event {
|
||||||
if msg.guild_id.is_none() || !msg.content.starts_with('!') {
|
if msg.guild_id.is_none() || !msg.content.starts_with('!') {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match msg.content.splitn(2, ' ').next() {
|
match msg.content.splitn(2, ' ').next() {
|
||||||
@@ -135,19 +144,16 @@ async fn main() -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
|
|||||||
Some("!seek") => spawn(seek(msg.0, Arc::clone(&state))),
|
Some("!seek") => spawn(seek(msg.0, Arc::clone(&state))),
|
||||||
Some("!stop") => spawn(stop(msg.0, Arc::clone(&state))),
|
Some("!stop") => spawn(stop(msg.0, Arc::clone(&state))),
|
||||||
Some("!volume") => spawn(volume(msg.0, Arc::clone(&state))),
|
Some("!volume") => spawn(volume(msg.0, Arc::clone(&state))),
|
||||||
_ => continue,
|
_ => return,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn join(msg: Message, state: State) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
|
async fn join(msg: Message, state: State) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
|
||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content("What's the channel ID you want me to join?")?
|
.content("What's the channel ID you want me to join?")
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let author_id = msg.author.id;
|
let author_id = msg.author.id;
|
||||||
@@ -171,7 +177,7 @@ async fn join(msg: Message, state: State) -> Result<(), Box<dyn Error + Send + S
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content(&content)?
|
.content(&content)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -191,7 +197,7 @@ async fn leave(msg: Message, state: State) -> Result<(), Box<dyn Error + Send +
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content("Left the channel")?
|
.content("Left the channel")
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -206,7 +212,7 @@ async fn play(msg: Message, state: State) -> Result<(), Box<dyn Error + Send + S
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content("What's the URL of the audio to play?")?
|
.content("What's the URL of the audio to play?")
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let author_id = msg.author.id;
|
let author_id = msg.author.id;
|
||||||
@@ -230,7 +236,7 @@ async fn play(msg: Message, state: State) -> Result<(), Box<dyn Error + Send + S
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content(&content)?
|
.content(&content)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(call_lock) = state.songbird.get(guild_id) {
|
if let Some(call_lock) = state.songbird.get(guild_id) {
|
||||||
@@ -244,7 +250,7 @@ async fn play(msg: Message, state: State) -> Result<(), Box<dyn Error + Send + S
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content("Didn't find any results")?
|
.content("Didn't find any results")
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +292,7 @@ async fn pause(msg: Message, state: State) -> Result<(), Box<dyn Error + Send +
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content(&content)?
|
.content(&content)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -301,7 +307,7 @@ async fn seek(msg: Message, state: State) -> Result<(), Box<dyn Error + Send + S
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content("Where in the track do you want to seek to (in seconds)?")?
|
.content("Where in the track do you want to seek to (in seconds)?")
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let author_id = msg.author.id;
|
let author_id = msg.author.id;
|
||||||
@@ -326,7 +332,7 @@ async fn seek(msg: Message, state: State) -> Result<(), Box<dyn Error + Send + S
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content(&content)?
|
.content(&content)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -349,7 +355,7 @@ async fn stop(msg: Message, state: State) -> Result<(), Box<dyn Error + Send + S
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content("Stopped the track")?
|
.content("Stopped the track")
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -364,7 +370,7 @@ async fn volume(msg: Message, state: State) -> Result<(), Box<dyn Error + Send +
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content("What's the volume you want to set (0.0-10.0, 1.0 being the default)?")?
|
.content("What's the volume you want to set (0.0-10.0, 1.0 being the default)?")
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let author_id = msg.author.id;
|
let author_id = msg.author.id;
|
||||||
@@ -381,7 +387,7 @@ async fn volume(msg: Message, state: State) -> Result<(), Box<dyn Error + Send +
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content("Invalid volume!")?
|
.content("Invalid volume!")
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -399,7 +405,7 @@ async fn volume(msg: Message, state: State) -> Result<(), Box<dyn Error + Send +
|
|||||||
state
|
state
|
||||||
.http
|
.http
|
||||||
.create_message(msg.channel_id)
|
.create_message(msg.channel_id)
|
||||||
.content(&content)?
|
.content(&content)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use serenity::gateway::ShardRunnerMessage;
|
|||||||
#[cfg(feature = "gateway")]
|
#[cfg(feature = "gateway")]
|
||||||
use std::{error::Error, fmt};
|
use std::{error::Error, fmt};
|
||||||
#[cfg(feature = "twilight")]
|
#[cfg(feature = "twilight")]
|
||||||
use twilight_gateway::error::SendError;
|
use twilight_gateway::error::ChannelError;
|
||||||
|
|
||||||
#[cfg(feature = "gateway")]
|
#[cfg(feature = "gateway")]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -48,7 +48,7 @@ pub enum JoinError {
|
|||||||
Serenity(Box<TrySendError<ShardRunnerMessage>>),
|
Serenity(Box<TrySendError<ShardRunnerMessage>>),
|
||||||
#[cfg(feature = "twilight")]
|
#[cfg(feature = "twilight")]
|
||||||
/// Twilight-specific WebSocket send error when a message fails to send over websocket.
|
/// Twilight-specific WebSocket send error when a message fails to send over websocket.
|
||||||
Twilight(SendError),
|
Twilight(ChannelError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gateway")]
|
#[cfg(feature = "gateway")]
|
||||||
@@ -121,8 +121,8 @@ impl From<Box<TrySendError<ShardRunnerMessage>>> for JoinError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "twilight", feature = "gateway"))]
|
#[cfg(all(feature = "twilight", feature = "gateway"))]
|
||||||
impl From<SendError> for JoinError {
|
impl From<ChannelError> for JoinError {
|
||||||
fn from(e: SendError) -> Self {
|
fn from(e: ChannelError) -> Self {
|
||||||
JoinError::Twilight(e)
|
JoinError::Twilight(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ use twilight_model::gateway::payload::outgoing::update_voice_state::UpdateVoiceS
|
|||||||
#[cfg(feature = "twilight")]
|
#[cfg(feature = "twilight")]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TwilightMap {
|
pub struct TwilightMap {
|
||||||
map: std::collections::HashMap<u64, MessageSender>,
|
map: std::collections::HashMap<u32, MessageSender>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "twilight")]
|
#[cfg(feature = "twilight")]
|
||||||
@@ -38,13 +38,13 @@ impl TwilightMap {
|
|||||||
///
|
///
|
||||||
/// For correctness all shards should be in the map.
|
/// For correctness all shards should be in the map.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(map: std::collections::HashMap<u64, MessageSender>) -> Self {
|
pub fn new(map: std::collections::HashMap<u32, MessageSender>) -> Self {
|
||||||
TwilightMap { map }
|
TwilightMap { map }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the message sender for `shard_id`.
|
/// Get the message sender for `shard_id`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get(&self, shard_id: u64) -> Option<&MessageSender> {
|
pub fn get(&self, shard_id: u32) -> Option<&MessageSender> {
|
||||||
self.map.get(&shard_id)
|
self.map.get(&shard_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ impl Sharder {
|
|||||||
s.get_or_insert_shard_handle(shard_id as u32),
|
s.get_or_insert_shard_handle(shard_id as u32),
|
||||||
)),
|
)),
|
||||||
#[cfg(feature = "twilight")]
|
#[cfg(feature = "twilight")]
|
||||||
Sharder::Twilight(t) => Some(Shard::Twilight(t.clone(), shard_id)),
|
Sharder::Twilight(t) => Some(Shard::Twilight(t.clone(), shard_id as u32)),
|
||||||
Sharder::Generic(src) => src.get_shard(shard_id).map(Shard::Generic),
|
Sharder::Generic(src) => src.get_shard(shard_id).map(Shard::Generic),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,7 +156,7 @@ pub enum Shard {
|
|||||||
Serenity(Arc<SerenityShardHandle>),
|
Serenity(Arc<SerenityShardHandle>),
|
||||||
#[cfg(feature = "twilight")]
|
#[cfg(feature = "twilight")]
|
||||||
/// Handle to a map of twilight command senders.
|
/// Handle to a map of twilight command senders.
|
||||||
Twilight(Arc<TwilightMap>, u64),
|
Twilight(Arc<TwilightMap>, u32),
|
||||||
/// Handle to a generic shard instance.
|
/// Handle to a generic shard instance.
|
||||||
Generic(#[derivative(Debug = "ignore")] Arc<dyn VoiceUpdate + Send + Sync>),
|
Generic(#[derivative(Debug = "ignore")] Arc<dyn VoiceUpdate + Send + Sync>),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user