package stream.flarebot.flarebot; import io.prometheus.client.Histogram; import net.dv8tion.jda.core.EmbedBuilder; import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.OnlineStatus; import net.dv8tion.jda.core.Permission; import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.Message; import net.dv8tion.jda.core.entities.MessageEmbed; import net.dv8tion.jda.core.entities.MessageReaction; import net.dv8tion.jda.core.entities.Role; import net.dv8tion.jda.core.entities.TextChannel; import net.dv8tion.jda.core.entities.VoiceChannel; import net.dv8tion.jda.core.events.DisconnectEvent; import net.dv8tion.jda.core.events.Event; import net.dv8tion.jda.core.events.ReadyEvent; import net.dv8tion.jda.core.events.StatusChangeEvent; import net.dv8tion.jda.core.events.guild.GuildJoinEvent; import net.dv8tion.jda.core.events.guild.GuildLeaveEvent; import net.dv8tion.jda.core.events.guild.member.GuildMemberJoinEvent; import net.dv8tion.jda.core.events.guild.voice.GuildVoiceJoinEvent; import net.dv8tion.jda.core.events.guild.voice.GuildVoiceLeaveEvent; import net.dv8tion.jda.core.events.guild.voice.GuildVoiceMoveEvent; import net.dv8tion.jda.core.events.message.guild.GenericGuildMessageEvent; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.core.events.message.react.MessageReactionAddEvent; import net.dv8tion.jda.core.events.role.RoleDeleteEvent; import net.dv8tion.jda.core.events.user.update.UserUpdateOnlineStatusEvent; import net.dv8tion.jda.core.exceptions.InsufficientPermissionException; import net.dv8tion.jda.core.hooks.ListenerAdapter; import okhttp3.Request; import okhttp3.RequestBody; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.MDC; import stream.flarebot.flarebot.commands.*; import stream.flarebot.flarebot.commands.music.*; import stream.flarebot.flarebot.commands.secret.update.*; import stream.flarebot.flarebot.database.RedisController; import stream.flarebot.flarebot.metrics.Metrics; import stream.flarebot.flarebot.mod.modlog.ModlogEvent; import stream.flarebot.flarebot.mod.modlog.ModlogHandler; import stream.flarebot.flarebot.objects.GuildWrapper; import stream.flarebot.flarebot.objects.PlayerCache; import stream.flarebot.flarebot.objects.Welcome; import stream.flarebot.flarebot.util.Constants; import stream.flarebot.flarebot.util.MessageUtils; import stream.flarebot.flarebot.util.RandomUtils; import stream.flarebot.flarebot.util.WebUtils; import stream.flarebot.flarebot.util.buttons.ButtonUtil; import stream.flarebot.flarebot.util.errorhandling.Markers; import stream.flarebot.flarebot.util.general.GeneralUtils; import stream.flarebot.flarebot.util.general.GuildUtils; import stream.flarebot.flarebot.util.general.VariableUtils; import stream.flarebot.flarebot.util.objects.ButtonGroup; import stream.flarebot.flarebot.util.votes.VoteUtil; import java.awt.Color; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; import java.util.stream.Collectors; public class Events extends ListenerAdapter { public static final ThreadGroup COMMAND_THREADS = new ThreadGroup("Command Threads"); private static final ExecutorService COMMAND_POOL = Executors.newFixedThreadPool(4, r -> new Thread(COMMAND_THREADS, r, "Command Pool-" + COMMAND_THREADS.activeCount())); private static final List<Long> removedByMe = new ArrayList<>(); private final Logger LOGGER = FlareBot.getLog(this.getClass()); private final Pattern multiSpace = Pattern.compile(" {2,}"); private final Pattern rip = Pattern.compile("\\brip( [a-zA-Z0-9]+)?\\b", Pattern.CASE_INSENSITIVE); private FlareBot flareBot; private Map<String, Integer> spamMap = new ConcurrentHashMap<>(); private final Map<Integer, Long> shardEventTime = new HashMap<>(); private final AtomicInteger commandCounter = new AtomicInteger(0); private Map<Long, Double> maxButtonClicksPerSec = new HashMap<>(); private Map<Long, List<Double>> buttonClicksPerSec = new HashMap<>(); Events(FlareBot bot) { this.flareBot = bot; } @Override public void onMessageReactionAdd(MessageReactionAddEvent event) { if (!event.getGuild().getSelfMember().hasPermission(event.getTextChannel(), Permission.MESSAGE_READ)) return; if (event.getUser().isBot()) return; if (ButtonUtil.isButtonMessage(event.getMessageId())) { for (ButtonGroup.Button button : ButtonUtil.getButtonGroup(event.getMessageId()).getButtons()) { if ((event.getReactionEmote() != null && event.getReactionEmote().isEmote() && event.getReactionEmote().getIdLong() == button.getEmoteId()) || (button.getUnicode() != null && event.getReactionEmote().getName().equals(button.getUnicode()))) { try { if(event.getGuild().getSelfMember().hasPermission(event.getTextChannel(), Permission.MESSAGE_MANAGE)) { event.getChannel().getMessageById(event.getMessageId()).queue(message -> { for (MessageReaction reaction : message.getReactions()) { if (reaction.getReactionEmote().equals(event.getReactionEmote())) { reaction.removeReaction(event.getUser()).queue(); } } }); } } catch (InsufficientPermissionException e) { } button.onClick(ButtonUtil.getButtonGroup(event.getMessageId()).getOwner(), event.getUser()); String emote = event.getReactionEmote() != null ? event.getReactionEmote().getName() + "(" + event.getReactionEmote().getId() + ")" : button.getUnicode(); Metrics.buttonsPressed.labels(emote, ButtonUtil.getButtonGroup(event.getMessageId()).getName()).inc(); if (!event.getGuild().getSelfMember().hasPermission(Permission.MESSAGE_MANAGE)) { return; } return; } } } if (!FlareBotManager.instance().getGuild(event.getGuild().getId()).getBetaAccess()) return; if (!event.getReactionEmote().getName().equals("\uD83D\uDCCC")) return; // Check if it's a :pushpin: event.getChannel().getMessageById(event.getMessageId()).queue(message -> { MessageReaction reaction = message.getReactions().stream().filter(r -> r.getReactionEmote().getName() .equals(event.getReactionEmote().getName())).findFirst().orElse(null); if (reaction != null) { if (reaction.getCount() == 5) { message.pin().queue((aVoid) -> event.getChannel().getHistory().retrievePast(1).complete().get(0) .delete().queue()); } } }); } @Override public void onReady(ReadyEvent event) { if (FlareBot.instance().isReady()) FlareBot.instance().run(); } @Override public void onGuildMemberJoin(GuildMemberJoinEvent event) { if (event.getMember().getUser().isBot() || event.getMember().getUser().isFake()) return; PlayerCache cache = flareBot.getPlayerCache(event.getMember().getUser().getId()); cache.setLastSeen(LocalDateTime.now()); GuildWrapper wrapper = FlareBotManager.instance().getGuild(event.getGuild().getId()); if (wrapper == null) return; if (wrapper.isBlocked()) return; if (flareBot.getManager().getGuild(event.getGuild().getId()).getWelcome() != null) { Welcome welcome = wrapper.getWelcome(); if ((welcome.getChannelId() != null && Getters.getChannelById(welcome.getChannelId()) != null) || welcome.isDmEnabled()) { if (welcome.getChannelId() != null && Getters.getChannelById(welcome.getChannelId()) != null && welcome.isGuildEnabled()) { TextChannel channel = Getters.getChannelById(welcome.getChannelId()); if (channel == null || !channel.canTalk()) { welcome.setGuildEnabled(false); MessageUtils.sendPM(event.getGuild().getOwner().getUser(), "Cannot send welcome messages in " + (channel == null ? welcome.getChannelId() : channel.getAsMention()) + " due to this, welcomes have been disabled!"); return; } if (welcome.isGuildEnabled()) { String guildMsg = VariableUtils.parseVariables(welcome.getRandomGuildMessage(), wrapper, null, event.getUser()); // Deprecated values guildMsg = guildMsg .replace("%user%", event.getMember().getUser().getName()) .replace("%guild%", event.getGuild().getName()) .replace("%mention%", event.getMember().getUser().getAsMention()); channel.sendMessage(guildMsg).queue(); if (guildMsg.contains("%user%") || guildMsg.contains("%guild%") || guildMsg.contains("%mention%")) { MessageUtils.sendPM(event.getGuild().getOwner().getUser(), "Your guild welcome message contains deprecated variables! " + "Please check the docs at the link below for a list of all the " + "variables you can use!\n" + "https://docs.flarebot.stream/variables"); } } } if (welcome.isDmEnabled()) { if (event.getMember().getUser().isBot()) return; // We can't DM other bots. String dmMsg = VariableUtils.parseVariables(welcome.getRandomDmMessage(), wrapper, null, event.getUser()); // Deprecated values dmMsg = dmMsg .replace("%user%", event.getMember().getUser().getName()) .replace("%guild%", event.getGuild().getName()) .replace("%mention%", event.getMember().getUser().getAsMention()); MessageUtils.sendPM(event.getMember().getUser(), dmMsg); if (dmMsg.contains("%user%") || dmMsg.contains("%guild%") || dmMsg.contains("%mention%")) { MessageUtils.sendPM(event.getGuild().getOwner().getUser(), "Your DM welcome message contains deprecated variables! " + "Please check the docs at the link below for a list of all the " + "variables you can use!\n" + "https://docs.flarebot.stream/variables"); } } } else welcome.setGuildEnabled(false); } if (event.getMember().getUser().isBot()) return; if (!wrapper.getAutoAssignRoles().isEmpty()) { Set<String> autoAssignRoles = wrapper.getAutoAssignRoles(); List<Role> roles = new ArrayList<>(); for (String s : autoAssignRoles) { Role role = event.getGuild().getRoleById(s); if (role != null) { roles.add(role); } else autoAssignRoles.remove(s); } try { event.getGuild().getController().addRolesToMember(event.getMember(), roles).queue((n) -> { }, e1 -> handle(e1, event, roles)); StringBuilder sb = new StringBuilder("```\n"); for (Role role : roles) { sb.append(role.getName()).append(" (").append(role.getId()).append(")\n"); } sb.append("```"); ModlogHandler.getInstance().postToModlog(wrapper, ModlogEvent.FLAREBOT_AUTOASSIGN_ROLE, event.getUser(), new MessageEmbed.Field("Roles", sb.toString(), false)); } catch (Exception e1) { handle(e1, event, roles); } } } private void handle(Throwable e1, GuildMemberJoinEvent event, List<Role> roles) { if (!e1.getMessage().startsWith("Can't modify a role with higher")) { MessageUtils.sendPM(event.getGuild().getOwner().getUser(), "**Could not auto assign a role!**\n" + e1.getMessage()); return; } MessageUtils.sendPM(event.getGuild().getOwner().getUser(), "**Hello!\nI am here to tell you that I could not give the role(s) ```\n" + roles.stream().map(Role::getName).collect(Collectors.joining("\n")) + "\n``` to one of your new users!\n" + "Please move one of the following roles so they are higher up than any of the above: \n```" + event.getGuild().getSelfMember().getRoles().stream() .map(Role::getName) .collect(Collectors.joining("\n")) + "``` in your server's role tab!**"); } @Override public void onGuildJoin(GuildJoinEvent event) { if (event.getJDA().getStatus() == JDA.Status.CONNECTED && event.getGuild().getSelfMember().getJoinDate().plusMinutes(2).isAfter(OffsetDateTime.now())) { Constants.getGuildLogChannel().sendMessage(new EmbedBuilder() .setColor(new Color(96, 230, 144)) .setThumbnail(event.getGuild().getIconUrl()) .setFooter(event.getGuild().getId(), event.getGuild().getIconUrl()) .setAuthor(event.getGuild().getName(), null, event.getGuild().getIconUrl()) .setTimestamp(event.getGuild().getSelfMember().getJoinDate()) .setDescription("Guild Created: `" + event.getGuild().getName() + "` :smile: :heart:\n" + "Guild Owner: " + event.getGuild().getOwner().getUser().getName() + "\nGuild Members: " + event.getGuild().getMembers().size()).build()).queue(); } } @Override public void onGuildLeave(GuildLeaveEvent event) { Constants.getGuildLogChannel().sendMessage(new EmbedBuilder() .setColor(new Color(244, 23, 23)) .setThumbnail(event.getGuild().getIconUrl()) .setFooter(event.getGuild().getId(), event.getGuild().getIconUrl()) .setTimestamp(OffsetDateTime.now()) .setAuthor(event.getGuild().getName(), null, event.getGuild().getIconUrl()) .setDescription("Guild Deleted: `" + event.getGuild().getName() + "` L :broken_heart:\n" + "Guild Owner: " + (event.getGuild().getOwner() != null ? event.getGuild().getOwner().getUser().getName() : "Non-existent, they had to much L")).build()).queue(); } @Override public void onGuildVoiceJoin(GuildVoiceJoinEvent event) { if (event.getMember().getUser().equals(event.getJDA().getSelfUser()) && flareBot.getMusicManager() .hasPlayer(event.getGuild().getId())) { flareBot.getMusicManager().getPlayer(event.getGuild().getId()).setPaused(false); } if (event.getMember().getUser().equals(event.getJDA().getSelfUser())) return; if (event.getGuild().getSelfMember().getVoiceState().getChannel() == null) return; if (VoteUtil.contains(SkipCommand.getSkipUUID(), event.getGuild()) && event.getGuild().getSelfMember().getVoiceState().inVoiceChannel() && event.getChannelJoined().getIdLong() == event.getGuild().getSelfMember().getVoiceState().getChannel().getIdLong()) { VoteUtil.getVoteGroup(SkipCommand.getSkipUUID(), event.getGuild()).addAllowedUser(event.getMember().getUser()); } } @Override public void onGuildVoiceLeave(GuildVoiceLeaveEvent event) { if (event.getMember().getUser().getIdLong() == event.getJDA().getSelfUser().getIdLong()) { if (flareBot.getMusicManager().hasPlayer(event.getGuild().getId())) { flareBot.getMusicManager().getPlayer(event.getGuild().getId()).setPaused(true); } if (Getters.getActiveVoiceChannels() == 0 && FlareBot.NOVOICE_UPDATING.get()) { Constants.getImportantLogChannel() .sendMessage("I am now updating, there are no voice channels active!").queue(); UpdateCommand.update(true, null); } } else { handleVoiceConnectivity(event.getChannelLeft()); } if (event.getMember().getUser().equals(event.getJDA().getSelfUser())) return; if (VoteUtil.contains(SkipCommand.getSkipUUID(), event.getGuild()) && event.getChannelLeft().getIdLong() == event.getGuild().getSelfMember().getVoiceState().getChannel().getIdLong()) { VoteUtil.getVoteGroup(SkipCommand.getSkipUUID(), event.getGuild()).remoreAllowedUser(event.getMember().getUser()); } } private void handleVoiceConnectivity(VoiceChannel channel) { if (channel.getMembers().contains(channel.getGuild().getSelfMember()) && (channel.getMembers().size() < 2 || channel.getMembers() .stream().filter(m -> m.getUser().isBot()).count() == channel.getMembers().size())) { channel.getGuild().getAudioManager().closeAudioConnection(); } } @Override public void onGuildVoiceMove(GuildVoiceMoveEvent event) { handleVoiceConnectivity(event.getChannelJoined()); } @Override public void onGuildMessageReceived(GuildMessageReceivedEvent event) { PlayerCache cache = flareBot.getPlayerCache(event.getAuthor().getId()); cache.setLastMessage(LocalDateTime.from(event.getMessage().getCreationTime())); cache.setLastSeen(LocalDateTime.now()); cache.setLastSpokeGuild(event.getGuild().getId()); if (event.getAuthor().isBot()) return; String message = multiSpace.matcher(event.getMessage().getContentRaw()).replaceAll(" "); if (message.startsWith("" + FlareBotManager.instance().getGuild(getGuildId(event)).getPrefix())) { List<Permission> perms = event.getChannel().getGuild().getSelfMember().getPermissions(event.getChannel()); if (!perms.contains(Permission.ADMINISTRATOR)) { if (!perms.contains(Permission.MESSAGE_WRITE)) { return; } if (!perms.contains(Permission.MESSAGE_EMBED_LINKS)) { event.getChannel().sendMessage("Hey! I can't be used here." + "\nI do not have the `Embed Links` permission! Please go to your permissions and give me Embed Links." + "\nThanks :D").queue(); return; } } String command = message.substring(1); String[] args = new String[0]; if (message.contains(" ")) { command = command.substring(0, message.indexOf(" ") - 1); args = message.substring(message.indexOf(" ") + 1).split(" "); } Command cmd = FlareBot.getCommandManager().getCommand(command, event.getAuthor()); if (cmd != null) handleCommand(event, cmd, args); } else { if (FlareBotManager.instance().getGuild(getGuildId(event)).getPrefix() != Constants.COMMAND_CHAR && (message.startsWith("_prefix")) || message.startsWith(event.getGuild().getSelfMember().getAsMention())) { event.getChannel().sendMessage(MessageUtils.getEmbed(event.getAuthor()) .setDescription("The server prefix is `" + FlareBotManager .instance().getGuild(getGuildId(event)).getPrefix() + "`") .build()).queue(); } if (!message.isEmpty()) { RedisController.set(event.getMessageId(), GeneralUtils.getRedisMessageJson(event.getMessage()), "nx", "ex", 86400); } // Random fun stuff if (event.getGuild().getIdLong() == Constants.OFFICIAL_GUILD) { if (rip.matcher(message).find()) { event.getMessage().addReaction("\uD83C\uDDEB").queue(); // F } else if (message.toLowerCase().startsWith("i cri")) { event.getMessage().addReaction("\uD83D\uDE22").queue(); // Cry } else if ((message.toLowerCase().contains("bellend") || message.toLowerCase().contains("bollocks")) && RandomUtils.getInt(0, 20) == 20) { event.getMessage().addReaction("\uD83C\uDDEC\uD83C\uDDE7").queue(); // GB flag event.getMessage().addReaction("\u0023\u20E3").queue(); // # event.getMessage().addReaction("\u0031\u20E3").queue(); // 1 Constants.logEG("UK#1", null, event.getGuild(), event.getAuthor()); } else if (message.toLowerCase().equalsIgnoreCase("fuck") && RandomUtils.getInt(0, 100) == 100) { GeneralUtils.sendImage("https://flarebot.stream/img/pissed-off-thats-why.gif", "pissed-off-thats-why.gif", event.getAuthor()); Constants.logEG("Pissed Off", null, event.getGuild(), event.getAuthor()); } } } } @Override public void onUserUpdateOnlineStatus(UserUpdateOnlineStatusEvent event) { if (event.getOldOnlineStatus() == OnlineStatus.OFFLINE) flareBot.getPlayerCache(event.getUser().getId()).setLastSeen(LocalDateTime.now()); } @Override public void onStatusChange(StatusChangeEvent event) { if (FlareBot.EXITING.get()) return; String statusHook = FlareBot.getStatusHook(); if (statusHook == null) return; Request.Builder request = new Request.Builder().url(statusHook); RequestBody body = RequestBody.create(WebUtils.APPLICATION_JSON, new JSONObject() .put("content", String.format("onStatusChange: %s -> %s SHARD: %d", event.getOldStatus(), event.getNewStatus(), event.getJDA().getShardInfo() != null ? event.getJDA().getShardInfo().getShardId() : null)).toString()); WebUtils.postAsync(request.post(body)); } @Override public void onDisconnect(DisconnectEvent event) { if (event.isClosedByServer()) LOGGER.error(Markers.NO_ANNOUNCE, String.format("---- DISCONNECT [SERVER] CODE: [%d] %s%n", event.getServiceCloseFrame() .getCloseCode(), event .getCloseCode())); else LOGGER.error(Markers.NO_ANNOUNCE, String.format("---- DISCONNECT [CLIENT] CODE: [%d] %s%n", event.getClientCloseFrame() .getCloseCode(), event .getClientCloseFrame().getCloseReason())); } @Override public void onRoleDelete(RoleDeleteEvent event) { if (FlareBotManager.instance().getGuild(event.getGuild().getId()) == null) return; if (FlareBotManager.instance().getGuild(event.getGuild().getId()).getSelfAssignRoles().contains(event.getRole().getId())) { FlareBotManager.instance().getGuild(event.getGuild().getId()).getSelfAssignRoles().remove(event.getRole().getId()); } } private void handleCommand(GuildMessageReceivedEvent event, Command cmd, String[] args) { Metrics.commandsReceived.labels(cmd.getClass().getSimpleName()).inc(); GuildWrapper guild = flareBot.getManager().getGuild(event.getGuild().getId()); if (cmd.getType().isInternal()) { if (GeneralUtils.canRunInternalCommand(cmd.getType(), event.getAuthor())) { dispatchCommand(cmd, args, event, guild); return; } else { GeneralUtils.sendImage("https://flarebot.stream/img/trap.jpg", "trap.jpg", event.getAuthor()); Constants.logEG("It's a trap", cmd, guild.getGuild(), event.getAuthor()); return; } } if (guild.hasBetaAccess()) { if ((guild.getSettings().getChannelBlacklist().contains(event.getChannel().getIdLong()) || guild.getSettings().getUserBlacklist().contains(event.getAuthor().getIdLong())) && !guild.getPermissions().hasPermission(event.getMember(), stream.flarebot.flarebot.permissions.Permission.BLACKLIST_BYPASS)) return; } if (guild.isBlocked() && System.currentTimeMillis() > guild.getUnBlockTime() && guild.getUnBlockTime() != -1) guild.revokeBlock(); handleSpamDetection(event, guild); if (guild.isBlocked() && !(cmd.getType() == CommandType.SECRET)) return; if (handleMissingPermission(cmd, event)) return; if (!guild.hasBetaAccess() && cmd.isBetaTesterCommand()) { if (flareBot.isTestBot()) LOGGER.error("Guild " + event.getGuild().getId() + " tried to use the beta command '" + cmd.getCommand() + "'!"); return; } if (FlareBot.UPDATING.get()) { event.getChannel().sendMessage("**Currently updating!**").queue(); return; } if (flareBot.getManager().isCommandDisabled(cmd.getCommand())) { MessageUtils.sendErrorMessage(flareBot.getManager().getDisabledCommandReason(cmd.getCommand()), event.getChannel(), event.getAuthor()); return; } // Internal stuff if (event.getGuild().getIdLong() == Constants.OFFICIAL_GUILD && !handleOfficialGuildStuff(event, cmd)) return; if (event.getGuild().getIdLong() != Constants.OFFICIAL_GUILD && cmd.getType() == CommandType.MUSIC) { MessageUtils.sendInfoMessage("FlareBot is closing down, as part of this we have disabled music commands, please read the announcement [here](https://docs.flarebot.stream). Please use the remaining available commands to move any data you wish over to other bots.\nBots we recommend:\nFredBoat - Music\nDyno - Moderation\nMee6 - Random stuff", event.getChannel()); return; } dispatchCommand(cmd, args, event, guild); } private boolean handleOfficialGuildStuff(GuildMessageReceivedEvent event, Command command) { Guild guild = event.getGuild(); GuildWrapper wrapper = FlareBotManager.instance().getGuild(guild.getId()); if (event.getChannel().getIdLong() == 226785954537406464L && !event.getMember().hasPermission(Permission.MESSAGE_MANAGE)) { event.getChannel().sendMessage("Heyo " + event.getAuthor().getAsMention() + " please use me in <#226786507065786380>!").queue(); return false; } return true; } /** * This handles if the user has permission to run a command. This should return <b>true</b> if the user does NOT * have permission to run the command. * * @param cmd The command to be ran. * @param e The event this came from. * @return If the user has permission to run the command, this will return <b>true</b> if they do NOT have permission. */ private boolean handleMissingPermission(Command cmd, GuildMessageReceivedEvent e) { if (cmd.getPermission() != null) { if (!cmd.getPermissions(e.getChannel()).hasPermission(e.getMember(), cmd.getPermission())) { MessageUtils.sendAutoDeletedMessage(MessageUtils.getEmbed(e.getAuthor()).setColor(Color.red) .setDescription("You are missing the permission ``" + cmd .getPermission() + "`` which is required for use of this command!").build(), 5000, e.getChannel()); delete(e.getMessage()); return true; } } return !cmd.getPermissions(e.getChannel()).hasPermission( e.getMember(), stream.flarebot.flarebot.permissions.Permission.getPermission(cmd.getType()) ) && cmd.getPermission() == null && cmd.getType() != CommandType.SECRET; } private void delete(Message message) { if (message.getTextChannel().getGuild().getSelfMember() .getPermissions(message.getTextChannel()).contains(Permission.MESSAGE_MANAGE)) message.delete().queue(); } private String getGuildId(GenericGuildMessageEvent e) { return e.getChannel().getGuild() != null ? e.getChannel().getGuild().getId() : null; } private void handleSpamDetection(GuildMessageReceivedEvent event, GuildWrapper guild) { if (spamMap.containsKey(event.getGuild().getId())) { int messages = spamMap.get(event.getGuild().getId()); double allowed = Math.floor(Math.sqrt(GuildUtils.getGuildUserCount(event.getGuild()) / 2.5)); allowed = allowed == 0 ? 1 : allowed; if (messages > allowed) { if (!guild.isBlocked()) { MessageUtils.sendErrorMessage("We detected command spam in this guild. No commands will be able to " + "be run in this guild for a little bit.", event.getChannel()); guild.addBlocked("Command spam", System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5)); Metrics.blocksGivenOut.labels(guild.getGuildId()).inc(); } } else { spamMap.put(event.getGuild().getId(), messages + 1); } } else { spamMap.put(event.getGuild().getId(), 1); } } private void dispatchCommand(Command cmd, String[] args, GuildMessageReceivedEvent event, GuildWrapper guild) { COMMAND_POOL.submit(() -> { Map<String, String> mdcContext = (MDC.getCopyOfContextMap() == null ? new HashMap<>() : MDC.getCopyOfContextMap()); mdcContext.put("command", cmd.getCommand()); mdcContext.put("args", Arrays.toString(args).replace("\n", "\\n")); mdcContext.put("guild", event.getGuild().getId()); mdcContext.put("user", event.getAuthor().getId()); MDC.setContextMap(mdcContext); LOGGER.info( "Dispatching command '" + cmd.getCommand() + "' " + Arrays .toString(args).replace("\n", "\\n") + " in " + event.getChannel() + "! Sender: " + event.getAuthor().getName() + '#' + event.getAuthor().getDiscriminator()); // We're sending a lot of commands... Let's change the way this works soon :D /*ApiRequester.requestAsync(ApiRoute.DISPATCH_COMMAND, new JSONObject().put("command", cmd.getCommand()) .put("guildId", guild.getGuildId()));*/ commandCounter.incrementAndGet(); try { Histogram.Timer executionTimer = Metrics.commandExecutionTime.labels(cmd.getClass().getSimpleName()).startTimer(); cmd.onCommand(event.getAuthor(), guild, event.getChannel(), event.getMessage(), args, event .getMember()); executionTimer.observeDuration(); Metrics.commandsExecuted.labels(cmd.getClass().getSimpleName()).inc(); MessageEmbed.Field field = null; if (args.length > 0) { String s = MessageUtils.getMessage(args, 0).replaceAll("`", "'"); if (s.length() > 1000) s = s.substring(0, 1000) + "..."; field = new MessageEmbed.Field("Args", "`" + s + "`", false); } ModlogHandler.getInstance().postToModlog(guild, ModlogEvent.FLAREBOT_COMMAND, event.getAuthor(), new MessageEmbed.Field("Channel", event.getChannel().getName() + " (" + event.getChannel().getIdLong() + ")", true), new MessageEmbed.Field("Command", cmd.getCommand(), true), field); } catch (Exception ex) { Metrics.commandExceptions.labels(ex.getClass().getSimpleName()).inc(); MessageUtils.sendException("**There was an internal error trying to execute your command**", ex, event .getChannel()); LOGGER.error("Exception in guild " + event.getGuild().getId() + "!\n" + '\'' + cmd.getCommand() + "' " + Arrays.toString(args) + " in " + event.getChannel() + "! Sender: " + event.getAuthor().getName() + '#' + event.getAuthor().getDiscriminator(), ex); } if ((guild.hasBetaAccess() && cmd.deleteMessage() && guild.getSettings().shouldDeleteCommands()) || cmd.deleteMessage()) { delete(event.getMessage()); removedByMe.add(event.getMessageIdLong()); } }); } public int getCommandCount() { return commandCounter.get(); } @Override public void onGenericEvent(Event e) { shardEventTime.put(e.getJDA().getShardInfo() == null ? 0 : e.getJDA().getShardInfo().getShardId(), System.currentTimeMillis()); } public Map<Integer, Long> getShardEventTime() { return this.shardEventTime; } public Map<String, Integer> getSpamMap() { return spamMap; } public List<Long> getRemovedByMeList() { return removedByMe; } public Map<Long, Double> getMaxButtonClicksPerSec() { return maxButtonClicksPerSec; } public Map<Long, List<Double>> getButtonClicksPerSec() { return buttonClicksPerSec; } }