Compare commits
2 Commits
2bf42e47c5
...
62399c2046
| Author | SHA1 | Date | |
|---|---|---|---|
| 62399c2046 | |||
| 612a696829 |
@@ -288,6 +288,8 @@ pub async fn handle(state: State, interaction: Interaction) {
|
|||||||
|
|
||||||
call.add_global_event(CoreEvent::SpeakingStateUpdate.into(), handler.clone());
|
call.add_global_event(CoreEvent::SpeakingStateUpdate.into(), handler.clone());
|
||||||
call.add_global_event(CoreEvent::VoiceTick.into(), handler);
|
call.add_global_event(CoreEvent::VoiceTick.into(), handler);
|
||||||
|
|
||||||
|
call.mute(true).await.expect("TODO");
|
||||||
}
|
}
|
||||||
|
|
||||||
let channel_mention = format!("<#{voice_channel_id}>");
|
let channel_mention = format!("<#{voice_channel_id}>");
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use twilight_model::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::VCs;
|
use crate::{VCs, track_vcs::GuildVoiceChannelToTextChannel};
|
||||||
|
|
||||||
mod debug;
|
mod debug;
|
||||||
mod join;
|
mod join;
|
||||||
@@ -31,6 +31,7 @@ pub struct State {
|
|||||||
pub discord_bot_owner_user_id: Id<UserMarker>,
|
pub discord_bot_owner_user_id: Id<UserMarker>,
|
||||||
pub discord_client: Arc<twilight_http::Client>,
|
pub discord_client: Arc<twilight_http::Client>,
|
||||||
pub discord_user_id: Id<UserMarker>,
|
pub discord_user_id: Id<UserMarker>,
|
||||||
|
pub discord_voice_channel_corresponding_text_channel: Arc<GuildVoiceChannelToTextChannel>,
|
||||||
pub recording_data: Operator,
|
pub recording_data: Operator,
|
||||||
pub songbird: Arc<Songbird>,
|
pub songbird: Arc<Songbird>,
|
||||||
pub user_data: Operator,
|
pub user_data: Operator,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ pub use one_to_many::OneToManyUniqueBTreeMap;
|
|||||||
pub use one_to_many_with_data::OneToManyUniqueBTreeMapWithData;
|
pub use one_to_many_with_data::OneToManyUniqueBTreeMapWithData;
|
||||||
pub use one_to_one::OneToOneBTreeMap;
|
pub use one_to_one::OneToOneBTreeMap;
|
||||||
pub use storage::Storage;
|
pub use storage::Storage;
|
||||||
pub use track_vcs::{VCs, initialize_vcs, update_vcs};
|
pub use track_vcs::{GuildVoiceChannelToTextChannel, VCs, initialize_vcs, update_vcs};
|
||||||
pub use vc_user::{UserInVCData, VoiceStatus};
|
pub use vc_user::{UserInVCData, VoiceStatus};
|
||||||
|
|
||||||
capnp::generated_code!(pub mod user_capnp);
|
capnp::generated_code!(pub mod user_capnp);
|
||||||
|
|||||||
82
src/main.rs
82
src/main.rs
@@ -1,13 +1,16 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use fomo_reducer::{CommandRouter, State, Storage, all_commands, initialize_vcs, update_vcs};
|
use fomo_reducer::{
|
||||||
|
CommandRouter, GuildVoiceChannelToTextChannel, State, Storage, all_commands, initialize_vcs,
|
||||||
|
update_vcs,
|
||||||
|
};
|
||||||
use secrecy::{ExposeSecret, SecretString};
|
use secrecy::{ExposeSecret, SecretString};
|
||||||
use snafu::Snafu;
|
use snafu::{OptionExt, ResultExt, Snafu};
|
||||||
use songbird::{
|
use songbird::{
|
||||||
Config, Songbird,
|
Config, Songbird,
|
||||||
driver::{Channels, DecodeConfig, SampleRate},
|
driver::{Channels, DecodeConfig, SampleRate},
|
||||||
shards::TwilightMap,
|
shards::TwilightMap,
|
||||||
};
|
};
|
||||||
use std::{fmt::Debug, sync::Arc};
|
use std::{fmt::Debug, str::FromStr, sync::Arc};
|
||||||
use strum::EnumString;
|
use strum::EnumString;
|
||||||
use tokio::{select, signal::ctrl_c, task::JoinSet};
|
use tokio::{select, signal::ctrl_c, task::JoinSet};
|
||||||
use tokio_util::{sync::CancellationToken, time::FutureExt as _};
|
use tokio_util::{sync::CancellationToken, time::FutureExt as _};
|
||||||
@@ -19,7 +22,10 @@ use twilight_model::{
|
|||||||
payload::{incoming::InteractionCreate, outgoing::UpdatePresence},
|
payload::{incoming::InteractionCreate, outgoing::UpdatePresence},
|
||||||
presence::{ActivityType, MinimalActivity, Status},
|
presence::{ActivityType, MinimalActivity, Status},
|
||||||
},
|
},
|
||||||
id::{Id, marker::UserMarker},
|
id::{
|
||||||
|
Id,
|
||||||
|
marker::{ChannelMarker, GuildMarker, UserMarker},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, strum::Display, EnumString)]
|
#[derive(Clone, Copy, Debug, strum::Display, EnumString)]
|
||||||
@@ -63,6 +69,41 @@ impl From<AudioSampleRate> for SampleRate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Snafu)]
|
||||||
|
enum ParseGuildVCToTextChannelError {
|
||||||
|
NoScope,
|
||||||
|
|
||||||
|
NoRelation,
|
||||||
|
|
||||||
|
ParseGuildError {
|
||||||
|
source: <Id<GuildMarker> as FromStr>::Err,
|
||||||
|
},
|
||||||
|
|
||||||
|
ParseVoiceChannelError {
|
||||||
|
source: <Id<ChannelMarker> as FromStr>::Err,
|
||||||
|
},
|
||||||
|
|
||||||
|
ParseTextChannelError {
|
||||||
|
source: <Id<ChannelMarker> as FromStr>::Err,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_guild_vc_to_text_channel(
|
||||||
|
source: &str,
|
||||||
|
) -> Result<(Id<GuildMarker>, Id<ChannelMarker>, Id<ChannelMarker>), ParseGuildVCToTextChannelError>
|
||||||
|
{
|
||||||
|
let (guild, voice_channel_and_text_channel) = source.split_once(':').context(NoScopeSnafu)?;
|
||||||
|
let (voice_channel, text_channel) = voice_channel_and_text_channel
|
||||||
|
.split_once("->")
|
||||||
|
.context(NoRelationSnafu)?;
|
||||||
|
|
||||||
|
let guild = guild.parse().context(ParseGuildSnafu)?;
|
||||||
|
let voice_channel = voice_channel.parse().context(ParseVoiceChannelSnafu)?;
|
||||||
|
let text_channel = text_channel.parse().context(ParseTextChannelSnafu)?;
|
||||||
|
|
||||||
|
Ok((guild, voice_channel, text_channel))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
struct AppArgs {
|
struct AppArgs {
|
||||||
#[arg(long, env)]
|
#[arg(long, env)]
|
||||||
@@ -77,6 +118,10 @@ struct AppArgs {
|
|||||||
#[arg(long, env)]
|
#[arg(long, env)]
|
||||||
discord_status: Option<Arc<str>>,
|
discord_status: Option<Arc<str>>,
|
||||||
|
|
||||||
|
#[arg(long, env, value_parser = parse_guild_vc_to_text_channel)]
|
||||||
|
discord_voice_channel_corresponding_text_channel:
|
||||||
|
Vec<(Id<GuildMarker>, Id<ChannelMarker>, Id<ChannelMarker>)>,
|
||||||
|
|
||||||
#[arg(long, env, default_value_t = AudioChannels::Mono)]
|
#[arg(long, env, default_value_t = AudioChannels::Mono)]
|
||||||
audio_channels: AudioChannels,
|
audio_channels: AudioChannels,
|
||||||
|
|
||||||
@@ -141,6 +186,7 @@ async fn main() -> Result<(), MainError> {
|
|||||||
discord_bot_owner_user_id,
|
discord_bot_owner_user_id,
|
||||||
discord_nickname,
|
discord_nickname,
|
||||||
discord_status,
|
discord_status,
|
||||||
|
discord_voice_channel_corresponding_text_channel,
|
||||||
audio_channels,
|
audio_channels,
|
||||||
audio_sample_rate,
|
audio_sample_rate,
|
||||||
bot_data,
|
bot_data,
|
||||||
@@ -244,11 +290,11 @@ async fn main() -> Result<(), MainError> {
|
|||||||
.await
|
.await
|
||||||
.expect("failed to deserialize set commands"); // TODO
|
.expect("failed to deserialize set commands"); // TODO
|
||||||
|
|
||||||
|
let vcs = initialize_vcs(&discord_client).await;
|
||||||
|
|
||||||
let command_router = CommandRouter::from_iter(commands);
|
let command_router = CommandRouter::from_iter(commands);
|
||||||
let command_router = Arc::new(command_router);
|
let command_router = Arc::new(command_router);
|
||||||
|
|
||||||
let vcs = initialize_vcs(&discord_client).await;
|
|
||||||
|
|
||||||
let discord_client = Arc::new(discord_client);
|
let discord_client = Arc::new(discord_client);
|
||||||
let songbird = Arc::new(songbird);
|
let songbird = Arc::new(songbird);
|
||||||
let vcs = Arc::new(vcs);
|
let vcs = Arc::new(vcs);
|
||||||
@@ -257,6 +303,22 @@ async fn main() -> Result<(), MainError> {
|
|||||||
let recording_data = recording_data.into_inner();
|
let recording_data = recording_data.into_inner();
|
||||||
let user_data = user_data.into_inner();
|
let user_data = user_data.into_inner();
|
||||||
|
|
||||||
|
let discord_voice_channel_corresponding_text_channel = {
|
||||||
|
let mut map = GuildVoiceChannelToTextChannel::default();
|
||||||
|
|
||||||
|
for (guild_id, voice_channel_id, text_channel_id) in
|
||||||
|
discord_voice_channel_corresponding_text_channel
|
||||||
|
{
|
||||||
|
map.entry(guild_id)
|
||||||
|
.or_default()
|
||||||
|
.insert(voice_channel_id, text_channel_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
map
|
||||||
|
};
|
||||||
|
let discord_voice_channel_corresponding_text_channel =
|
||||||
|
Arc::new(discord_voice_channel_corresponding_text_channel);
|
||||||
|
|
||||||
let state = State {
|
let state = State {
|
||||||
audio_channels,
|
audio_channels,
|
||||||
audio_sample_rate,
|
audio_sample_rate,
|
||||||
@@ -266,6 +328,7 @@ async fn main() -> Result<(), MainError> {
|
|||||||
discord_bot_owner_user_id,
|
discord_bot_owner_user_id,
|
||||||
discord_client,
|
discord_client,
|
||||||
discord_user_id,
|
discord_user_id,
|
||||||
|
discord_voice_channel_corresponding_text_channel,
|
||||||
recording_data,
|
recording_data,
|
||||||
songbird,
|
songbird,
|
||||||
user_data,
|
user_data,
|
||||||
@@ -344,7 +407,12 @@ async fn handle_events(command_router: Arc<CommandRouter>, state: State, mut sha
|
|||||||
Ok(event) => {
|
Ok(event) => {
|
||||||
handle_event(command_router.clone(), state.clone(), event).await;
|
handle_event(command_router.clone(), state.clone(), event).await;
|
||||||
}
|
}
|
||||||
Err(reconnect_error) if matches!(reconnect_error.kind(), &twilight_gateway::error::ReceiveMessageErrorType::Reconnect) => {
|
Err(reconnect_error)
|
||||||
|
if matches!(
|
||||||
|
reconnect_error.kind(),
|
||||||
|
&twilight_gateway::error::ReceiveMessageErrorType::Reconnect
|
||||||
|
) =>
|
||||||
|
{
|
||||||
tracing::error!(?reconnect_error);
|
tracing::error!(?reconnect_error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use futures::{StreamExt, stream::FuturesUnordered};
|
use futures::{StreamExt, stream::FuturesUnordered};
|
||||||
use twilight_model::{
|
use twilight_model::{
|
||||||
@@ -8,10 +10,11 @@ use twilight_model::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{OneToManyUniqueBTreeMapWithData, UserInVCData, VoiceStatus};
|
use crate::{OneToManyUniqueBTreeMapWithData, OneToOneBTreeMap, UserInVCData, VoiceStatus};
|
||||||
|
|
||||||
|
pub type GuildVoiceChannelToTextChannel = BTreeMap<Id<GuildMarker>, OneToOneBTreeMap<Id<ChannelMarker>, Id<ChannelMarker>>>;
|
||||||
|
|
||||||
type VCsInGuild = OneToManyUniqueBTreeMapWithData<Id<ChannelMarker>, Id<UserMarker>, UserInVCData>;
|
type VCsInGuild = OneToManyUniqueBTreeMapWithData<Id<ChannelMarker>, Id<UserMarker>, UserInVCData>;
|
||||||
|
|
||||||
pub type VCs = DashMap<Id<GuildMarker>, VCsInGuild>;
|
pub type VCs = DashMap<Id<GuildMarker>, VCsInGuild>;
|
||||||
|
|
||||||
#[tracing::instrument(skip(discord_client), ret)]
|
#[tracing::instrument(skip(discord_client), ret)]
|
||||||
|
|||||||
Reference in New Issue
Block a user