use serenity::model::prelude::*; use serenity::prelude::*; use std::collections::{HashSet, VecDeque}; use std::sync::{Mutex, OnceLock}; use crate::commands::moderation_tools; use crate::commands::remove_activity; use crate::commands::{ addrole, alias, ancien, antilink, antimassmention, antiraideautoconfig, antispam, autobackup, autoconfiglog, autopublish, autopublishoff, autopublishon, autoreact, backup, badwords, ban, banlist, banner, bl, blinfo, boostembed, boosters, boostlog, bringall, button, calc, change, changeall, changereset, channel, choose, claim, cleanup, clear_all_sanctions, clear_badwords, clear_bl, clear_limit, clear_messages, clear_owners, clear_perms, clear_sanctions, close, cmute, compet, create, del_sanction, delperm, delrole, derank, discussion, dnd, embed, emoji, end, endgiveaway, giveaway, help, helpsetting, hide, hideall, idle, invisible, invite, join, kick, leave, leave_settings, link, listen, loading, lock, lockall, mainprefix, massiverole, member, messagelog, modlog, mp, mpdelete, mpsent, mpsettings, mute, mutelist, muterole, newsticker, noderank, noderankadd, noderankdel, nolog, online, owner, perms, pic, piconly, piconlyadd, piconlydel, ping, playto, prefix, public, punish, punishadd, punishdel, punishsetup, raidlog, rename, renew, reroll, resetantiraide, role, rolelog, rolemembers, rolemenu, sanctions, say, serverbanner, serverinfo, serverlist, serverpic, set_boostembed, set_modlogs, set_muterole, setbanner, setname, setperm, setpic, setprofil, shadowbot, showpics, slowmode, snipe, spam, stream, strikes, suggestion, suggestionsettings, sync, tempban, tempcmute, tempmute, temprole, tempvoc, tempvoc_cmd, theme, ticket, ticket_member, tickets, timeout, unalias, unban, unbanall, unbl, uncmute, unhide, unhideall, unlock, unlockall, unmassiverole, unmute, unmuteall, unowner, untemprole, user, viewlogs, vocinfo, voicekick, voicelog, voicemove, warn, watch, }; use crate::commands::{alladmins, allbots, allperms, botadmins}; use crate::db::{DbPoolKey, upsert_message_observed}; use crate::permissions; const PROCESSED_CACHE_MAX: usize = 8192; static PROCESSED_MESSAGES: OnceLock> = OnceLock::new(); struct ProcessedMessages { order: VecDeque, seen: HashSet, } impl ProcessedMessages { fn new() -> Self { Self { order: VecDeque::with_capacity(PROCESSED_CACHE_MAX), seen: HashSet::with_capacity(PROCESSED_CACHE_MAX), } } } fn should_process_message(message_id: MessageId) -> bool { let lock = PROCESSED_MESSAGES.get_or_init(|| Mutex::new(ProcessedMessages::new())); let mut cache = lock.lock().expect("processed message cache poisoned"); let id = message_id.get(); if cache.seen.contains(&id) { return false; } cache.seen.insert(id); cache.order.push_back(id); while cache.order.len() > PROCESSED_CACHE_MAX { if let Some(oldest) = cache.order.pop_front() { cache.seen.remove(&oldest); } } true } pub async fn handle_message(ctx: &Context, msg: &Message) { if !should_process_message(msg.id) { return; } if crate::commands::admin_service::enforce_blacklist_on_message(ctx, msg).await { return; } let bot_id = ctx.cache.current_user().id; if let Some(pool) = { let data = ctx.data.read().await; data.get::().cloned() } { let _ = upsert_message_observed(&pool, bot_id, msg).await; } if msg.author.bot { return; } if let Some(guild_id) = msg.guild_id { ancien::maybe_assign_ancien_role(ctx, guild_id, msg.author.id).await; } let content = msg.content.trim(); let prefix_value = permissions::resolve_prefix(ctx, msg.guild_id).await; if piconly::enforce_piconly_message(ctx, msg, content, &prefix_value).await { return; } crate::commands::advanced_tools::apply_autoreacts(ctx, msg).await; crate::commands::advanced_tools::maybe_run_maintenance(ctx, msg.guild_id).await; moderation_tools::maybe_run_maintenance(ctx, msg.guild_id).await; if crate::commands::automod_service::enforce_automod_message(ctx, msg).await { return; } if !content.starts_with(&prefix_value) { return; } let without_prefix = content.trim_start_matches(&prefix_value).trim(); if without_prefix.is_empty() { return; } let mut parts = without_prefix.split_whitespace(); let typed_command = parts.next().unwrap_or("").to_lowercase(); let typed_args = parts.collect::>(); let mut command = typed_command; let args = typed_args; // Ne laisse pas un alias écraser une commande native. let native_commands = permissions::all_command_keys(); let is_native = native_commands.iter().any(|cmd| cmd == &command) || crate::commands::all_command_metadata() .into_iter() .any(|meta| meta.name.eq_ignore_ascii_case(&command)); if !is_native { if let Some(alias_target) = alias::resolve_command_alias_name(ctx, &command).await { command = alias_target; } else if let Some(default_target) = crate::commands::resolve_default_alias(&command) { command = default_target.to_string(); } } let command_key = permissions::command_key(&command, &args); if msg.guild_id.is_none() { let dm_metadata = crate::commands::command_metadata_by_key(&command_key) .or_else(|| { let mapped = match command_key.as_str() { "showpics" => Some("showpics"), "ticket_settings" => Some("ticket"), "ticket_add" => Some("add"), "ticket_remove" => Some("del"), "ticket_close" => Some("close"), _ => None, }; mapped.and_then(crate::commands::command_metadata_by_key) }) .or_else(|| crate::commands::command_metadata_by_key(&command)); if let Some(meta) = dm_metadata { if !meta.allow_in_dm { let embed = serenity::builder::CreateEmbed::new() .title("Commande indisponible en DM") .description(format!( "La commande `+{}` n'est pas autorisee en message prive.", command.replace('_', "") )) .color(0xED4245); crate::commands::common::send_embed(ctx, msg, embed).await; return; } } } let required = permissions::command_required_permission(ctx, &command_key).await; if !crate::commands::automod_service::public_command_allowed(ctx, msg, &command_key, required) .await { return; } let can_use = permissions::can_use_command(ctx, msg, &command_key).await; if !can_use { permissions::deny_permission(ctx, msg, &command_key, required).await; return; } match command.as_str() { "ticket" => ticket::handle_ticket_settings(ctx, msg, &args).await, "claim" => claim::handle_claim(ctx, msg, &args).await, "rename" => rename::handle_rename(ctx, msg, &args).await, "add" => ticket_member::handle_ticket_add(ctx, msg, &args).await, "delperm" => delperm::handle_delperm_command(ctx, msg, &args).await, "delsanction" => del_sanction::handle_del_sanction(ctx, msg, &args).await, "del" => ticket_member::handle_ticket_remove(ctx, msg, &args).await, "close" => close::handle_close(ctx, msg, &args).await, "tickets" => tickets::handle_tickets(ctx, msg, &args).await, "showpics" => showpics::handle_show_pics(ctx, msg, &args).await, "piconly" => piconly::handle_piconly(ctx, msg, &args).await, "piconlyadd" => piconlyadd::handle_piconlyadd_command(ctx, msg, &args).await, "piconlydel" => piconlydel::handle_piconlydel_command(ctx, msg, &args).await, "suggestion" => suggestion::handle_suggestion(ctx, msg, &args).await, "suggestionsettings" => { suggestionsettings::handle_suggestionsettings_command(ctx, msg, &args).await } "autopublish" => autopublish::handle_autopublish(ctx, msg, &args).await, "autopublishon" => autopublishon::handle_autopublishon_command(ctx, msg, &args).await, "autopublishoff" => autopublishoff::handle_autopublishoff_command(ctx, msg, &args).await, "tempvoccmd" => tempvoc_cmd::handle_tempvoc_cmd(ctx, msg, &args).await, "tempvoc" => tempvoc::handle_tempvoc(ctx, msg, &args).await, "ping" => ping::handle_ping(ctx, msg, &args).await, "timeout" => timeout::handle_timeout_toggle(ctx, msg, &args).await, "muterole" => muterole::handle_muterole(ctx, msg, &args).await, "antispam" => antispam::handle_antispam(ctx, msg, &args).await, "antiraideautoconfig" => { antiraideautoconfig::handle_antiraideautoconfig(ctx, msg, &args).await } "antilink" => antilink::handle_antilink(ctx, msg, &args).await, "antimassmention" => antimassmention::handle_antimassmention(ctx, msg, &args).await, "badwords" => badwords::handle_badwords(ctx, msg, &args).await, "spam" => spam::handle_spam_override(ctx, msg, &args).await, "link" => link::handle_link_override(ctx, msg, &args).await, "strikes" => strikes::handle_strikes(ctx, msg, &args).await, "punish" => punish::handle_punish(ctx, msg, &args).await, "punishsetup" => punishsetup::handle_punishsetup_command(ctx, msg, &args).await, "punishadd" => punishadd::handle_punishadd_command(ctx, msg, &args).await, "punishdel" => punishdel::handle_punishdel_command(ctx, msg, &args).await, "public" => public::handle_public(ctx, msg, &args).await, "resetantiraide" => resetantiraide::handle_resetantiraide(ctx, msg, &args).await, "allbots" => allbots::handle_allbots(ctx, msg, &args).await, "alladmins" => alladmins::handle_alladmins(ctx, msg, &args).await, "botadmins" => botadmins::handle_botadmins(ctx, msg, &args).await, "boosters" => boosters::handle_boosters(ctx, msg, &args).await, "rolemembers" => rolemembers::handle_rolemembers(ctx, msg, &args).await, "serverinfo" => serverinfo::handle_serverinfo(ctx, msg, &args).await, "vocinfo" => vocinfo::handle_vocinfo(ctx, msg, &args).await, "role" => role::handle_role(ctx, msg, &args).await, "rolemenu" => rolemenu::handle_rolemenu(ctx, msg, &args).await, "ancien" => ancien::handle_ancien(ctx, msg, &args).await, "channel" => channel::handle_channel(ctx, msg, &args).await, "user" => user::handle_user(ctx, msg, &args).await, "member" => member::handle_member(ctx, msg, &args).await, "pic" => pic::handle_pic(ctx, msg, &args).await, "banner" => banner::handle_banner(ctx, msg, &args).await, "serverpic" => serverpic::handle_serverpic(ctx, msg, &args).await, "serverbanner" => serverbanner::handle_serverbanner(ctx, msg, &args).await, "serverlist" => serverlist::handle_serverlist(ctx, msg, &args).await, "snipe" => snipe::handle_snipe(ctx, msg, &args).await, "emoji" => emoji::handle_emoji(ctx, msg, &args).await, "giveaway" => giveaway::handle_giveaway(ctx, msg, &args).await, "modlog" => modlog::handle_modlog(ctx, msg, &args).await, "messagelog" => messagelog::handle_messagelog(ctx, msg, &args).await, "voicelog" => voicelog::handle_voicelog(ctx, msg, &args).await, "boostlog" => boostlog::handle_boostlog(ctx, msg, &args).await, "rolelog" => rolelog::handle_rolelog(ctx, msg, &args).await, "raidlog" => raidlog::handle_raidlog(ctx, msg, &args).await, "autoconfiglog" => autoconfiglog::handle_autoconfiglog(ctx, msg).await, "joinsettings" => join::handle_join(ctx, msg, &args).await, "boostembed" => boostembed::handle_boostembed(ctx, msg, &args).await, "nolog" => nolog::handle_nolog(ctx, msg, &args).await, "sanctions" => sanctions::handle_sanctions(ctx, msg, &args).await, "endgiveaway" => endgiveaway::handle_endgiveaway_command(ctx, msg, &args).await, "end" => end::handle_end(ctx, msg, &args).await, "reroll" => reroll::handle_reroll(ctx, msg, &args).await, "choose" => choose::handle_choose(ctx, msg, &args).await, "embed" => embed::handle_embed(ctx, msg, &args).await, "backup" => backup::handle_backup(ctx, msg, &args).await, "autobackup" => autobackup::handle_autobackup(ctx, msg, &args).await, "loading" => loading::handle_loading(ctx, msg, &args).await, "create" => create::handle_create(ctx, msg, &args).await, "newsticker" => newsticker::handle_newsticker(ctx, msg, &args).await, "massiverole" => massiverole::handle_massiverole(ctx, msg, &args).await, "unmassiverole" => unmassiverole::handle_unmassiverole(ctx, msg, &args).await, "voicemove" => voicemove::handle_voicemove(ctx, msg, &args).await, "voicekick" => voicekick::handle_voicekick(ctx, msg, &args).await, "cleanup" => cleanup::handle_cleanup(ctx, msg, &args).await, "bringall" => bringall::handle_bringall(ctx, msg, &args).await, "renew" => renew::handle_renew(ctx, msg, &args).await, "unbanall" => unbanall::handle_unbanall(ctx, msg, &args).await, "warn" => { warn::handle_warn(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "warn", &args).await; } "mute" => { mute::handle_mute(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "mute", &args).await; } "tempmute" => { tempmute::handle_tempmute(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "tempmute", &args) .await; } "unmute" => { unmute::handle_unmute(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "unmute", &args).await; } "cmute" => { cmute::handle_cmute(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "cmute", &args).await; } "tempcmute" => { tempcmute::handle_tempcmute(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "tempcmute", &args) .await; } "uncmute" => { uncmute::handle_uncmute(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "uncmute", &args).await; } "mutelist" => { mutelist::handle_mutelist(ctx, msg).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "mutelist", &args) .await; } "unmuteall" => { unmuteall::handle_unmuteall(ctx, msg).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "unmuteall", &args) .await; } "kick" => { kick::handle_kick(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "kick", &args).await; } "ban" => { ban::handle_ban(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "ban", &args).await; } "tempban" => { tempban::handle_tempban(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "tempban", &args).await; } "unban" => { unban::handle_unban(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "unban", &args).await; } "banlist" => { banlist::handle_banlist(ctx, msg).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "banlist", &args).await; } "slowmode" => { slowmode::handle_slowmode(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "slowmode", &args) .await; } "lock" => { lock::handle_lock(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "lock", &args).await; } "unlock" => { unlock::handle_unlock(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "unlock", &args).await; } "lockall" => { lockall::handle_lockall(ctx, msg).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "lockall", &args).await; } "unlockall" => { unlockall::handle_unlockall(ctx, msg).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "unlockall", &args) .await; } "hide" => { hide::handle_hide(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "hide", &args).await; } "unhide" => { unhide::handle_unhide(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "unhide", &args).await; } "hideall" => { hideall::handle_hideall(ctx, msg).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "hideall", &args).await; } "unhideall" => { unhideall::handle_unhideall(ctx, msg).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "unhideall", &args) .await; } "addrole" => { addrole::handle_addrole(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "addrole", &args).await; } "delrole" => { delrole::handle_delrole(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "delrole", &args).await; } "derank" => { derank::handle_derank(ctx, msg, &args).await; crate::commands::logs_service::log_moderation_command(ctx, msg, "derank", &args).await; } "noderank" => noderank::handle_noderank(ctx, msg, &args).await, "noderankadd" => noderankadd::handle_noderankadd_command(ctx, msg, &args).await, "noderankdel" => noderankdel::handle_noderankdel_command(ctx, msg, &args).await, "temprole" => temprole::handle_temprole(ctx, msg, &args).await, "untemprole" => untemprole::handle_untemprole(ctx, msg, &args).await, "sync" => sync::handle_sync(ctx, msg, &args).await, "button" => button::handle_button(ctx, msg, &args).await, "autoreact" => autoreact::handle_autoreact(ctx, msg, &args).await, "calc" => calc::handle_calc(ctx, msg, &args).await, "shadowbot" => shadowbot::handle_shadowbot(ctx, msg, &args).await, "setperm" => setperm::handle_setperm_command(ctx, msg, &args).await, "setname" => setname::handle_setname_command(ctx, msg, &args).await, "setpic" => setpic::handle_setpic_command(ctx, msg, &args).await, "setbanner" => setbanner::handle_setbanner_command(ctx, msg, &args).await, "setprofil" => setprofil::handle_setprofil_command(ctx, msg, &args).await, "setmuterole" => set_muterole::handle_set_muterole(ctx, msg, &args).await, "setmodlogs" => set_modlogs::handle_set_modlogs(ctx, msg, &args).await, "setboostembed" => set_boostembed::handle_set_boostembed(ctx, msg, &args).await, "theme" => theme::handle_theme(ctx, msg, &args).await, "playto" => playto::handle_playto(ctx, msg, &args).await, "listen" => listen::handle_listen(ctx, msg, &args).await, "watch" => watch::handle_watch(ctx, msg, &args).await, "compet" => compet::handle_compet(ctx, msg, &args).await, "stream" => stream::handle_stream(ctx, msg, &args).await, "help" => help::handle_help(ctx, msg, &args).await, "helpsetting" => helpsetting::handle_helpsetting(ctx, msg, &args).await, "alias" => alias::handle_alias(ctx, msg, &args).await, "unalias" => unalias::handle_unalias_command(ctx, msg, &args).await, "mpsettings" => mpsettings::handle_mpsettings_command(ctx, msg, &args).await, "mpsent" => mpsent::handle_mpsent_command(ctx, msg, &args).await, "mpdelete" | "mpdel" => mpdelete::handle_mpdelete_command(ctx, msg, &args).await, "mp" => mp::handle_mp(ctx, msg, &args).await, "invite" => invite::handle_invite(ctx, msg, &args).await, "leavesettings" => leave_settings::handle_leave_settings(ctx, msg, &args).await, "leave" => leave::handle_leave(ctx, msg, &args).await, "viewlogs" => viewlogs::handle_viewlogs(ctx, msg, &args).await, "discussion" => discussion::handle_discussion(ctx, msg, &args).await, "removeactivity" => remove_activity::handle_remove_activity(ctx, msg).await, "online" => online::handle_online(ctx, msg).await, "idle" => idle::handle_idle(ctx, msg).await, "dnd" => dnd::handle_dnd(ctx, msg).await, "invisible" => invisible::handle_invisible(ctx, msg).await, "owner" => owner::handle_owner(ctx, msg, &args).await, "unowner" => unowner::handle_unowner(ctx, msg, &args).await, "bl" => bl::handle_bl(ctx, msg, &args).await, "unbl" => unbl::handle_unbl(ctx, msg, &args).await, "blinfo" => blinfo::handle_blinfo(ctx, msg, &args).await, "say" => say::handle_say(ctx, msg, &args).await, "changereset" => changereset::handle_changereset_command(ctx, msg, &args).await, "change" => change::handle_change(ctx, msg, &args).await, "changeall" => changeall::handle_changeall(ctx, msg, &args).await, "mainprefix" => mainprefix::handle_mainprefix(ctx, msg, &args).await, "prefix" => prefix::handle_prefix(ctx, msg, &args).await, "perms" => perms::handle_perms(ctx, msg, &args).await, "allperms" => allperms::handle_allperms(ctx, msg, &args).await, "clearowners" => clear_owners::handle_clear_owners(ctx, msg).await, "clearbl" => clear_bl::handle_clear_bl(ctx, msg).await, "clearperms" => clear_perms::handle_clear_perms(ctx, msg).await, "clearlimit" => clear_limit::handle_clear_limit(ctx, msg, &args).await, "clearbadwords" => clear_badwords::handle_clear_badwords(ctx, msg, &args).await, "clearsanctions" => clear_sanctions::handle_clear_sanctions(ctx, msg, &args).await, "clearallsanctions" => clear_all_sanctions::handle_clear_all_sanctions(ctx, msg).await, "clearmessages" => clear_messages::handle_clear_messages(ctx, msg, &args).await, "clear" => clear_messages::handle_clear_messages(ctx, msg, &args).await, _ => {} } }