summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNatrixAeria <upezu@student.kit.edu>2020-09-27 20:58:35 +0200
committerNatrixAeria <upezu@student.kit.edu>2020-09-27 20:58:35 +0200
commita2f8d36a3747a1a07212ed4af5d3fb857687e96a (patch)
treeee0d665837b7689bda90d1018c3f2e798cc38774
parent0723199ed2495d73dc9a62d33eab7481ca1245f0 (diff)
Cache channelsfeature-channels
-rw-r--r--src/config.rs22
-rw-r--r--src/main.rs149
2 files changed, 148 insertions, 23 deletions
diff --git a/src/config.rs b/src/config.rs
index cd8a55b..fd00c24 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,6 +1,20 @@
+macro_rules! bot_name {
+ () => {
+ "Cupido"
+ };
+}
+
pub const TOKEN_ENV: &str = "DISCORD_TOKEN";
pub const GLOBAL_COMMAND_PREFIX: &str = "!<3";
-pub const META_CHANNEL_NAME: &str = "Cupido Shuffler";
-pub const META_CHANNEL_DESCRIPTION: &str = "All channels related to cupido";
-pub const HELP_TEXT: &str = "Cupido is a discord bot to get to know your people.
-Cupido is open-source <https://git.kobert.dev/lovefinderrz.git/>!";
+pub const META_CHANNEL_NAME: &str = concat!(bot_name!(), " Shuffler");
+pub const META_CHANNEL_DESCRIPTION: &str = concat!("All channels related to ", bot_name!());
+pub const LOBBY_CHANNEL_NAME: &str = "lobby";
+pub const LOBBY_CHANNEL_DESCRIPTION: &str = "You wanna get shuffled? You're at the right place!";
+pub const HELP_TEXT: &str = concat!(
+ bot_name!(),
+ " - your partner for getting shuffled.
+",
+ bot_name!(),
+ " is a discord bot to get to know your people.
+This software is open-source <https://git.kobert.dev/lovefinderrz.git/>!"
+);
diff --git a/src/main.rs b/src/main.rs
index 455da50..a3c0222 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,12 @@
+#![feature(once_cell)]
+
mod config;
use serenity::framework::StandardFramework;
+use serenity::model::id::ChannelId;
use serenity::Client;
+use std::lazy::SyncLazy;
+use std::sync::{Arc, Mutex};
fn configure(conf: &mut serenity::framework::standard::Configuration) {
conf.prefix(config::GLOBAL_COMMAND_PREFIX)
@@ -26,20 +31,32 @@ impl std::fmt::Display for BotError {
impl std::error::Error for BotError {}
+#[derive(Debug, Clone, Default)]
+pub struct ChannelCache {
+ pub meta: Option<ChannelId>,
+ pub lobby: Option<ChannelId>,
+}
+
+static CHANNEL_CACHE: SyncLazy<Arc<Mutex<ChannelCache>>> =
+ SyncLazy::new(|| Arc::new(Mutex::new(Default::default())));
+
mod commands {
+ use super::{ChannelCache, CHANNEL_CACHE};
use crate::config;
use serenity::client::Context;
use serenity::framework::standard::{macros::*, CommandError, CommandResult};
use serenity::model::{
- channel::{ChannelType, GuildChannel, Message},
+ channel::{Channel, ChannelType, GuildChannel, Message},
guild::Guild,
id::ChannelId,
};
+
#[group]
- #[description = "Commands for the cupido bot"]
+ #[description("Commands for this bot")]
#[commands(help, create)]
struct Group;
+ #[derive(Debug, Clone)]
struct ChannelDescriptor<'n, 'd> {
name: &'n str,
description: &'d str,
@@ -70,22 +87,116 @@ mod commands {
.await?)
}
+ async fn get_guild_channel_by_optional_id(
+ ctx: &Context,
+ id: Option<ChannelId>,
+ ) -> Option<GuildChannel> {
+ match id {
+ Some(id) => ctx.cache.guild_channel(id).await,
+ None => None,
+ }
+ }
+
+ async fn get_channel_by_optional_id(
+ ctx: &Context,
+ kind: ChannelType,
+ id: Option<ChannelId>,
+ ) -> Option<Channel> {
+ match (kind, id) {
+ (ChannelType::Category, Some(id)) => ctx
+ .cache
+ .categories()
+ .await
+ .get(&id)
+ .cloned()
+ .map(Channel::Category),
+ (_, opt_id) => get_guild_channel_by_optional_id(ctx, opt_id)
+ .await
+ .map(Channel::Guild),
+ }
+ }
+
async fn create_channel<'n, 'd>(
ctx: &Context,
guild: &Guild,
desc: ChannelDescriptor<'n, 'd>,
- ) -> Result<GuildChannel, CommandError> {
- let channel = guild.channel_id_from_name(&ctx.cache, desc.name).await;
- let optional_channel = match channel {
- Some(channel) => ctx.cache.guild_channel(channel).await,
- None => None,
+ ) -> Result<Channel, CommandError> {
+ let optional_channel = match desc.kind {
+ ChannelType::Category => {
+ println!("{:?}", ctx.cache.categories().await);
+ ctx.cache.categories().await.values().find_map(|channel| {
+ if channel.name() == desc.name {
+ Some(Channel::Category(channel.clone()))
+ } else {
+ None
+ }
+ })
+ }
+ _ => get_guild_channel_by_optional_id(
+ ctx,
+ guild.channel_id_from_name(&ctx.cache, desc.name).await,
+ )
+ .await
+ .map(Channel::Guild),
};
match optional_channel {
Some(channel) => Ok(channel),
- None => create_channel_no_cache(ctx, guild, desc).await,
+ None => {
+ let channel = create_channel_no_cache(ctx, guild, desc)
+ .await
+ .map(Channel::Guild);
+ channel
+ }
}
}
+ async fn get_channel_or_create<'n, 'd, F: Fn(&mut ChannelCache) -> &mut Option<ChannelId>>(
+ ctx: &Context,
+ guild: &Guild,
+ desc: ChannelDescriptor<'n, 'd>,
+ f: F,
+ ) -> Result<Channel, CommandError> {
+ let lock = || CHANNEL_CACHE.lock().unwrap();
+ Ok({
+ let optional_id = *f(&mut *lock());
+ match get_channel_by_optional_id(ctx, desc.kind, optional_id).await {
+ Some(channel) => channel,
+ None => {
+ let channel = create_channel(ctx, &guild, desc).await?;
+ *f(&mut *lock()) = Some(channel.id());
+ channel
+ }
+ }
+ })
+ }
+
+ async fn get_meta_channel_or_create(
+ ctx: &Context,
+ guild: &Guild,
+ ) -> Result<Channel, CommandError> {
+ let desc = ChannelDescriptor {
+ name: config::META_CHANNEL_NAME,
+ description: config::META_CHANNEL_DESCRIPTION,
+ kind: ChannelType::Category,
+ parent: None,
+ };
+ get_channel_or_create(ctx, guild, desc, |cache| &mut cache.meta).await
+ }
+
+ async fn get_lobby_channel_or_create(
+ ctx: &Context,
+ guild: &Guild,
+ meta_channel_id: ChannelId,
+ ) -> Result<Channel, CommandError> {
+ let desc = ChannelDescriptor {
+ name: config::LOBBY_CHANNEL_NAME,
+ description: config::LOBBY_CHANNEL_DESCRIPTION,
+ kind: ChannelType::Voice,
+ parent: Some(meta_channel_id),
+ };
+ get_channel_or_create(ctx, guild, desc, |cache| &mut cache.lobby).await
+ }
+
#[command]
#[aliases("hepl", "?", "h")]
async fn help(ctx: &Context, msg: &Message) -> CommandResult {
@@ -97,17 +208,17 @@ mod commands {
#[aliases("craete", "+", "c", "init")]
async fn create(ctx: &Context, msg: &Message) -> CommandResult {
let guild = get_guild(ctx, msg).await?;
- let meta_channel = create_channel(
- ctx,
- &guild,
- ChannelDescriptor {
- name: config::META_CHANNEL_NAME,
- description: config::META_CHANNEL_DESCRIPTION,
- kind: ChannelType::Category,
- parent: None,
- },
- )
- .await?;
+ let meta_channel = get_meta_channel_or_create(ctx, &guild).await?;
+
+ let lobby_channel = get_lobby_channel_or_create(ctx, &guild, meta_channel.id()).await?;
+
+ Ok(())
+ }
+
+ #[command]
+ #[aliases("strat", "s", "r", "run", "rnu")]
+ async fn start(ctx: &Context, msg: &Message) -> CommandResult {
+ let guild = get_guild(ctx, msg).await?;
Ok(())
}