removed all guild data related code

This commit is contained in:
jellywx 2021-10-26 21:10:14 +01:00
parent 44debf93c5
commit e36e718f28
11 changed files with 63 additions and 414 deletions

1
Cargo.lock generated
View File

@ -1201,7 +1201,6 @@ dependencies = [
"base64", "base64",
"chrono", "chrono",
"chrono-tz", "chrono-tz",
"dashmap",
"dotenv", "dotenv",
"env_logger", "env_logger",
"humantime", "humantime",

View File

@ -5,7 +5,6 @@ authors = ["jellywx <judesouthworth@pm.me>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
dashmap = "4.0"
dotenv = "0.15" dotenv = "0.15"
humantime = "2.1" humantime = "2.1"
tokio = { version = "1", features = ["process", "full"] } tokio = { version = "1", features = ["process", "full"] }

View File

@ -3,7 +3,6 @@ use regex_command_attr::command;
use serenity::{builder::CreateEmbedFooter, client::Context}; use serenity::{builder::CreateEmbedFooter, client::Context};
use crate::{ use crate::{
consts::DEFAULT_PREFIX,
framework::{CommandInvoke, CreateGenericResponse}, framework::{CommandInvoke, CreateGenericResponse},
models::CtxData, models::CtxData,
THEME_COLOR, THEME_COLOR,
@ -28,8 +27,6 @@ fn footer(ctx: &Context) -> impl FnOnce(&mut CreateEmbedFooter) -> &mut CreateEm
#[description("Get information about the bot")] #[description("Get information about the bot")]
#[group("Info")] #[group("Info")]
async fn info(ctx: &Context, invoke: &mut CommandInvoke) { async fn info(ctx: &Context, invoke: &mut CommandInvoke) {
let prefix = ctx.prefix(invoke.guild_id()).await;
let current_user = ctx.cache.current_user();
let footer = footer(ctx); let footer = footer(ctx);
let _ = invoke let _ = invoke
@ -38,18 +35,15 @@ async fn info(ctx: &Context, invoke: &mut CommandInvoke) {
CreateGenericResponse::new().embed(|e| { CreateGenericResponse::new().embed(|e| {
e.title("Info") e.title("Info")
.description(format!( .description(format!(
"Default prefix: `{default_prefix}` "Help: `/help`
Reset prefix: `@{user} prefix {default_prefix}`
Help: `{prefix}help`**Welcome to Reminder Bot!** **Welcome to Reminder Bot!**
Developer: <@203532103185465344> Developer: <@203532103185465344>
Icon: <@253202252821430272> Icon: <@253202252821430272>
Find me on https://discord.jellywx.com and on https://github.com/JellyWX :) Find me on https://discord.jellywx.com and on https://github.com/JellyWX :)
Invite the bot: https://invite.reminder-bot.com/ Invite the bot: https://invite.reminder-bot.com/
Use our dashboard: https://reminder-bot.com/", Use our dashboard: https://reminder-bot.com/",
default_prefix = *DEFAULT_PREFIX,
user = current_user.name,
prefix = prefix
)) ))
.footer(footer) .footer(footer)
.color(*THEME_COLOR) .color(*THEME_COLOR)

View File

@ -12,7 +12,7 @@ use crate::{
consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR}, consts::{EMBED_DESCRIPTION_MAX_LENGTH, THEME_COLOR},
framework::{CommandInvoke, CommandOptions, CreateGenericResponse, OptionValue}, framework::{CommandInvoke, CommandOptions, CreateGenericResponse, OptionValue},
hooks::{CHECK_GUILD_PERMISSIONS_HOOK, CHECK_MANAGED_PERMISSIONS_HOOK}, hooks::{CHECK_GUILD_PERMISSIONS_HOOK, CHECK_MANAGED_PERMISSIONS_HOOK},
models::{channel_data::ChannelData, command_macro::CommandMacro, CtxData}, models::{command_macro::CommandMacro, CtxData},
PopularTimezones, RecordingMacros, RegexFramework, SQLPool, PopularTimezones, RecordingMacros, RegexFramework, SQLPool,
}; };

View File

@ -11,7 +11,6 @@ use regex_command_attr::command;
use serenity::{builder::CreateEmbed, client::Context, model::channel::Channel}; use serenity::{builder::CreateEmbed, client::Context, model::channel::Channel};
use crate::{ use crate::{
check_subscription_on_message,
component_models::{ component_models::{
pager::{DelPager, LookPager, Pager}, pager::{DelPager, LookPager, Pager},
ComponentDataModel, DelSelector, ComponentDataModel, DelSelector,

View File

@ -10,7 +10,7 @@ const THEME_COLOR_FALLBACK: u32 = 0x8fb677;
use std::{collections::HashSet, env, iter::FromIterator}; use std::{collections::HashSet, env, iter::FromIterator};
use regex::{Regex, RegexBuilder}; use regex::Regex;
use serenity::http::AttachmentType; use serenity::http::AttachmentType;
lazy_static! { lazy_static! {
@ -21,31 +21,11 @@ lazy_static! {
env!("WEBHOOK_AVATAR", "WEBHOOK_AVATAR not provided for compilation") env!("WEBHOOK_AVATAR", "WEBHOOK_AVATAR not provided for compilation")
)) as &[u8], )) as &[u8],
env!("WEBHOOK_AVATAR"), env!("WEBHOOK_AVATAR"),
) )
.into(); .into();
pub static ref REGEX_CHANNEL: Regex = Regex::new(r#"^\s*<#(\d+)>\s*$"#).unwrap(); pub static ref REGEX_CHANNEL: Regex = Regex::new(r#"^\s*<#(\d+)>\s*$"#).unwrap();
pub static ref REGEX_ROLE: Regex = Regex::new(r#"<@&(\d+)>"#).unwrap(); pub static ref REGEX_ROLE: Regex = Regex::new(r#"<@&(\d+)>"#).unwrap();
pub static ref REGEX_CONTENT_SUBSTITUTION: Regex = Regex::new(r#"<<((?P<user>\d+)|(?P<role>.{1,100}))>>"#).unwrap();
pub static ref REGEX_CHANNEL_USER: Regex = Regex::new(r#"\s*<(#|@)(?:!)?(\d+)>\s*"#).unwrap(); pub static ref REGEX_CHANNEL_USER: Regex = Regex::new(r#"\s*<(#|@)(?:!)?(\d+)>\s*"#).unwrap();
pub static ref REGEX_NATURAL_COMMAND_1: Regex = RegexBuilder::new(
r#"(?P<time>.*?)(?:\s+)(?:send|say)(?:\s+)(?P<msg>.*?)(?:(?:\s+)to(?:\s+)(?P<mentions>((?:<@\d+>)|(?:<@!\d+>)|(?:<#\d+>)|(?:\s+))+))?$"#
)
.dot_matches_new_line(true)
.build()
.unwrap();
pub static ref REGEX_NATURAL_COMMAND_2: Regex = RegexBuilder::new(
r#"(?P<msg>.*)(?:\s+)every(?:\s+)(?P<interval>.*?)(?:(?:\s+)(?:until|for)(?:\s+)(?P<expires>.*?))?$"#
)
.dot_matches_new_line(true)
.build()
.unwrap();
pub static ref SUBSCRIPTION_ROLES: HashSet<u64> = HashSet::from_iter( pub static ref SUBSCRIPTION_ROLES: HashSet<u64> = HashSet::from_iter(
env::var("SUBSCRIPTION_ROLES") env::var("SUBSCRIPTION_ROLES")
.map(|var| var .map(|var| var
@ -54,35 +34,23 @@ lazy_static! {
.collect::<Vec<u64>>()) .collect::<Vec<u64>>())
.unwrap_or_else(|_| Vec::new()) .unwrap_or_else(|_| Vec::new())
); );
pub static ref CNC_GUILD: Option<u64> =
pub static ref CNC_GUILD: Option<u64> = env::var("CNC_GUILD") env::var("CNC_GUILD").map(|var| var.parse::<u64>().ok()).ok().flatten();
.map(|var| var.parse::<u64>().ok())
.ok()
.flatten();
pub static ref MIN_INTERVAL: i64 = env::var("MIN_INTERVAL") pub static ref MIN_INTERVAL: i64 = env::var("MIN_INTERVAL")
.ok() .ok()
.map(|inner| inner.parse::<i64>().ok()) .map(|inner| inner.parse::<i64>().ok())
.flatten() .flatten()
.unwrap_or(600); .unwrap_or(600);
pub static ref MAX_TIME: i64 = env::var("MAX_TIME") pub static ref MAX_TIME: i64 = env::var("MAX_TIME")
.ok() .ok()
.map(|inner| inner.parse::<i64>().ok()) .map(|inner| inner.parse::<i64>().ok())
.flatten() .flatten()
.unwrap_or(60 * 60 * 24 * 365 * 50); .unwrap_or(60 * 60 * 24 * 365 * 50);
pub static ref LOCAL_TIMEZONE: String = pub static ref LOCAL_TIMEZONE: String =
env::var("LOCAL_TIMEZONE").unwrap_or_else(|_| "UTC".to_string()); env::var("LOCAL_TIMEZONE").unwrap_or_else(|_| "UTC".to_string());
pub static ref THEME_COLOR: u32 = env::var("THEME_COLOR")
pub static ref DEFAULT_PREFIX: String = .map_or(THEME_COLOR_FALLBACK, |inner| u32::from_str_radix(&inner, 16)
env::var("DEFAULT_PREFIX").unwrap_or_else(|_| "$".to_string()); .unwrap_or(THEME_COLOR_FALLBACK));
pub static ref THEME_COLOR: u32 = env::var("THEME_COLOR").map_or(
THEME_COLOR_FALLBACK,
|inner| u32::from_str_radix(&inner, 16).unwrap_or(THEME_COLOR_FALLBACK)
);
pub static ref PYTHON_LOCATION: String = pub static ref PYTHON_LOCATION: String =
env::var("PYTHON_LOCATION").unwrap_or_else(|_| "venv/bin/python3".to_string()); env::var("PYTHON_LOCATION").unwrap_or_else(|_| "venv/bin/python3".to_string());
} }

View File

@ -7,7 +7,7 @@ use std::{
}; };
use log::info; use log::info;
use regex::{Match, Regex, RegexBuilder}; use regex::{Regex, RegexBuilder};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serenity::{ use serenity::{
async_trait, async_trait,
@ -16,11 +16,11 @@ use serenity::{
client::Context, client::Context,
framework::Framework, framework::Framework,
futures::prelude::future::BoxFuture, futures::prelude::future::BoxFuture,
http::{CacheHttp, Http}, http::Http,
model::{ model::{
channel::Message, channel::Message,
guild::{Guild, Member}, guild::{Guild, Member},
id::{ChannelId, GuildId, MessageId, RoleId, UserId}, id::{ChannelId, GuildId, RoleId, UserId},
interactions::{ interactions::{
application_command::{ application_command::{
ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType, ApplicationCommand, ApplicationCommandInteraction, ApplicationCommandOptionType,
@ -34,7 +34,7 @@ use serenity::{
Result as SerenityResult, Result as SerenityResult,
}; };
use crate::{models::CtxData, LimitExecutors}; use crate::LimitExecutors;
pub struct CreateGenericResponse { pub struct CreateGenericResponse {
content: String, content: String,
@ -89,7 +89,6 @@ impl CreateGenericResponse {
enum InvokeModel { enum InvokeModel {
Slash(ApplicationCommandInteraction), Slash(ApplicationCommandInteraction),
Component(MessageComponentInteraction), Component(MessageComponentInteraction),
Text(Message),
} }
#[derive(Clone)] #[derive(Clone)]
@ -108,10 +107,6 @@ impl CommandInvoke {
Self { model: InvokeModel::Slash(interaction), already_responded: false, deferred: false } Self { model: InvokeModel::Slash(interaction), already_responded: false, deferred: false }
} }
fn msg(msg: Message) -> Self {
Self { model: InvokeModel::Text(msg), already_responded: false, deferred: false }
}
pub async fn defer(&mut self, http: impl AsRef<Http>) { pub async fn defer(&mut self, http: impl AsRef<Http>) {
if !self.deferred { if !self.deferred {
match &self.model { match &self.model {
@ -133,7 +128,6 @@ impl CommandInvoke {
self.deferred = true; self.deferred = true;
} }
InvokeModel::Text(_) => (),
} }
} }
} }
@ -142,7 +136,6 @@ impl CommandInvoke {
match &self.model { match &self.model {
InvokeModel::Slash(i) => i.channel_id, InvokeModel::Slash(i) => i.channel_id,
InvokeModel::Component(i) => i.channel_id, InvokeModel::Component(i) => i.channel_id,
InvokeModel::Text(m) => m.channel_id,
} }
} }
@ -150,7 +143,6 @@ impl CommandInvoke {
match &self.model { match &self.model {
InvokeModel::Slash(i) => i.guild_id, InvokeModel::Slash(i) => i.guild_id,
InvokeModel::Component(i) => i.guild_id, InvokeModel::Component(i) => i.guild_id,
InvokeModel::Text(m) => m.guild_id,
} }
} }
@ -162,15 +154,13 @@ impl CommandInvoke {
match &self.model { match &self.model {
InvokeModel::Slash(i) => i.user.id, InvokeModel::Slash(i) => i.user.id,
InvokeModel::Component(i) => i.user.id, InvokeModel::Component(i) => i.user.id,
InvokeModel::Text(m) => m.author.id,
} }
} }
pub async fn member(&self, cache_http: impl CacheHttp) -> Option<Member> { pub fn member(&self) -> Option<Member> {
match &self.model { match &self.model {
InvokeModel::Slash(i) => i.member.clone(), InvokeModel::Slash(i) => i.member.clone(),
InvokeModel::Component(i) => i.member.clone(), InvokeModel::Component(i) => i.member.clone(),
InvokeModel::Text(m) => m.member(cache_http).await.ok(),
} }
} }
@ -264,26 +254,6 @@ impl CommandInvoke {
}) })
.await .await
.map(|_| ()), .map(|_| ()),
InvokeModel::Text(m) => m
.channel_id
.send_message(http, |m| {
m.content(generic_response.content);
if let Some(embed) = generic_response.embed {
m.set_embed(embed);
}
if let Some(components) = generic_response.components {
m.components(|c| {
*c = components;
c
});
}
m
})
.await
.map(|_| ()),
}?; }?;
self.already_responded = true; self.already_responded = true;
@ -484,9 +454,6 @@ pub enum HookResult {
type SlashCommandFn = type SlashCommandFn =
for<'fut> fn(&'fut Context, &'fut mut CommandInvoke, CommandOptions) -> BoxFuture<'fut, ()>; for<'fut> fn(&'fut Context, &'fut mut CommandInvoke, CommandOptions) -> BoxFuture<'fut, ()>;
type TextCommandFn =
for<'fut> fn(&'fut Context, &'fut mut CommandInvoke, String) -> BoxFuture<'fut, ()>;
type MultiCommandFn = for<'fut> fn(&'fut Context, &'fut mut CommandInvoke) -> BoxFuture<'fut, ()>; type MultiCommandFn = for<'fut> fn(&'fut Context, &'fut mut CommandInvoke) -> BoxFuture<'fut, ()>;
pub type HookFn = for<'fut> fn( pub type HookFn = for<'fut> fn(
@ -497,16 +464,9 @@ pub type HookFn = for<'fut> fn(
pub enum CommandFnType { pub enum CommandFnType {
Slash(SlashCommandFn), Slash(SlashCommandFn),
Text(TextCommandFn),
Multi(MultiCommandFn), Multi(MultiCommandFn),
} }
impl CommandFnType {
pub fn is_slash(&self) -> bool {
!matches!(self, CommandFnType::Text(_))
}
}
pub struct Hook { pub struct Hook {
pub fun: HookFn, pub fun: HookFn,
pub uuid: u128, pub uuid: u128,
@ -697,7 +657,6 @@ impl RegexFramework {
commands: &'a mut CreateApplicationCommands, commands: &'a mut CreateApplicationCommands,
) -> &'a mut CreateApplicationCommands { ) -> &'a mut CreateApplicationCommands {
for command in &self.commands { for command in &self.commands {
if command.fun.is_slash() {
commands.create_application_command(|c| { commands.create_application_command(|c| {
c.name(command.names[0]).description(command.desc); c.name(command.names[0]).description(command.desc);
@ -735,7 +694,6 @@ impl RegexFramework {
c c
}); });
} }
}
commands commands
} }
@ -798,7 +756,6 @@ impl RegexFramework {
match command.fun { match command.fun {
CommandFnType::Slash(t) => t(&ctx, &mut command_invoke, args).await, CommandFnType::Slash(t) => t(&ctx, &mut command_invoke, args).await,
CommandFnType::Multi(m) => m(&ctx, &mut command_invoke).await, CommandFnType::Multi(m) => m(&ctx, &mut command_invoke).await,
_ => (),
} }
ctx.drop_executing(user_id).await; ctx.drop_executing(user_id).await;
@ -820,85 +777,11 @@ impl RegexFramework {
match command.fun { match command.fun {
CommandFnType::Slash(t) => t(&ctx, command_invoke, command_options).await, CommandFnType::Slash(t) => t(&ctx, command_invoke, command_options).await,
CommandFnType::Multi(m) => m(&ctx, command_invoke).await, CommandFnType::Multi(m) => m(&ctx, command_invoke).await,
_ => (),
} }
} }
} }
#[async_trait] #[async_trait]
impl Framework for RegexFramework { impl Framework for RegexFramework {
async fn dispatch(&self, ctx: Context, msg: Message) { async fn dispatch(&self, _ctx: Context, _msg: Message) {}
async fn check_prefix(ctx: &Context, guild: &Guild, prefix_opt: Option<Match<'_>>) -> bool {
if let Some(prefix) = prefix_opt {
let guild_prefix = ctx.prefix(Some(guild.id)).await;
guild_prefix.as_str() == prefix.as_str()
} else {
true
}
}
// gate to prevent analysing messages unnecessarily
if (msg.author.bot && self.ignore_bots) || msg.content.is_empty() {
return;
}
let user_id = msg.author.id;
let mut invoke = CommandInvoke::msg(msg.clone());
// Guild Command
if let Some(guild) = msg.guild(&ctx) {
if let Some(full_match) = self.command_matcher.captures(&msg.content) {
if check_prefix(&ctx, &guild, full_match.name("prefix")).await {
let command = self
.commands_map
.get(&full_match.name("cmd").unwrap().as_str().to_lowercase())
.unwrap();
let channel_data = ctx.channel_data(invoke.channel_id()).await.unwrap();
if !command.can_blacklist || !channel_data.blacklisted {
let args =
full_match.name("args").map(|m| m.as_str()).unwrap_or("").to_string();
if msg.id == MessageId(0) || !ctx.check_executing(user_id).await {
ctx.set_executing(user_id).await;
match command.fun {
CommandFnType::Text(t) => t(&ctx, &mut invoke, args).await,
CommandFnType::Multi(m) => m(&ctx, &mut invoke).await,
_ => {}
};
ctx.drop_executing(user_id).await;
}
}
}
}
}
// DM Command
else if self.dm_enabled {
if let Some(full_match) = self.dm_regex_matcher.captures(&msg.content[..]) {
let command = self
.commands_map
.get(&full_match.name("cmd").unwrap().as_str().to_lowercase())
.unwrap();
let args = full_match.name("args").map(|m| m.as_str()).unwrap_or("").to_string();
let user_id = invoke.author_id();
if msg.id == MessageId(0) || !ctx.check_executing(user_id).await {
ctx.set_executing(user_id).await;
match command.fun {
CommandFnType::Text(t) => t(&ctx, &mut invoke, args).await,
CommandFnType::Multi(m) => m(&ctx, &mut invoke).await,
_ => {}
};
ctx.drop_executing(user_id).await;
}
}
}
}
} }

View File

@ -107,7 +107,7 @@ pub async fn check_managed_permissions(
return HookResult::Continue; return HookResult::Continue;
} }
let member = invoke.member(&ctx).await.unwrap(); let member = invoke.member().unwrap();
let pool = ctx let pool = ctx
.data .data

View File

@ -13,19 +13,17 @@ mod time_parser;
use std::{collections::HashMap, env, sync::Arc, time::Instant}; use std::{collections::HashMap, env, sync::Arc, time::Instant};
use chrono_tz::Tz; use chrono_tz::Tz;
use dashmap::DashMap;
use dotenv::dotenv; use dotenv::dotenv;
use log::info; use log::info;
use serenity::{ use serenity::{
async_trait, async_trait,
cache::Cache,
client::{bridge::gateway::GatewayIntents, Client}, client::{bridge::gateway::GatewayIntents, Client},
futures::TryFutureExt, futures::TryFutureExt,
http::{client::Http, CacheHttp}, http::{client::Http, CacheHttp},
model::{ model::{
channel::{GuildChannel, Message}, channel::GuildChannel,
gateway::{Activity, Ready}, gateway::{Activity, Ready},
guild::{Guild, GuildUnavailable}, guild::Guild,
id::{GuildId, UserId}, id::{GuildId, UserId},
interactions::Interaction, interactions::Interaction,
}, },
@ -38,17 +36,11 @@ use tokio::sync::RwLock;
use crate::{ use crate::{
commands::{info_cmds, moderation_cmds, reminder_cmds, todo_cmds}, commands::{info_cmds, moderation_cmds, reminder_cmds, todo_cmds},
component_models::ComponentDataModel, component_models::ComponentDataModel,
consts::{CNC_GUILD, DEFAULT_PREFIX, SUBSCRIPTION_ROLES, THEME_COLOR}, consts::{CNC_GUILD, SUBSCRIPTION_ROLES, THEME_COLOR},
framework::RegexFramework, framework::RegexFramework,
models::{command_macro::CommandMacro, guild_data::GuildData}, models::command_macro::CommandMacro,
}; };
struct GuildDataCache;
impl TypeMapKey for GuildDataCache {
type Value = Arc<DashMap<GuildId, Arc<RwLock<GuildData>>>>;
}
struct SQLPool; struct SQLPool;
impl TypeMapKey for SQLPool { impl TypeMapKey for SQLPool {
@ -156,20 +148,6 @@ DELETE FROM channels WHERE channel = ?
if is_new { if is_new {
let guild_id = guild.id.as_u64().to_owned(); let guild_id = guild.id.as_u64().to_owned();
{
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
GuildData::from_guild(guild, &pool).await.unwrap_or_else(|_| {
panic!("Failed to create new guild object for {}", guild_id)
});
}
if let Ok(token) = env::var("DISCORDBOTS_TOKEN") { if let Ok(token) = env::var("DISCORDBOTS_TOKEN") {
let shard_count = ctx.cache.shard_count(); let shard_count = ctx.cache.shard_count();
let current_shard_id = shard_id(guild_id, shard_count); let current_shard_id = shard_id(guild_id, shard_count);
@ -214,34 +192,6 @@ DELETE FROM channels WHERE channel = ?
} }
} }
async fn guild_delete(
&self,
ctx: Context,
deleted_guild: GuildUnavailable,
_guild: Option<Guild>,
) {
let pool = ctx
.data
.read()
.await
.get::<SQLPool>()
.cloned()
.expect("Could not get SQLPool from data");
let guild_data_cache = ctx.data.read().await.get::<GuildDataCache>().cloned().unwrap();
guild_data_cache.remove(&deleted_guild.id);
sqlx::query!(
"
DELETE FROM guilds WHERE guild = ?
",
deleted_guild.id.as_u64()
)
.execute(&pool)
.await
.unwrap();
}
async fn ready(&self, ctx: Context, _: Ready) { async fn ready(&self, ctx: Context, _: Ready) {
ctx.set_activity(Activity::watching("for /remind")).await; ctx.set_activity(Activity::watching("for /remind")).await;
} }
@ -288,7 +238,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let dm_enabled = env::var("DM_ENABLED").map_or(true, |var| var == "1"); let dm_enabled = env::var("DM_ENABLED").map_or(true, |var| var == "1");
let framework = RegexFramework::new(logged_in_id) let framework = RegexFramework::new(logged_in_id)
.default_prefix(DEFAULT_PREFIX.clone()) .default_prefix("")
.case_insensitive(env::var("CASE_INSENSITIVE").map_or(true, |var| var == "1")) .case_insensitive(env::var("CASE_INSENSITIVE").map_or(true, |var| var == "1"))
.ignore_bots(env::var("IGNORE_BOTS").map_or(true, |var| var == "1")) .ignore_bots(env::var("IGNORE_BOTS").map_or(true, |var| var == "1"))
.debug_guild(env::var("DEBUG_GUILD").map_or(None, |g| { .debug_guild(env::var("DEBUG_GUILD").map_or(None, |g| {
@ -337,8 +287,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
.expect("Error occurred creating client"); .expect("Error occurred creating client");
{ {
let guild_data_cache = dashmap::DashMap::new();
let pool = MySqlPool::connect( let pool = MySqlPool::connect(
&env::var("DATABASE_URL").expect("Missing DATABASE_URL from environment"), &env::var("DATABASE_URL").expect("Missing DATABASE_URL from environment"),
) )
@ -357,7 +305,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut data = client.data.write().await; let mut data = client.data.write().await;
data.insert::<GuildDataCache>(Arc::new(guild_data_cache));
data.insert::<CurrentlyExecuting>(Arc::new(RwLock::new(HashMap::new()))); data.insert::<CurrentlyExecuting>(Arc::new(RwLock::new(HashMap::new())));
data.insert::<SQLPool>(pool); data.insert::<SQLPool>(pool);
data.insert::<PopularTimezones>(Arc::new(popular_timezones)); data.insert::<PopularTimezones>(Arc::new(popular_timezones));
@ -415,15 +362,3 @@ pub async fn check_subscription(cache_http: impl CacheHttp, user_id: impl Into<U
true true
} }
} }
pub async fn check_subscription_on_message(
cache_http: impl CacheHttp + AsRef<Cache>,
msg: &Message,
) -> bool {
check_subscription(&cache_http, &msg.author).await
|| if let Some(guild) = msg.guild(&cache_http) {
check_subscription(&cache_http, guild.owner_id).await
} else {
false
}
}

View File

@ -1,77 +0,0 @@
use log::error;
use serenity::model::guild::Guild;
use sqlx::MySqlPool;
use crate::consts::DEFAULT_PREFIX;
pub struct GuildData {
pub id: u32,
pub name: Option<String>,
pub prefix: String,
}
impl GuildData {
pub async fn from_guild(guild: Guild, pool: &MySqlPool) -> Result<Self, sqlx::Error> {
let guild_id = guild.id.as_u64().to_owned();
match sqlx::query_as!(
Self,
"
SELECT id, name, prefix FROM guilds WHERE guild = ?
",
guild_id
)
.fetch_one(pool)
.await
{
Ok(mut g) => {
g.name = Some(guild.name);
Ok(g)
}
Err(sqlx::Error::RowNotFound) => {
sqlx::query!(
"
INSERT INTO guilds (guild, name, prefix) VALUES (?, ?, ?)
",
guild_id,
guild.name,
*DEFAULT_PREFIX
)
.execute(&pool.clone())
.await?;
Ok(sqlx::query_as!(
Self,
"
SELECT id, name, prefix FROM guilds WHERE guild = ?
",
guild_id
)
.fetch_one(pool)
.await?)
}
Err(e) => {
error!("Unexpected error in guild query: {:?}", e);
Err(e)
}
}
}
pub async fn commit_changes(&self, pool: &MySqlPool) {
sqlx::query!(
"
UPDATE guilds SET name = ?, prefix = ? WHERE id = ?
",
self.name,
self.prefix,
self.id
)
.execute(pool)
.await
.unwrap();
}
}

View File

@ -1,35 +1,23 @@
pub mod channel_data; pub mod channel_data;
pub mod command_macro; pub mod command_macro;
pub mod guild_data;
pub mod reminder; pub mod reminder;
pub mod timer; pub mod timer;
pub mod user_data; pub mod user_data;
use std::sync::Arc;
use chrono_tz::Tz; use chrono_tz::Tz;
use serenity::{ use serenity::{
async_trait, async_trait,
model::id::{ChannelId, GuildId, UserId}, model::id::{ChannelId, UserId},
prelude::Context, prelude::Context,
}; };
use tokio::sync::RwLock;
use crate::{ use crate::{
consts::DEFAULT_PREFIX, models::{channel_data::ChannelData, user_data::UserData},
models::{channel_data::ChannelData, guild_data::GuildData, user_data::UserData}, SQLPool,
GuildDataCache, SQLPool,
}; };
#[async_trait] #[async_trait]
pub trait CtxData { pub trait CtxData {
async fn guild_data<G: Into<GuildId> + Send + Sync>(
&self,
guild_id: G,
) -> Result<Arc<RwLock<GuildData>>, sqlx::Error>;
async fn prefix<G: Into<GuildId> + Send + Sync>(&self, guild_id: Option<G>) -> String;
async fn user_data<U: Into<UserId> + Send + Sync>( async fn user_data<U: Into<UserId> + Send + Sync>(
&self, &self,
user_id: U, user_id: U,
@ -45,45 +33,6 @@ pub trait CtxData {
#[async_trait] #[async_trait]
impl CtxData for Context { impl CtxData for Context {
async fn guild_data<G: Into<GuildId> + Send + Sync>(
&self,
guild_id: G,
) -> Result<Arc<RwLock<GuildData>>, sqlx::Error> {
let guild_id = guild_id.into();
let guild = guild_id.to_guild_cached(&self.cache).unwrap();
let guild_cache = self.data.read().await.get::<GuildDataCache>().cloned().unwrap();
let x = if let Some(guild_data) = guild_cache.get(&guild_id) {
Ok(guild_data.clone())
} else {
let pool = self.data.read().await.get::<SQLPool>().cloned().unwrap();
match GuildData::from_guild(guild, &pool).await {
Ok(d) => {
let lock = Arc::new(RwLock::new(d));
guild_cache.insert(guild_id, lock.clone());
Ok(lock)
}
Err(e) => Err(e),
}
};
x
}
async fn prefix<G: Into<GuildId> + Send + Sync>(&self, guild_id: Option<G>) -> String {
if let Some(guild_id) = guild_id {
self.guild_data(guild_id).await.unwrap().read().await.prefix.clone()
} else {
DEFAULT_PREFIX.clone()
}
}
async fn user_data<U: Into<UserId> + Send + Sync>( async fn user_data<U: Into<UserId> + Send + Sync>(
&self, &self,
user_id: U, user_id: U,