From 06a2e5eaa987a16d2eb413be2aec3960f1b178e5 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 10 May 2021 02:45:07 +0100 Subject: [PATCH] - Changing of all listeners from ListenerAdapter to the annotation based system. - Added reload config command, (thread-safe) - Small style changes - Logging implementation included - README.md changed. --- .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/compiler.xml | 1 + .idea/dbnavigator.xml | 10 +- .idea/jarRepositories.xml | 15 ++ .idea/misc.xml | 2 +- .idea/nerdrolebot.iml | 2 - pom.xml | 136 ++++++----- src/main/java/META-INF/MANIFEST.MF | 2 +- src/main/java/me/alex/Config.java | 132 ---------- src/main/java/me/alex/discord/Blacklist.java | 40 ++- .../java/me/alex/discord/CarbonRestImpl.java | 11 +- .../java/me/alex/discord/ForceUpdate.java | 19 +- .../alex/discord/MessageCooldownHandler.java | 14 +- src/main/java/me/alex/discord/ModPX.java | 10 +- .../me/alex/discord/RetrieveLeaderboard.java | 28 ++- .../java/me/alex/discord/RoleUpdater.java | 33 ++- .../listeners/DatabaseAccessListener.java | 1 + src/main/java/me/alex/{ => meta}/Bot.java | 75 +++--- src/main/java/me/alex/meta/Config.java | 228 ++++++++++++++++++ .../InvalidConfigurationException.java | 2 +- src/main/java/me/alex/{ => meta}/Main.java | 19 +- src/main/java/me/alex/meta/TestAppender.java | 34 +++ .../java/me/alex/sql/DatabaseManager.java | 23 +- .../java/me/alex/sql/RoleUpdateQuery.java | 6 +- src/main/resources/META-INF/MANIFEST.MF | 2 +- src/main/resources/log4j.xml | 15 ++ 26 files changed, 550 insertions(+), 315 deletions(-) create mode 100644 .idea/codeStyles/codeStyleConfig.xml delete mode 100644 .idea/nerdrolebot.iml delete mode 100644 src/main/java/me/alex/Config.java rename src/main/java/me/alex/{ => meta}/Bot.java (71%) create mode 100644 src/main/java/me/alex/meta/Config.java rename src/main/java/me/alex/{ => meta}/InvalidConfigurationException.java (97%) rename src/main/java/me/alex/{ => meta}/Main.java (50%) create mode 100644 src/main/java/me/alex/meta/TestAppender.java create mode 100644 src/main/resources/log4j.xml diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 5cedcf8..ababb4c 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -6,6 +6,7 @@ + diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml index 51325a2..4075ff4 100644 --- a/.idea/dbnavigator.xml +++ b/.idea/dbnavigator.xml @@ -2,12 +2,13 @@ - + + @@ -31,6 +32,9 @@ + + + @@ -109,8 +113,6 @@ - - @@ -121,8 +123,6 @@ - - diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml index f4bfedf..9372cf5 100644 --- a/.idea/jarRepositories.xml +++ b/.idea/jarRepositories.xml @@ -11,6 +11,11 @@ - + \ No newline at end of file diff --git a/.idea/nerdrolebot.iml b/.idea/nerdrolebot.iml deleted file mode 100644 index 78b2cc5..0000000 --- a/.idea/nerdrolebot.iml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index 31f8d6a..e122e8c 100644 --- a/pom.xml +++ b/pom.xml @@ -15,8 +15,8 @@ UTF-8 - 1.8 - 1.8 + 11 + 11 @@ -33,21 +33,60 @@ fluent-hc 4.5.13 - - org.xerial - sqlite-jdbc - 3.7.2 - + com.google.code.gson gson 2.8.6 + + org.xerial + sqlite-jdbc + 3.34.0.1-SNAPSHOT + net.dv8tion JDA 4.2.0_212 + + org.apache.logging.log4j + log4j-api + 2.14.1 + + + org.slf4j + slf4j-api + + + + + org.apache.logging.log4j + log4j-core + 2.14.1 + + + org.slf4j + slf4j-api + + + + + ch.qos.logback + logback-classic + 1.1.7 + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.11.0 + + + org.slf4j + slf4j-api + + + @@ -62,95 +101,78 @@ - + org.apache.maven.plugins maven-clean-plugin 3.1.0 + org.apache.maven.plugins maven-resources-plugin 3.0.2 + org.apache.maven.plugins maven-compiler-plugin 3.8.0 + org.apache.maven.plugins maven-surefire-plugin 2.22.1 org.apache.maven.plugins - maven-shade-plugin - 3.2.4 - - - package - - shade - - - D:\Users\samue\Desktop\nerdrolebot\target - false - true - - - me.alex.Main - - - - - - - maven-jar-plugin - 3.0.2 + 3.2.0 org.apache.maven.plugins - maven-assembly-plugin - 3.3.0 - - - - me.alex.Main - - - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - maven-install-plugin 2.5.2 + org.apache.maven.plugins maven-deploy-plugin 2.8.2 + org.apache.maven.plugins maven-site-plugin 3.7.1 - maven-project-info-reports-plugin - 3.0.0 + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + + shade + + + true + + + me.alex.meta.Main + + + + + *:* + + **/Log4j2Plugins.dat + + + + + + - diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF index 5e5dac9..03eb34d 100644 --- a/src/main/java/META-INF/MANIFEST.MF +++ b/src/main/java/META-INF/MANIFEST.MF @@ -1,3 +1,3 @@ Manifest-Version: 1.0 -Main-Class: me.alex.Main +Main-Class: me.alex.meta.Main diff --git a/src/main/java/me/alex/Config.java b/src/main/java/me/alex/Config.java deleted file mode 100644 index 388b03f..0000000 --- a/src/main/java/me/alex/Config.java +++ /dev/null @@ -1,132 +0,0 @@ -package me.alex; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; - -import java.io.*; -import java.nio.file.Paths; -import java.util.List; - -/** - * This class is a thread-safe singleton class that reads the configuration JSON file or creates one if one does not exist. - * Since only one instance can be created, it will appear often in many classes. - */ -public class Config { - /** - * Returns the only instance of this singleton class. - */ - private static Config instance; - /** - * A list of User IDs that are exempt from being affected by any role changes. - * @see net.dv8tion.jda.api.entities.User - */ - public Long[] exemptionList; - /** - * A list of Role IDs that can call !update to force update the roles. - * @see net.dv8tion.jda.api.entities.Role - */ - public Long[] rolesAllowedToUpdate; - /** - * A list of Channel IDs that are ignored when receiving messages for updating the role's holders. - * @see net.dv8tion.jda.api.entities.Invite.Channel - * @see me.alex.discord.MessageCooldownHandler#onMessageReceived(MessageReceivedEvent) - */ - public Long[] ignoredChannels; - /** - * The percentage of the most active message senders that should get the role. - * @see me.alex.discord.RoleUpdater#memberLoadCallback(List) - */ - public double topPercentage; - /** - * An integer that describes how many weeks of data should be considered when changing who has the role. - */ - public int weeksOfData; - /** - * Usually how often the main loop runs in milliseconds to update the roles, but is also used to signify one time use by some classes in order for a thread to terminate immediately - * @see me.alex.discord.RoleUpdater - * @see me.alex.discord.ForceUpdate - */ - public long delay; - /** - * The ID of the role being updated - * @see net.dv8tion.jda.api.JDA#getRoleById - */ - public long roleId; - /** - * The ID of the server being updated - * @see net.dv8tion.jda.api.JDA#getGuildById - */ - public long serverId; - /** - * The cooldown of messages logged. - * @see me.alex.discord.MessageCooldownHandler - */ - public long messageCooldown; - /** - * The token of the bot. - */ - public String botToken; - - /** - * The command prefix - */ - public char prefix; - /** - * A list of blacklisted strings - */ - public String[] blacklist; - private Config() { - } - public static void loadConfig() { - try { - String workingDir = Paths.get("").toAbsolutePath().toString(); - File f = new File(workingDir + "/conf.json"); - if (f.createNewFile()) { - instance = new Config(); - BufferedWriter bufferedWriter = new BufferedWriter(new PrintWriter(f)); - // bufferedWriter.write("{\"exemptionList\":[479285497487949853, 230336110637744131],\"weeksOfData\":2,\"roleId\":706554375572684860,\"serverId\":679434326282207238}"); - instance.exemptionList = new Long[]{266279893543682049L, 230336110637744131L}; - instance.weeksOfData = 2; - instance.delay = 120000; - instance.roleId = 706554375572684860L; - instance.serverId = 679434326282207238L; - instance.botToken = "NzExOTk1MjExMzc0Mzk1NDEy.XsLHNg.IZgzg4W7RwkExCYNXa7vmc_L5us"; - instance.messageCooldown = 60000L; - instance.rolesAllowedToUpdate = new Long[] {718236096814645289L,772163720062173214L }; - instance.ignoredChannels = new Long[] {738006372725293086L}; - instance.topPercentage = 50; - instance.prefix = '!'; - instance.blacklist = new String[]{"nigga", "nigger","negro", "fag", "faggot", "fagg","udemy.com/course"}; - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - bufferedWriter.write(gson.toJson(instance)); - bufferedWriter.close(); - throw new InvalidConfigurationException("Created new configuration file, please edit before restarting the program!"); - } - BufferedReader bufferedReader = new BufferedReader(new FileReader(f)); - String line; - StringBuilder config = new StringBuilder(); - while ((line = bufferedReader.readLine()) != null) { - config.append(line); - } - bufferedReader.close(); - Gson gson = new Gson(); - instance = gson.fromJson(config.toString(), Config.class); - if (instance.topPercentage > 100 || instance.topPercentage< 0) { - throw new InvalidConfigurationException("The value top percentage in conf.json cannot be less than 0 or larger than 100!"); - } - } catch (IOException e) { - e.printStackTrace(); - System.exit(1); - } - } - - /** - * This method reads the configuration and assigns values accordingly. In the case of a configuration not existing, it uses default values and creates a configuration. - * @return Returns the instance of Config. - * @see Gson - */ - public static synchronized Config getInstance() { - return instance; - } -} \ No newline at end of file diff --git a/src/main/java/me/alex/discord/Blacklist.java b/src/main/java/me/alex/discord/Blacklist.java index 2c7e691..ea7210c 100644 --- a/src/main/java/me/alex/discord/Blacklist.java +++ b/src/main/java/me/alex/discord/Blacklist.java @@ -1,42 +1,45 @@ package me.alex.discord; -import me.alex.Config; +import me.alex.meta.Config; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent; import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.hooks.SubscribeEvent; +import org.apache.logging.log4j.LogManager; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; +import java.util.stream.Stream; -public class Blacklist extends ListenerAdapter { +public class Blacklist { private final Config config = Config.getInstance(); - @Override + + @SubscribeEvent public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent e) { delete(e.getMessage(), e.getGuild()); } - @Override + + @SubscribeEvent public void onGuildMessageUpdate(@NotNull GuildMessageUpdateEvent e) { delete(e.getMessage(), e.getGuild()); } private void delete(Message message, Guild guild) { - final String content = message.getContentRaw().replaceAll("[^A-Za-z0-9]", ""); + final String content = message.getContentRaw(); boolean shouldReturn = true; - for (String i: config.blacklist) { + for (String i: config.getBlacklist()) { if (content.contains(i)) { shouldReturn = false; break; } } if (shouldReturn) return; - if (!guild.getId().equals(String.valueOf(config.serverId))) return; + if (!guild.getId().equals(String.valueOf(config.getServerId()))) return; final User author = message.getAuthor(); - if (Arrays.asList(config.exemptionList).contains(author.getIdLong())) return; + if (Arrays.asList(config.getExemptionList()).contains(author.getIdLong())) return; message.delete() .queue(clazz -> author.openPrivateChannel() .queue(privateChannel -> privateChannel.sendMessage("We deleted your message because it " + @@ -44,6 +47,19 @@ private void delete(Message message, Guild guild) { "Please contact the moderation team " + "if you believe this was in error.") .queue()), - error -> System.err.printf("Error when moderating %s: [Message Content: %s]", author.getName(), message.getContentRaw())); + error -> LogManager.getRootLogger().error(String.format("Error when moderating %s: [Message Content: %s]", author.getName(), message.getContentRaw()))); + } + @SubscribeEvent + public void onGuildUpdateName(GuildMemberUpdateNicknameEvent e) { + if (e.getGuild().getIdLong() != config.getServerId()) return; + boolean invalid = Stream.of(config.getBlacklist()).anyMatch(it -> e.getNewNickname() != null && e.getNewNickname().contains(it)); + if (invalid) { + e.getMember().modifyNickname(e.getOldNickname() == null ? "" : e.getOldNickname()).queue(); + e.getJDA().openPrivateChannelById(e.getMember().getUser().getId()).queue(chn -> chn.sendMessage("We deleted your message because it " + + "contained a prohibited keyword. " + + "Please contact the moderation team " + + "if you believe this was in error.").queue(it -> LogManager.getRootLogger().info(String.format("Reverted %s's name!", e.getMember().getUser().getName())), + thr -> LogManager.getRootLogger().warn(String.format("Reverted %s's name, but couldn't dm them!", e.getMember().getUser().getName())))); + } } } diff --git a/src/main/java/me/alex/discord/CarbonRestImpl.java b/src/main/java/me/alex/discord/CarbonRestImpl.java index 1ec33b5..b182e24 100644 --- a/src/main/java/me/alex/discord/CarbonRestImpl.java +++ b/src/main/java/me/alex/discord/CarbonRestImpl.java @@ -1,9 +1,9 @@ package me.alex.discord; import com.google.gson.Gson; -import me.alex.Config; +import me.alex.meta.Config; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.hooks.SubscribeEvent; import org.apache.http.HttpResponse; import org.apache.http.client.fluent.Request; import org.apache.http.entity.ContentType; @@ -15,10 +15,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public class CarbonRestImpl extends ListenerAdapter { - @Override +public class CarbonRestImpl { + @SubscribeEvent public void onMessageReceived(@Nonnull MessageReceivedEvent e) { - if (!e.getMessage().getContentRaw().startsWith(Config.getInstance().prefix + "carbon")) return; + + if (!e.getMessage().getContentRaw().startsWith(Config.getInstance().getPrefix() + "carbon")) return; String message = e.getMessage().getContentRaw().substring(7); // You have a config file yet the prefix is not in it??? Gson gson = new Gson(); if (message.length() == 1) { diff --git a/src/main/java/me/alex/discord/ForceUpdate.java b/src/main/java/me/alex/discord/ForceUpdate.java index 324f2f3..f08b002 100644 --- a/src/main/java/me/alex/discord/ForceUpdate.java +++ b/src/main/java/me/alex/discord/ForceUpdate.java @@ -1,8 +1,9 @@ package me.alex.discord; -import me.alex.Bot; -import me.alex.Config; +import me.alex.meta.Bot; +import me.alex.meta.Config; import me.alex.listeners.DatabaseAccessListener; +import me.alex.meta.Main; import me.alex.sql.DatabaseManager; import me.alex.sql.MessageUpdater; import me.alex.sql.RoleUpdateQuery; @@ -11,7 +12,7 @@ import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.hooks.SubscribeEvent; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -24,7 +25,7 @@ * @see RoleUpdater * @see Config */ -public class ForceUpdate extends ListenerAdapter implements RoleUpdater.Output { +public class ForceUpdate implements RoleUpdater.Output { private final Config config = Config.getInstance(); private final DatabaseManager databaseManager; private final MessageCooldownHandler messageCooldownHandler; @@ -44,20 +45,20 @@ public class ForceUpdate extends ListenerAdapter implements RoleUpdater.Output { public ForceUpdate(Bot bot) { databaseManager = bot.getDatabaseManager(); messageCooldownHandler = bot.getMessageCooldownHandler(); - roleUpdater = new RoleUpdater(bot.getJDA(), true); + roleUpdater = new RoleUpdater(true); } /** * This method does one iteration of the cycle that the main class initiates. * @param e The MessageReceivedEvent object received when a user sends a message. - * @see me.alex.Main + * @see Main * @see Bot */ - @Override + @SubscribeEvent public void onMessageReceived(@NotNull MessageReceivedEvent e) { // I wish you would use a proper command handler and a configurable prefix. // command handler? nah im good /s. Good point might make one in the future. - final char prefix = Config.getInstance().prefix; + final char prefix = Config.getInstance().getPrefix(); if (!e.getMessage().getContentRaw().equalsIgnoreCase(prefix + "update") && !e.getMessage() .getContentRaw() .equalsIgnoreCase(prefix + "updateinfo")) return; @@ -80,7 +81,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent e) { List roles = e.getMember().getRoles(); boolean carryOn = false; for (Role role : roles) { // cleaned up this 'satanic' code at the request of Xemor. That 'satanic' code didn't actually work as well, thank you Xemor. - if (Arrays.asList(config.rolesAllowedToUpdate).contains(role.getIdLong())) { + if (Arrays.asList(config.getRolesAllowedToUpdate()).contains(role.getIdLong())) { carryOn = true; break; } diff --git a/src/main/java/me/alex/discord/MessageCooldownHandler.java b/src/main/java/me/alex/discord/MessageCooldownHandler.java index 4d1c58b..cd0f0e9 100644 --- a/src/main/java/me/alex/discord/MessageCooldownHandler.java +++ b/src/main/java/me/alex/discord/MessageCooldownHandler.java @@ -1,11 +1,11 @@ package me.alex.discord; -import me.alex.Config; +import me.alex.meta.Config; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.ChannelType; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.hooks.SubscribeEvent; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -16,7 +16,7 @@ * A class that stores messages that users have sent before updating the database in memory. Implements a cooldown between messages. * @see Config */ -public class MessageCooldownHandler extends ListenerAdapter { +public class MessageCooldownHandler { private final Config config = Config.getInstance(); /** @@ -32,13 +32,13 @@ public class MessageCooldownHandler extends ListenerAdapter { * @param e The MessageReceivedEvent object received when a user sends a message. * @see MessageReceivedEvent */ - @Override + @SubscribeEvent public void onMessageReceived(@NotNull MessageReceivedEvent e) { // For the love of god alex stop using so many if statements CONDENSE IT DOWN if(e.getAuthor().isBot() || e.getChannelType() == ChannelType.PRIVATE - || !e.getGuild().equals(e.getJDA().getGuildById(config.serverId)) - || Arrays.asList(config.ignoredChannels).contains(e.getChannel().getIdLong())) { + || !e.getGuild().equals(e.getJDA().getGuildById(config.getServerId())) + || Arrays.asList(config.getIgnoredChannels()).contains(e.getChannel().getIdLong())) { return; } long time = System.currentTimeMillis(); @@ -47,7 +47,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent e) { if (cooldowns.get(e.getAuthor()) == null || cooldowns.get(e.getAuthor()) <= System.currentTimeMillis()) { users.add(e.getAuthor()); timeStamp.add(time); - cooldowns.put(e.getAuthor(), time + config.messageCooldown); + cooldowns.put(e.getAuthor(), time + config.getMessageCooldown()); } } diff --git a/src/main/java/me/alex/discord/ModPX.java b/src/main/java/me/alex/discord/ModPX.java index 3fed177..26a7b3f 100644 --- a/src/main/java/me/alex/discord/ModPX.java +++ b/src/main/java/me/alex/discord/ModPX.java @@ -1,20 +1,20 @@ package me.alex.discord; -import me.alex.Config; +import me.alex.meta.Config; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.hooks.SubscribeEvent; import javax.annotation.Nonnull; import java.util.List; -public class ModPX extends ListenerAdapter { - @Override +public class ModPX { + @SubscribeEvent public void onMessageReceived(@Nonnull MessageReceivedEvent e) { if (e.getAuthor().isBot()) return; if (e.getMessage().isWebhookMessage()) return; String message = e.getMessage().getContentRaw(); - if (!message.startsWith(Config.getInstance().prefix + "mod")) return; + if (!message.startsWith(Config.getInstance().getPrefix() + "mod")) return; List mentionedMembers = e.getMessage().getMentionedMembers(); if (mentionedMembers.size() != 1) return; int result = (int) (mentionedMembers.get(0).getIdLong() % 3); diff --git a/src/main/java/me/alex/discord/RetrieveLeaderboard.java b/src/main/java/me/alex/discord/RetrieveLeaderboard.java index 1ef0736..e110817 100644 --- a/src/main/java/me/alex/discord/RetrieveLeaderboard.java +++ b/src/main/java/me/alex/discord/RetrieveLeaderboard.java @@ -1,7 +1,8 @@ package me.alex.discord; -import me.alex.Config; -import me.alex.InvalidConfigurationException; +import me.alex.meta.Bot; +import me.alex.meta.Config; +import me.alex.meta.InvalidConfigurationException; import me.alex.listeners.ScoreMapReadyListener; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.JDA; @@ -9,7 +10,7 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.hooks.SubscribeEvent; import net.dv8tion.jda.api.utils.MarkdownSanitizer; import org.jetbrains.annotations.NotNull; @@ -18,22 +19,21 @@ import java.util.List; import java.util.*; -public class RetrieveLeaderboard extends ListenerAdapter implements ScoreMapReadyListener { +public class RetrieveLeaderboard implements ScoreMapReadyListener { private final String thumbnail = "https://media.discordapp.net/attachments/787351993735708758/790033548525830144/nerdbot2.png?width=586&height=586"; private final EmbedBuilder template = new EmbedBuilder().setColor(Color.GREEN).setTitle("Leaderboard").setAuthor("Nerd Bot", thumbnail); private HashMap scoreMap = null; private final Config config = Config.getInstance(); - private final JDA jda; + private final JDA jda = Bot.getJDA(); private List members = new ArrayList<>(); - public RetrieveLeaderboard(JDA jda) { - this.jda = jda; + public RetrieveLeaderboard() { } @Override synchronized public void onFullScoreMapReadyEvent(HashMap fullScoreMap) { // so we don't change the fullscore while it is being read. scoreMap = fullScoreMap; - final Guild guild = jda.getGuildById(config.serverId); + final Guild guild = jda.getGuildById(config.getServerId()); if (guild == null) { try { throw new InvalidConfigurationException("Server cannot be null!"); @@ -55,9 +55,8 @@ synchronized public void onFullScoreMapReadyEvent(HashMap fullScoreM private MessageEmbed createErrorEmbed() { return new EmbedBuilder().setColor(Color.RED).setAuthor("Nerd Bot", thumbnail).setTimestamp(Instant.now()).setTitle("Uh-oh!").addField("Error:", "Invalid page number!", false).build(); } - private MessageEmbed createPage(int page) { - + int firstIndex = (page - 1) * 10; int lastIndex = firstIndex + 10; if (firstIndex >= members.size() || firstIndex < 0) return createErrorEmbed(); @@ -82,16 +81,18 @@ private MessageEmbed createEmbed(final List members) { return new EmbedBuilder(template).addField("Results", contents.toString(), false).build(); } - @Override + @SubscribeEvent public void onMessageReceived(@NotNull MessageReceivedEvent e) { - final char prefix = Config.getInstance().prefix; + + final char prefix = Config.getInstance().getPrefix(); if (!e.getMessage().getContentRaw().startsWith(prefix + "lead") && !e.getMessage().getContentRaw().startsWith(prefix + "leaderboard")) return; //ensures it is the right command String[] splitMessage = e.getMessage().getContentRaw().split(" "); //splits into arguments if (scoreMap == null) { e.getChannel().sendMessage("We have no data yet! Try running !update.").queue(); return; } - Guild guild = e.getJDA().getGuildById(config.serverId); + Guild guild = e.getJDA().getGuildById(config.getServerId()); + if (guild == null) { try { throw new InvalidConfigurationException("Server cannot be null!"); @@ -115,5 +116,6 @@ public void onMessageReceived(@NotNull MessageReceivedEvent e) { e.getChannel().sendMessage(createErrorEmbed()).queue(); } } + } } diff --git a/src/main/java/me/alex/discord/RoleUpdater.java b/src/main/java/me/alex/discord/RoleUpdater.java index c7a4a40..aed8310 100644 --- a/src/main/java/me/alex/discord/RoleUpdater.java +++ b/src/main/java/me/alex/discord/RoleUpdater.java @@ -1,6 +1,7 @@ package me.alex.discord; -import me.alex.Config; +import me.alex.meta.Bot; +import me.alex.meta.Config; import me.alex.listeners.ScoreMapReadyListener; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.JDA; @@ -20,22 +21,20 @@ */ public class RoleUpdater implements ScoreMapReadyListener { - private final JDA jda; + private final JDA jda = Bot.getJDA(); private final Config config = Config.getInstance(); private HashMap scoreMap; private final ArrayList listeners = new ArrayList<>(); private final boolean command; /** - * @param jda The JDA instance being used for this bot. * @param command Checks whether the update is called by a discord user. * @see JDA * @see Config * @see net.dv8tion.jda.api.entities.User */ - public RoleUpdater(JDA jda, boolean command) { + public RoleUpdater( boolean command) { this.command = command; - this.jda = jda; } /** @@ -57,11 +56,11 @@ public void removeListener(RoleUpdater.Output output) { @Override public void onScoreMapReadyEvent(HashMap scoreMap) { if (scoreMap == null || scoreMap.size() == 0) return; - scoreMap.keySet().removeAll(Arrays.asList(config.exemptionList)); + Arrays.asList(config.getExemptionList()).forEach(scoreMap.keySet()::remove); this.scoreMap = scoreMap; - Guild guild = jda.getGuildById(config.serverId); + Guild guild = jda.getGuildById(config.getServerId()); if (guild == null) { - System.err.printf("Unknown server for id \"%s\"!\n", config.serverId); + System.err.printf("Unknown server for id \"%s\"!\n", config.getServerId()); return; } guild.loadMembers().onSuccess(this::memberLoadCallback); @@ -79,14 +78,14 @@ public void onScoreMapReadyEvent(HashMap scoreMap) { * @see Role */ public void memberLoadCallback(List members) { - Guild guild = this.jda.getGuildById(this.config.serverId); + Guild guild = this.jda.getGuildById(this.config.getServerId()); if (guild == null) { - System.err.printf("Unknown server for id \"%s\"!\n", this.config.serverId); + System.err.printf("Unknown server for id \"%s\"!\n", this.config.getServerId()); return; } - Role role = guild.getRoleById(this.config.roleId); + Role role = guild.getRoleById(this.config.getRoleId()); if (role == null) { - System.err.printf("Unknown role for id \"%s\"!\n", this.config.roleId); + System.err.printf("Unknown role for id \"%s\"!\n", this.config.getRoleId()); return; } List originalMembers = new ArrayList<>(members); @@ -95,7 +94,7 @@ public void memberLoadCallback(List members) { members.sort(Comparator.comparingLong((member) -> scoreMap.get(member.getIdLong()))); Collections.reverse(members); long messageMembersCount = members.size(); - long topMembers = (long) Math.ceil(messageMembersCount * (config.topPercentage /100)); + long topMembers = (long) Math.ceil(messageMembersCount * (config.getTopPercentage() /100)); if (members.size() != 1) { members = members.subList(0, (int) topMembers + 1); } @@ -159,9 +158,9 @@ public MessageEmbed getOutput() { embedBuilder.setThumbnail("https://media.discordapp.net/attachments/772164567425220640/789866299618099230/NerdBot.png?width=669&height=669"); embedBuilder.setColor(new Color(52, 153, 49)); embedBuilder.setTitle("Update Output:"); - Role role = jda.getRoleById(config.roleId); + Role role = jda.getRoleById(config.getRoleId()); if (role == null) { - return new EmbedBuilder().addField("Error:", "NullPointerException: Could not find role with ID " + config.roleId, true).build(); + return new EmbedBuilder().addField("Error:", "NullPointerException: Could not find role with ID " + config.getRoleId(), true).build(); } embedBuilder.addField("Changes:", "Users given role " + role.getName() + ": " + rolesAdded.size() + "\nUsers that had role " + role.getName() + " removed: " + rolesRemoved.size(), true); @@ -173,9 +172,9 @@ public MessageEmbed getOutput() { * @see RolesChanged#getOutput() */ public EmbedBuilder getOutputDetailed() { - Role role = jda.getRoleById(config.roleId); + Role role = jda.getRoleById(config.getRoleId()); if (role == null) { - return new EmbedBuilder().addField("Error:", "NullPointerException: Could not find role with ID " + config.roleId, true); + return new EmbedBuilder().addField("Error:", "NullPointerException: Could not find role with ID " + config.getRoleId(), true); } EmbedBuilder embedBuilder = new EmbedBuilder(); diff --git a/src/main/java/me/alex/listeners/DatabaseAccessListener.java b/src/main/java/me/alex/listeners/DatabaseAccessListener.java index b096d31..1108cbc 100644 --- a/src/main/java/me/alex/listeners/DatabaseAccessListener.java +++ b/src/main/java/me/alex/listeners/DatabaseAccessListener.java @@ -7,6 +7,7 @@ * @see DatabaseManager */ public interface DatabaseAccessListener { + void onDatabaseAccessEvent(); void onDatabaseStopAccessEvent(); } diff --git a/src/main/java/me/alex/Bot.java b/src/main/java/me/alex/meta/Bot.java similarity index 71% rename from src/main/java/me/alex/Bot.java rename to src/main/java/me/alex/meta/Bot.java index 6dbf6ea..6fc94bc 100644 --- a/src/main/java/me/alex/Bot.java +++ b/src/main/java/me/alex/meta/Bot.java @@ -1,4 +1,4 @@ -package me.alex; +package me.alex.meta; import me.alex.discord.*; import me.alex.sql.DatabaseManager; @@ -6,10 +6,15 @@ import me.alex.sql.RoleUpdateQuery; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.hooks.AnnotatedEventManager; +import net.dv8tion.jda.api.hooks.SubscribeEvent; import net.dv8tion.jda.api.requests.GatewayIntent; import javax.security.auth.login.LoginException; import java.io.IOException; +import java.lang.reflect.Method; import java.util.EnumSet; /** @@ -17,14 +22,14 @@ * It also gets the main loop started. */ public class Bot { - private final Config config = Config.getInstance(); - private JDA jda; + private Config config = Config.getInstance(); + private static JDA jda; private DatabaseManager databaseManager; private RoleUpdateQuery roleUpdateQuery; private MessageCooldownHandler messageCooldownHandler; private MessageUpdater messageUpdater; private RoleUpdater roleUpdater; - private RetrieveLeaderboard retrieveLeaderboard; + private final RetrieveLeaderboard retrieveLeaderboard; /** @@ -32,40 +37,50 @@ public class Bot { * Do not use any of the getters or setters without calling this function! */ public Bot() { - if (config == null) { - try { - throw new InvalidConfigurationException("Config is null! Check that it is formatted correctly."); - } catch (IOException e) { - e.printStackTrace(); - System.exit(1); - } - // No error printing? There you go angus. - } EnumSet gatewayIntents = EnumSet.allOf(GatewayIntent.class); - JDABuilder jdaBuilder = JDABuilder.create(Config.getInstance().botToken, gatewayIntents); - try { - jda = jdaBuilder.build(); - jda.awaitReady(); - } catch (LoginException | InterruptedException e) { - e.printStackTrace(); - return; - } + JDABuilder jdaBuilder = JDABuilder.create(Config.getInstance().getBotToken(), gatewayIntents).setEventManager(new AnnotatedEventManager()); databaseManager = new DatabaseManager(); roleUpdateQuery = new RoleUpdateQuery(databaseManager); - roleUpdater = new RoleUpdater(jda, false); + roleUpdater = new RoleUpdater(false); messageCooldownHandler = new MessageCooldownHandler(); ForceUpdate forceUpdate = new ForceUpdate(this); roleUpdater.addListener(forceUpdate); - retrieveLeaderboard = new RetrieveLeaderboard(jda); + retrieveLeaderboard = new RetrieveLeaderboard(); roleUpdateQuery.addListener(roleUpdater); - jda.addEventListener(retrieveLeaderboard); + jdaBuilder.addEventListeners(retrieveLeaderboard); roleUpdateQuery.addListener(retrieveLeaderboard); messageUpdater = new MessageUpdater(roleUpdateQuery, messageCooldownHandler); - jda.addEventListener(messageCooldownHandler); - jda.addEventListener(new ModPX()); - jda.addEventListener(new Blacklist()); - jda.addEventListener(forceUpdate); - jda.addEventListener(new CarbonRestImpl()); + jdaBuilder.addEventListeners(messageCooldownHandler, new ModPX(), + new Blacklist(), + forceUpdate, + new CarbonRestImpl(), + configReloadListener()); + try { + jda = jdaBuilder.build(); + jda.awaitReady(); + } catch (LoginException | InterruptedException e) { + e.printStackTrace(); + } + + } + private Object configReloadListener() { + return new Object() { + @SubscribeEvent + public void onGuildMessage(GuildMessageReceivedEvent e) { + new Thread(() -> { + if (e.getGuild().getIdLong() != Config.getInstance().getServerId()) return; + if (e.getAuthor().isBot() || e.isWebhookMessage()) return; + if (!e.getMessage().getContentDisplay().equalsIgnoreCase(config.getPrefix() + "reloadconfig")) return; + if (e.getMember() != null) { + if (e.getMember().getRoles().stream().mapToLong(Role::getIdLong).anyMatch(it -> it == 772163720062173214L)) { // mega nerd id should b in config... + Config.loadConfig(); + config = Config.getInstance(); + e.getChannel().sendMessage("" + config.getPrefix()).queue(); + } + } + }).start(); + } + }; } /** @@ -97,7 +112,7 @@ public void setRoleUpdater(RoleUpdater roleUpdater) { * @return The JDA instance in which all discord api calls are done from. * @see JDA */ - public JDA getJDA() { + public static JDA getJDA() { return jda; } diff --git a/src/main/java/me/alex/meta/Config.java b/src/main/java/me/alex/meta/Config.java new file mode 100644 index 0000000..fe3af4f --- /dev/null +++ b/src/main/java/me/alex/meta/Config.java @@ -0,0 +1,228 @@ +package me.alex.meta; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import org.apache.logging.log4j.LogManager; +import org.jetbrains.annotations.NotNull; + +import java.io.*; +import java.nio.file.Paths; +import java.util.List; +import java.util.function.Consumer; + +/** + * This class is a thread-safe singleton class that reads the configuration JSON file or creates one if one does not exist. + * Since only one instance can be created, it will appear often in many classes. + */ +public class Config { + // TODO: 09/05/2021 Phase out keeping references of Config + + /** + * Mutex for this object. + */ + private static final Object mutex = new Object(); + /** + * Whether mutex is needed + */ + private static boolean mutexNeeded = false; + /** + * + * Returns the only instance of this singleton class. + */ + private static Config instance; + /** + * A list of User IDs that are exempt from being affected by any role changes. + * @see net.dv8tion.jda.api.entities.User + */ + private Long[] exemptionList; + /** + * A list of Role IDs that can call !update to force update the roles. + * @see net.dv8tion.jda.api.entities.Role + */ + private Long[] rolesAllowedToUpdate; + /** + * A list of Channel IDs that are ignored when receiving messages for updating the role's holders. + * @see net.dv8tion.jda.api.entities.Invite.Channel + * @see me.alex.discord.MessageCooldownHandler#onMessageReceived(MessageReceivedEvent) + */ + private Long[] ignoredChannels; + /** + * The percentage of the most active message senders that should get the role. + * @see me.alex.discord.RoleUpdater#memberLoadCallback(List) + */ + private double topPercentage; + /** + * An integer that describes how many weeks of data should be considered when changing who has the role. + */ + private int weeksOfData; + /** + * Usually how often the main loop runs in milliseconds to update the roles, but is also used to signify one time use by some classes in order for a thread to terminate immediately + * @see me.alex.discord.RoleUpdater + * @see me.alex.discord.ForceUpdate + */ + private long delay; + /** + * The ID of the role being updated + * @see net.dv8tion.jda.api.JDA#getRoleById + */ + private long roleId; + /** + * The ID of the server being updated + * @see net.dv8tion.jda.api.JDA#getGuildById + */ + private long serverId; + /** + * The cooldown of messages logged. + * @see me.alex.discord.MessageCooldownHandler + */ + private long messageCooldown; + /** + * The token of the bot. + */ + private String botToken; + + /** + * The command prefix + */ + private char prefix; + /** + * A list of blacklisted strings + */ + private String[] blacklist; + private Config() { + } + public static void loadConfig() { + synchronized (mutex) { + try { + if (mutexNeeded) { + mutex.wait(); + } + } catch (InterruptedException e) { + throw new RuntimeException("AAAAAAAAAAAAAA I HATE CHECKED EXCEPTIONS KOTLIN SHELTER ME PLSSSSSS"); + } + mutexNeeded = true; + try { + String workingDir = Paths.get("").toAbsolutePath().toString(); + File f = new File(workingDir + "/conf.json"); + if (f.createNewFile()) { + instance = new Config(); + BufferedWriter bufferedWriter = new BufferedWriter(new PrintWriter(f)); + // bufferedWriter.write("{\"exemptionList\":[479285497487949853, 230336110637744131],\"weeksOfData\":2,\"roleId\":706554375572684860,\"serverId\":679434326282207238}"); + instance.exemptionList = new Long[]{266279893543682049L, 230336110637744131L}; + instance.weeksOfData = 2; + instance.delay = 120000; + instance.roleId = 706554375572684860L; + instance.serverId = 679434326282207238L; + instance.botToken = "NzExOTk1MjExMzc0Mzk1NDEy.XsLHNg.IZgzg4W7RwkExCYNXa7vmc_L5us"; + instance.messageCooldown = 60000L; + instance.rolesAllowedToUpdate = new Long[] {718236096814645289L,772163720062173214L }; + instance.ignoredChannels = new Long[] {738006372725293086L}; + instance.topPercentage = 50; + instance.prefix = '!'; + instance.blacklist = new String[]{"nigga", "nigger","negro", "fag", "faggot", "fagg","udemy.com/course"}; + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + bufferedWriter.write(gson.toJson(instance)); + bufferedWriter.close(); + throw new InvalidConfigurationException("Created new configuration file, please edit before restarting the program!"); + } + BufferedReader bufferedReader = new BufferedReader(new FileReader(f)); + String line; + StringBuilder config = new StringBuilder(); + while ((line = bufferedReader.readLine()) != null) { + config.append(line); + } + bufferedReader.close(); + Gson gson = new Gson(); + instance = gson.fromJson(config.toString(), Config.class); + if (instance.topPercentage > 100 || instance.topPercentage< 0) { + throw new InvalidConfigurationException("The value top percentage in conf.json cannot be less than 0 or larger than 100!"); + } + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + mutex.notifyAll(); + mutexNeeded = false; + LogManager.getRootLogger().info("Loaded config file!"); + } + } + + /** + * This method reads the configuration and assigns values accordingly. In the case of a configuration not existing, it uses default values and creates a configuration. + * @return Returns the instance of Config. + * @see Gson + */ + public static Config getInstance() { + if (instance == null) { + Config.loadConfig(); + } + return threadSafeGet(instance); + } + + /** + * @return The object supplied, after waiting for the mutex. + */ + @NotNull + private static T threadSafeGet(T get) { + synchronized (mutex) { + try { + if (mutexNeeded) { + mutex.wait(); + } + return get; + } catch (InterruptedException e) { + e.printStackTrace(); + throw new NullPointerException("Thread interrupted!"); + } + } + } + + public Long[] getExemptionList() { + return threadSafeGet(Config.getInstance().exemptionList); + } + + public Long[] getRolesAllowedToUpdate() { + return threadSafeGet(Config.getInstance().rolesAllowedToUpdate); + } + + public Long[] getIgnoredChannels() { + return threadSafeGet(Config.getInstance().ignoredChannels); + } + + public double getTopPercentage() { + return threadSafeGet(Config.getInstance().topPercentage); + } + + public int getWeeksOfData() { + return threadSafeGet(Config.getInstance().weeksOfData); + } + + public long getDelay() { + return threadSafeGet(Config.getInstance().delay); + } + + public long getRoleId() { + return threadSafeGet(Config.getInstance().roleId); + } + + public long getServerId() { + return threadSafeGet(Config.getInstance().serverId); + } + + public long getMessageCooldown() { + return threadSafeGet(Config.getInstance().messageCooldown); + } + + public String getBotToken() { + return threadSafeGet(Config.getInstance().botToken); + } + + public char getPrefix() { + return threadSafeGet(Config.getInstance().prefix); + } + + public String[] getBlacklist() { + return threadSafeGet(Config.getInstance().blacklist); + } +} \ No newline at end of file diff --git a/src/main/java/me/alex/InvalidConfigurationException.java b/src/main/java/me/alex/meta/InvalidConfigurationException.java similarity index 97% rename from src/main/java/me/alex/InvalidConfigurationException.java rename to src/main/java/me/alex/meta/InvalidConfigurationException.java index acc86fd..51421ed 100644 --- a/src/main/java/me/alex/InvalidConfigurationException.java +++ b/src/main/java/me/alex/meta/InvalidConfigurationException.java @@ -1,4 +1,4 @@ -package me.alex; +package me.alex.meta; import java.io.IOException; diff --git a/src/main/java/me/alex/Main.java b/src/main/java/me/alex/meta/Main.java similarity index 50% rename from src/main/java/me/alex/Main.java rename to src/main/java/me/alex/meta/Main.java index 0800903..5904973 100644 --- a/src/main/java/me/alex/Main.java +++ b/src/main/java/me/alex/meta/Main.java @@ -1,8 +1,11 @@ -package me.alex; +package me.alex.meta; import me.alex.sql.DatabaseManager; -import net.dv8tion.jda.api.JDA; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.Logger; +import java.util.Objects; import java.util.concurrent.TimeUnit; /** @@ -16,6 +19,13 @@ public class Main { * @param args Takes in launch arguments. */ public static void main(String[] args) { + + System.setProperty("log4j2.configurationFile", Objects.requireNonNull(Main.class.getResource("/log4j.xml")).toString()); + Logger logger = ((Logger)LogManager.getRootLogger()); + logger.setLevel(Level.ALL); + logger.getAppenders().keySet().forEach(System.out::println); + org.apache.logging.log4j.Logger log = LogManager.getRootLogger(); + log.trace("pog"); try { Config.loadConfig(); Bot bot = new Bot(); @@ -24,12 +34,15 @@ public static void main(String[] args) { } catch (Exception e) { e.printStackTrace(); } + + //ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); + //service.scheduleAtFixedRate(() -> System.out.println("Test"), 0, 10000, TimeUnit.MILLISECONDS); } public static void startRunning(Bot bot) { DatabaseManager.getService().scheduleAtFixedRate(() -> bot.getMessageUpdater().run(), 0, - Config.getInstance().delay, + Config.getInstance().getDelay(), TimeUnit.MILLISECONDS); } } \ No newline at end of file diff --git a/src/main/java/me/alex/meta/TestAppender.java b/src/main/java/me/alex/meta/TestAppender.java new file mode 100644 index 0000000..bd45ac0 --- /dev/null +++ b/src/main/java/me/alex/meta/TestAppender.java @@ -0,0 +1,34 @@ +package me.alex.meta; + +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Core; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.config.plugins.Plugin; +import org.apache.logging.log4j.core.config.plugins.PluginFactory; +import org.apache.logging.log4j.core.filter.BurstFilter; +import org.apache.logging.log4j.core.layout.PatternLayout; + + +@Plugin( + name = "TestAppender", + category = Core.CATEGORY_NAME, + elementType = Appender.ELEMENT_TYPE) +public class TestAppender extends AbstractAppender { + + + protected TestAppender() { + super("TestAppender", BurstFilter.newBuilder().build(), PatternLayout.createDefaultLayout(), false, Property.EMPTY_ARRAY); + } + + @PluginFactory + public static TestAppender createAppender() { + return new TestAppender(); + } + + @Override + public void append(LogEvent event) { + System.out.println(event.toImmutable().getMessage()); + } +} \ No newline at end of file diff --git a/src/main/java/me/alex/sql/DatabaseManager.java b/src/main/java/me/alex/sql/DatabaseManager.java index 1e7c8d4..4d5699c 100644 --- a/src/main/java/me/alex/sql/DatabaseManager.java +++ b/src/main/java/me/alex/sql/DatabaseManager.java @@ -1,11 +1,12 @@ package me.alex.sql; -import me.alex.Bot; -import me.alex.Config; -import me.alex.InvalidConfigurationException; +import me.alex.meta.Bot; +import me.alex.meta.Config; +import me.alex.meta.InvalidConfigurationException; import me.alex.listeners.DatabaseAccessListener; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.*; +import org.apache.logging.log4j.LogManager; import java.io.File; import java.io.IOException; @@ -20,7 +21,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; -import static me.alex.Main.startRunning; +import static me.alex.meta.Main.startRunning; /** * This is a class that helps deal with maintaining no concurrent connections to the database. @@ -76,17 +77,17 @@ synchronized public void notifyStopAccess() { * @see Config */ public void firstTimeDatabaseSetup(Bot bot) throws IOException, ClassNotFoundException { - JDA jda = bot.getJDA(); + JDA jda = Bot.getJDA(); Config config = bot.getConfig(); Class.forName("org.sqlite.JDBC"); if (new File(workingDir + File.separator + "nerds.db").exists()){ startRunning(bot); return; } - System.err.println("Could not find existing nerds database, creating..."); + LogManager.getRootLogger().warn("Could not find existing nerds database, creating..."); initializeTables(); - Guild guild = jda.getGuildById(config.serverId); - if (guild == null) throw new InvalidConfigurationException("Invalid server id for id " + config.serverId + "!"); + Guild guild = jda.getGuildById(config.getServerId()); + if (guild == null) throw new InvalidConfigurationException("Invalid server id for id " + config.getServerId() + "!"); List channels = guild.getTextChannels(); Member botMember = guild.getMember(jda.getSelfUser()); if (botMember == null) throw new NullPointerException("Null bot!"); @@ -94,10 +95,10 @@ public void firstTimeDatabaseSetup(Bot bot) throws IOException, ClassNotFoundExc List sqlCalls = new ArrayList<>(); final long time = System.currentTimeMillis(); final long weekInMillis = (long) 6.048e+8; - final long weeksAgo = time - (weekInMillis * config.weeksOfData); + final long weeksAgo = time - (weekInMillis * config.getWeeksOfData()); final HashMap cooldownMap = new HashMap<>(); for (TextChannel channel: channels) { - if (Arrays.asList(config.ignoredChannels).contains(channel.getIdLong()) || !channel.canTalk(botMember)) { + if (Arrays.asList(config.getIgnoredChannels()).contains(channel.getIdLong()) || !channel.canTalk(botMember)) { masterCounter.getAndIncrement(); if (masterCounter.get() == channels.size()) { executeSQLCalls(sqlCalls); @@ -121,7 +122,7 @@ public void firstTimeDatabaseSetup(Bot bot) throws IOException, ClassNotFoundExc if (lastTime == null) { // im such a nink. were iterating backwards in terms of time cooldownMap.put(message.getAuthor().getIdLong(), timeMade); sqlCalls.add(String.format("INSERT INTO messages(id, time) VALUES (%s, %s)", message.getAuthor().getId(), message.getTimeCreated().toEpochSecond() * 1000)); - } else if (lastTime - timeMade >= config.messageCooldown) { + } else if (lastTime - timeMade >= config.getMessageCooldown()) { cooldownMap.put(message.getAuthor().getIdLong(), timeMade); sqlCalls.add(String.format("INSERT INTO messages(id, time) VALUES (%s, %s)", message.getAuthor().getId(), message.getTimeCreated().toEpochSecond() * 1000)); } diff --git a/src/main/java/me/alex/sql/RoleUpdateQuery.java b/src/main/java/me/alex/sql/RoleUpdateQuery.java index 2661c81..feae371 100644 --- a/src/main/java/me/alex/sql/RoleUpdateQuery.java +++ b/src/main/java/me/alex/sql/RoleUpdateQuery.java @@ -1,7 +1,7 @@ package me.alex.sql; -import me.alex.Config; +import me.alex.meta.Config; import me.alex.listeners.DatabaseAccessListener; import me.alex.listeners.ScoreMapReadyListener; @@ -115,7 +115,7 @@ private void setScoreMap() { conn = DriverManager.getConnection(url); if (conn != null) { long weekInMillis = (long) 6.048e+8; - String sql = "SELECT DISTINCT id FROM messages WHERE time >= " + System.currentTimeMillis() + " - " + (weekInMillis * config.weeksOfData); + String sql = "SELECT DISTINCT id FROM messages WHERE time >= " + System.currentTimeMillis() + " - " + (weekInMillis * config.getWeeksOfData()); Statement statement = conn.createStatement(); statement.execute(sql); ResultSet resultSet = statement.getResultSet(); @@ -125,7 +125,7 @@ private void setScoreMap() { } HashMap allScoreMap = new HashMap<>(scoreMap); for (long i : scoreMap.keySet()) { - sql = String.format("SELECT count(id) FROM messages WHERE time >= %s - %s and id = %s", System.currentTimeMillis(), (weekInMillis * config.weeksOfData), i); + sql = String.format("SELECT count(id) FROM messages WHERE time >= %s - %s and id = %s", System.currentTimeMillis(), (weekInMillis * config.getWeeksOfData()), i); statement = conn.createStatement(); statement.execute(sql); resultSet = statement.getResultSet(); diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF index 5e5dac9..03eb34d 100644 --- a/src/main/resources/META-INF/MANIFEST.MF +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -1,3 +1,3 @@ Manifest-Version: 1.0 -Main-Class: me.alex.Main +Main-Class: me.alex.meta.Main diff --git a/src/main/resources/log4j.xml b/src/main/resources/log4j.xml new file mode 100644 index 0000000..aca4d6c --- /dev/null +++ b/src/main/resources/log4j.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file