diff --git a/.gitignore b/.gitignore index d989a4e..3f94ff6 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,4 @@ fabric.properties # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* fundiscordbot.iml +./.idea/* diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..a33744a --- /dev/null +++ b/build.gradle @@ -0,0 +1,98 @@ +import org.apache.tools.ant.filters.ReplaceTokens + +plugins { + id 'java' + id 'maven-publish' + id 'com.github.johnrengelman.shadow' version '4.0.2' +} + +group = 'de.devgruppe' +version = '0.0.1' +description = 'FunDiscordBot' +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +repositories { + mavenLocal() + mavenCentral() + maven { + url = 'http://jcenter.bintray.com' + } + + maven { + url = 'http://repo.maven.apache.org/maven2' + } +} + +dependencies { + implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.13.0' + implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.13.0' + + compile 'net.dv8tion:JDA:3.4.0_317' + compile 'com.google.code.gson:gson:2.8.5' + compile 'commons-io:commons-io:2.5' + + compileOnly 'org.projectlombok:lombok:1.18.10' + annotationProcessor 'org.projectlombok:lombok:1.18.10' +} + +task sourcesForRelease(type: Copy) { + from 'src/main/java' + into 'build/filteredSrc' + filter(ReplaceTokens, tokens: [VERSION: version, DATE: getBuildDate(), TIME: getBuildTime()]) +} + +static def getBuildDate() { + return new Date().format('yyyy/MM/dd') +} + +static def getBuildTime() { + return new Date().format('HH:mm:ss') +} + +compileJava { + options.encoding = 'UTF-8' + source = sourcesForRelease.destinationDir + classpath = sourceSets.main.compileClasspath + dependsOn sourcesForRelease +} + +task sourcesJar(type: Jar, dependsOn: classes) { + classifier = 'sources' + from "${buildDir}/filteredSrc" +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +javadoc { + options.encoding = 'UTF-8' + if (JavaVersion.current().java9Compatible) { + afterEvaluate { + options.addBooleanOption("html5", true) + } + } +} + +jar { + baseName = project.name +} + +shadowJar { + classifier = 'withDependencies' +} + +build { + dependsOn clean + dependsOn jar + //dependsOn javadocJar + dependsOn sourcesJar + dependsOn shadowJar + + jar.mustRunAfter clean + javadocJar.mustRunAfter jar + //sourcesJar.mustRunAfter javadocJar + shadowJar.mustRunAfter sourcesJar +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..d2540fc --- /dev/null +++ b/gradle.properties @@ -0,0 +1,11 @@ +#Enable daemon +org.gradle.daemon=true + +# Try and findout the best heap size for your project build. +org.gradle.jvmargs=-Xmx3096m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# Modularise your project and enable parallel build +org.gradle.parallel=true + +# Enable configure on demand. +org.gradle.configureondemand=true \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..8d27651 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Oct 04 15:17:45 CEST 2019 +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..83f2acf --- /dev/null +++ b/gradlew @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..9618d8d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/pom.xml b/pom.xml deleted file mode 100644 index e438d89..0000000 --- a/pom.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - 4.0.0 - - de.devgruppe - fundiscordbot - FunDiscordBot - 0.0.1 - jar - - - This application is developed by the DevGruppe members for fun. - - - de.devgruppe.fundiscordbot.FunDiscordBotStarter - UTF-8 - UTF-8 - - - - - jcenter - jcenter-bintray - http://jcenter.bintray.com - - - - - - log4j - log4j - 1.2.17 - compile - - - org.projectlombok - lombok - 1.16.16 - provided - - - net.dv8tion - JDA - LATEST - compile - - - com.google.code.gson - gson - LATEST - - - commons-io - commons-io - 2.5 - - - - - src/main/java - - - - . - true - src/main/resources - - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.0.2 - - - - ${main.class} - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-shade-plugin - 2.4.3 - - - package - - shade - - - - - false - true - - - - org.apache.maven.plugins - maven-resources-plugin - 2.6 - - - - diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..1d7d688 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'fundiscordbot' diff --git a/src/main/java/de/devgruppe/fundiscordbot/FunDiscordBotStarter.java b/src/main/java/de/devgruppe/fundiscordbot/FunDiscordBotStarter.java index 8ef26a8..109274d 100644 --- a/src/main/java/de/devgruppe/fundiscordbot/FunDiscordBotStarter.java +++ b/src/main/java/de/devgruppe/fundiscordbot/FunDiscordBotStarter.java @@ -9,7 +9,7 @@ import de.devgruppe.fundiscordbot.command.impl.DefaultCommandRegistry; import de.devgruppe.fundiscordbot.config.Config; import de.devgruppe.fundiscordbot.config.Configuration; - +import lombok.Getter; import net.dv8tion.jda.core.AccountType; import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.JDABuilder; @@ -18,14 +18,11 @@ import net.dv8tion.jda.core.events.ReadyEvent; import net.dv8tion.jda.core.exceptions.RateLimitedException; import net.dv8tion.jda.core.hooks.EventListener; - -import org.apache.log4j.Logger; - -import java.util.Scanner; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import javax.security.auth.login.LoginException; - -import lombok.Getter; +import java.util.Scanner; public class FunDiscordBotStarter implements EventListener { @@ -54,19 +51,20 @@ private FunDiscordBotStarter() { configuration.readConfiguration(); config = configuration.getConfig(); this.commandRegistry = new DefaultCommandRegistry(); - logger.info("Connecting..."); + logger.info("Connecting to discord server..."); try { jda = new JDABuilder(AccountType.BOT) .setToken(this.config.getBotToken()) .setAutoReconnect(true) .addEventListener(this) - .setGame(Game.of("https://github.com/Dev-Gruppe/FunDiscordBot", "https://github.com/Dev-Gruppe/FunDiscordBot")) + .setGame( + Game.of("https://github.com/Dev-Gruppe/FunDiscordBot", "https://github.com/Dev-Gruppe/FunDiscordBot")) .buildAsync(); } catch (LoginException | RateLimitedException e) { e.printStackTrace(); } if (jda == null) { - logger.error("JDA is null"); + logger.error("JDA is null. Shutting down..."); System.exit(0); } this.jda.addEventListener(this.commandRegistry); @@ -74,12 +72,13 @@ private FunDiscordBotStarter() { } public static void main(String[] args) { - logger = Logger.getLogger("FunDiscordBot"); + logger = LogManager.getLogger("FunDiscordBot"); new FunDiscordBotStarter(); } private void registerCommands() { - this.commandRegistry.registerCommand(new CommandListCommand()); + final CommandListCommand commandListCommand = new CommandListCommand(); + this.commandRegistry.registerCommand(commandListCommand); this.commandRegistry.registerCommand(new EchoCommand()); this.commandRegistry.registerCommand(new RandomCommand()); this.commandRegistry.registerCommand(new CountCommand()); @@ -88,12 +87,15 @@ private void registerCommands() { this.commandRegistry.registerCommand(new RandomGiphyCommand()); this.commandRegistry.registerCommand(new TrendingGiphyCommand()); this.commandRegistry.registerCommand(new PingCommand()); + this.commandRegistry.registerCommand(new StatusCommand()); + this.commandRegistry.registerCommand(new UserInfoCommand()); + commandListCommand.initialize(); } @Override public void onEvent(Event event) { if (event instanceof ReadyEvent) { - logger.info("Connected"); + logger.info("Connected to discord server!"); new Thread(() -> { Scanner scanner = new Scanner(System.in); String line; diff --git a/src/main/java/de/devgruppe/fundiscordbot/command/commands/CommandListCommand.java b/src/main/java/de/devgruppe/fundiscordbot/command/commands/CommandListCommand.java index 610a8ea..31d5ccb 100644 --- a/src/main/java/de/devgruppe/fundiscordbot/command/commands/CommandListCommand.java +++ b/src/main/java/de/devgruppe/fundiscordbot/command/commands/CommandListCommand.java @@ -1,33 +1,159 @@ package de.devgruppe.fundiscordbot.command.commands; +import de.devgruppe.fundiscordbot.Constants; import de.devgruppe.fundiscordbot.FunDiscordBotStarter; import de.devgruppe.fundiscordbot.command.Command; -import de.devgruppe.fundiscordbot.command.CommandRegistry; import de.devgruppe.fundiscordbot.command.CommandResponse; + +import net.dv8tion.jda.core.EmbedBuilder; import net.dv8tion.jda.core.entities.Message; +import net.dv8tion.jda.core.entities.MessageEmbed; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.events.message.react.MessageReactionAddEvent; +import net.dv8tion.jda.core.hooks.ListenerAdapter; +import net.dv8tion.jda.core.requests.RestAction; + +import java.awt.*; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; /** * Created by GalaxyHD on 12.09.2017. */ public class CommandListCommand extends Command { + private LinkedList cachedMessageEmbedMap = new LinkedList<>(); + + private Map registeredHelpCommandMessages = new HashMap<>(); + private static final String ARROW_RIGHT_EMOTE = new String(new byte[]{-30, -98, -95}, StandardCharsets.UTF_8); + private static final String ARROW_LEFT_EMOTE = new String(new byte[]{-30, -84, -123}, StandardCharsets.UTF_8); + + private static final int ITEM_AMOUNT_PER_SITE = 4; public CommandListCommand() { - super("commandlist", "", "Gibt dir eine Übersicht von allen Befehlen"); + super("commandlist", "", "Gibt dir eine Übersicht von allen Befehlen aus."); + } + + public void initialize() { + FunDiscordBotStarter.getInstance().getJda().addEventListener(new CommandListReactionListener()); + int site = 0; + int iterateTo; + final List commandList = FunDiscordBotStarter.getInstance().getCommandRegistry().getRegisteredCommands(); + do { + site++; + final EmbedBuilder embedBuilder = new EmbedBuilder().setColor(Color.GRAY).setTitle("Befehlsübersicht") + .setFooter("Seite " + String.valueOf(site), null); + iterateTo = addCommandsToMessageEmbed(site, embedBuilder, commandList); + final MessageEmbed messageEmbed = embedBuilder.build(); + this.cachedMessageEmbedMap.add(messageEmbed); + } while (iterateTo < commandList.size()); + } + + private int addCommandsToMessageEmbed(int site, EmbedBuilder embedBuilder, List commandList) { + final int offset = (site - 1) * ITEM_AMOUNT_PER_SITE; + final int iterateTo = offset + ITEM_AMOUNT_PER_SITE; + if (offset == iterateTo) { + throw new IllegalStateException("Can not display site " + site + " because it would not contain any item!"); + } + for (int i = offset; i < iterateTo && i != commandList.size(); i++) { + final Command command = commandList.get(i); + embedBuilder.addField(FunDiscordBotStarter.getInstance().getCommandRegistry().getPrefix() + command.getCommandName(), + command.getDescription(), false); + } + return iterateTo; } @Override public CommandResponse triggerCommand(Message message, String[] args) { - StringBuilder stringBuilder = new StringBuilder(); - CommandRegistry commandRegistry = FunDiscordBotStarter.getInstance().getCommandRegistry(); - stringBuilder.append("Befehle: \n"); - stringBuilder.append("```"); - commandRegistry.getRegisteredCommands().forEach(command -> stringBuilder.append(commandRegistry.getPrefix()) - .append(command.getCommandName()) - .append(" - ") - .append(command.getDescription()) - .append("\n")); - stringBuilder.append("```"); - message.getTextChannel().sendMessage(stringBuilder.toString()).complete(); + this.displayCommandListSite(message.getTextChannel()); return CommandResponse.ACCEPTED; } + + private void displayCommandListSite(final TextChannel textChannel) { + this.displayCommandListSite(1, textChannel, null); + } + + private void displayCommandListSite(final int site, final TextChannel textChannel, final Message editMessage) { + final MessageEmbed messageEmbed = this.cachedMessageEmbedMap.get(site - 1); + final RestAction restAction; + if (editMessage != null) { + restAction = editMessage.editMessage(messageEmbed); + } else { + restAction = textChannel.sendMessage(messageEmbed); + } + restAction.queue(message -> { + if (site > 1) { + message.addReaction(ARROW_LEFT_EMOTE).queue(ignoredVoid -> { + if (site < CommandListCommand.this.cachedMessageEmbedMap.size()) { + message.addReaction(ARROW_RIGHT_EMOTE).queue(new PutMessageMapConsumer(message, site)); + } else { + new PutMessageMapConsumer(message, site).accept(null); + } + }); + } else { + message.addReaction(ARROW_RIGHT_EMOTE).queue(new PutMessageMapConsumer(message, site)); + } + }); + } + + @AllArgsConstructor(access = AccessLevel.PRIVATE) + private class PutMessageMapConsumer implements Consumer { + private final Message message; + private final int site; + + @Override + public void accept(Void ignoredVoid) { + CommandListCommand.this.registeredHelpCommandMessages.put(this.message, this.site); + Constants.EXECUTOR_SERVICE.execute(() -> { + try { + Thread.sleep(TimeUnit.SECONDS.toMillis(60)); + PutMessageMapConsumer.this.message.clearReactions().queue(anotherIgnoredVoid -> + CommandListCommand.this.registeredHelpCommandMessages.remove(PutMessageMapConsumer.this.message)); + } catch (InterruptedException e) { + FunDiscordBotStarter.getLogger().error("There was an error while sleeping until the help messages gets removed.", e); + } + }); + } + } + + private class CommandListReactionListener extends ListenerAdapter { + @Override + public void onMessageReactionAdd(MessageReactionAddEvent event) { + final int currentSite; + generalMessageCheck: + { + for (Message message : CommandListCommand.this.registeredHelpCommandMessages.keySet()) { + if (message.getTextChannel().getId().equals(event.getTextChannel().getId()) && + message.getId().equals(event.getMessageId())) { + currentSite = CommandListCommand.this.registeredHelpCommandMessages.get(message); + break generalMessageCheck; + } + } + return; + } + if (event.getReaction().isSelf()) return; + event.getReaction().getUsers().queue(users -> { + if (!users.contains(event.getJDA().getSelfUser())) return; + String reactionName = event.getReaction().getEmote().getName(); + final int newSite; + if (reactionName.equals(ARROW_LEFT_EMOTE)) { + newSite = currentSite - 1; + } else if (reactionName.equals(ARROW_RIGHT_EMOTE)) { + newSite = currentSite + 1; + } else { + return; + } + event.getTextChannel().getMessageById(event.getMessageId()).queue(editMessage -> + editMessage.clearReactions().queue(ignoredVoid -> + CommandListCommand.this.displayCommandListSite(newSite, event.getTextChannel(), editMessage))); + }); + } + } } diff --git a/src/main/java/de/devgruppe/fundiscordbot/command/commands/PingCommand.java b/src/main/java/de/devgruppe/fundiscordbot/command/commands/PingCommand.java index 6820937..0ce7d2d 100644 --- a/src/main/java/de/devgruppe/fundiscordbot/command/commands/PingCommand.java +++ b/src/main/java/de/devgruppe/fundiscordbot/command/commands/PingCommand.java @@ -4,12 +4,14 @@ import de.devgruppe.fundiscordbot.FunDiscordBotStarter; import de.devgruppe.fundiscordbot.command.Command; import de.devgruppe.fundiscordbot.command.CommandResponse; +import de.devgruppe.fundiscordbot.cooldown.ICooldown; +import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.Message; /** * Created by GalaxyHD on 26.09.2017. */ -public class PingCommand extends Command { +public class PingCommand extends Command implements ICooldown { private static final int COUNT = 8; @@ -28,11 +30,11 @@ public PingCommand() { public CommandResponse triggerCommand(Message message, String[] args) { if (args.length == 1) { if (args[0].equalsIgnoreCase("nice")) { - Constants.EXECUTOR_SERVICE.execute(() -> message.getTextChannel().sendMessage("Ping...").queue(pingMessage -> { + message.getTextChannel().sendMessage("Ping...").queue(pingMessage -> Constants.EXECUTOR_SERVICE.execute(() -> { long lastResult; long sum = 0, min = 999, max = 0; for (int i = 0; i < COUNT; i++) { - pingMessage.editMessage(pingMessages[i % pingMessages.length]).complete(); + pingMessage.editMessage(pingMessages[i % pingMessages.length]).queue(); lastResult = FunDiscordBotStarter.getInstance().getJda().getPing(); sum += lastResult; min = Math.min(min, lastResult); @@ -44,7 +46,9 @@ public CommandResponse triggerCommand(Message message, String[] args) { } } pingMessage.editMessage( - String.format("Durchschnittlicher Ping %dms (min: %d, max: %d)", (int) Math.ceil(sum / COUNT), min, max)) + String + .format("Durchschnittlicher Ping %dms (min: %d, max: %d)", (int) Math.ceil((double) sum / COUNT), min, + max)) .complete(); })); return CommandResponse.ACCEPTED; @@ -56,4 +60,13 @@ public CommandResponse triggerCommand(Message message, String[] args) { return CommandResponse.ACCEPTED; } + @Override + public boolean bypassCooldown(Member member) { + return member.getUser().getId().equals("127528375643406336"); + } + + @Override + public int cooldownDuration() { + return 20; + } } diff --git a/src/main/java/de/devgruppe/fundiscordbot/command/commands/StatusCommand.java b/src/main/java/de/devgruppe/fundiscordbot/command/commands/StatusCommand.java new file mode 100644 index 0000000..d8ff738 --- /dev/null +++ b/src/main/java/de/devgruppe/fundiscordbot/command/commands/StatusCommand.java @@ -0,0 +1,38 @@ +package de.devgruppe.fundiscordbot.command.commands; + +import de.devgruppe.fundiscordbot.FunDiscordBotStarter; +import de.devgruppe.fundiscordbot.command.Command; +import de.devgruppe.fundiscordbot.command.CommandResponse; +import net.dv8tion.jda.core.EmbedBuilder; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.JDAInfo; +import net.dv8tion.jda.core.entities.Message; + +public class StatusCommand extends Command { + + public StatusCommand() { + super("status", "", "Bot information"); + } + + @Override + public CommandResponse triggerCommand(final Message message, final String[] args) { + JDA jda = message.getJDA(); + final FunDiscordBotStarter instance = FunDiscordBotStarter.getInstance(); + EmbedBuilder embedBuilder = new EmbedBuilder() + .setAuthor("Information", null, jda.getSelfUser().getEffectiveAvatarUrl()) + .setColor(message.getGuild().getSelfMember().getColor()); + embedBuilder.addField("JDA Version", JDAInfo.VERSION, true); + embedBuilder.addField("Java Version", System.getProperty("java.runtime.version").replace("+", "_"), true); + embedBuilder.addField("Guilds", String.valueOf(jda.getGuilds().size()), true); + embedBuilder.addField("Ping", String.valueOf(jda.getPing()), true); + embedBuilder.addField("Total Responses", String.valueOf(jda.getResponseTotal()), true); + embedBuilder + .addField("Commands", String.valueOf(instance.getCommandRegistry().getRegisteredCommands().size()), true); + embedBuilder.addField("Total Users", String.valueOf(jda.getUserCache().size()), true); + embedBuilder.addField("JDA Status", jda.getStatus().name(), true); + embedBuilder.addField("WebSocketTrace", String.valueOf(jda.getWebSocketTrace().size()), true); + embedBuilder.addField("CloudflareRays", String.valueOf(jda.getCloudflareRays().size()), true); + message.getTextChannel().sendMessage(embedBuilder.build()).queue(); + return CommandResponse.ACCEPTED; + } +} diff --git a/src/main/java/de/devgruppe/fundiscordbot/command/commands/UserInfoCommand.java b/src/main/java/de/devgruppe/fundiscordbot/command/commands/UserInfoCommand.java new file mode 100644 index 0000000..b9d0883 --- /dev/null +++ b/src/main/java/de/devgruppe/fundiscordbot/command/commands/UserInfoCommand.java @@ -0,0 +1,96 @@ +package de.devgruppe.fundiscordbot.command.commands; + +import de.devgruppe.fundiscordbot.command.Command; +import de.devgruppe.fundiscordbot.command.CommandResponse; +import net.dv8tion.jda.core.EmbedBuilder; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.Message; +import net.dv8tion.jda.core.entities.User; +import net.dv8tion.jda.core.utils.MiscUtil; + +import java.text.MessageFormat; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; + +public class UserInfoCommand extends Command { + + public UserInfoCommand() { + super("userinfo", "", "User information"); + } + + @Override + public CommandResponse triggerCommand(Message message, String[] args) { + if (args.length < 1) + return CommandResponse.SYNTAX_PRINTED; + Member member = getMember(message.getGuild(), args[0]); + if (member == null) { + message.getChannel().sendMessage("Member not found.").complete(); + return CommandResponse.ACCEPTED; + } + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(member.getColor()); + User user = member.getUser(); + String onlineStatus = member.getOnlineStatus().name(); + String game = (member.getGame() != null ? member.getGame().getName() : "No game"); + String accountCreation = MiscUtil.getDateTimeString(MiscUtil.getCreationTime(user)); + + List joins = new ArrayList<>(message.getGuild().getMembers()); + joins.sort(Comparator.comparing(Member:: getJoinDate)); + String joinPosition = String.valueOf(joins.indexOf(member) + 1); + + String joinDate = member.getJoinDate().format(DateTimeFormatter.RFC_1123_DATE_TIME); + String joinOrder = getJoinOrder(member, joins); + + embedBuilder.setThumbnail(user.getEffectiveAvatarUrl()); + + embedBuilder.setAuthor(MessageFormat.format("Userinfo for {0} ({1})", user.getName(), user.getId()), + user.getEffectiveAvatarUrl(), user.getEffectiveAvatarUrl()); + embedBuilder.addField("Status", onlineStatus, true); + embedBuilder.addField("Game", game, true); + embedBuilder.addField("IsBot", String.valueOf(user.isBot()), true); + embedBuilder.addField("Account Creation", accountCreation, true); + embedBuilder.addField("Join Position", joinPosition, true); + embedBuilder.addField("Join Date", joinDate, true); + embedBuilder.addField("Nickname", member.getEffectiveName(), true); + embedBuilder.addField("Join Order", joinOrder, true); + message.getChannel().sendMessage(embedBuilder.build()).complete(); + return CommandResponse.ACCEPTED; + } + + private String getJoinOrder(Member member, List joins) { + StringBuilder joinOrder = new StringBuilder(); + int index = joins.indexOf(member); + index -= 3; + if (index < 0) + index = 0; + if (joins.get(index).equals(member)) + joinOrder.append("**").append(joins.get(index).getUser().getName()).append("**"); + else + joinOrder.append(joins.get(index).getUser().getName()); + for (int i = index + 1; i < index + 7; i++) { + if (i >= joins.size()) + break; + Member joinMember = joins.get(i); + String name = joinMember.getUser().getName(); + if (joinMember.equals(member)) + name = "**" + name + "**"; + joinOrder.append(" > ").append(name); + } + return joinOrder.toString(); + } + + private Member getMember(Guild guild, String name) { + Optional optional = guild. + getMembers() + .stream() + .filter(member -> member.getUser().getName().toLowerCase().startsWith(name.toLowerCase()) || + (member.getNickname() != null && member.getNickname().toLowerCase().startsWith(name.toLowerCase()))) + .findFirst(); + return optional.orElse(null); + } + +} diff --git a/src/main/java/de/devgruppe/fundiscordbot/command/commands/memegen/MemeGenCommand.java b/src/main/java/de/devgruppe/fundiscordbot/command/commands/memegen/MemeGenCommand.java index bca7f35..c5ec870 100644 --- a/src/main/java/de/devgruppe/fundiscordbot/command/commands/memegen/MemeGenCommand.java +++ b/src/main/java/de/devgruppe/fundiscordbot/command/commands/memegen/MemeGenCommand.java @@ -16,6 +16,8 @@ import java.awt.*; import java.io.FileNotFoundException; import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.Arrays; public class MemeGenCommand extends Command { @@ -40,32 +42,36 @@ private CommandResponse performMemeRequest(final Message message, final String[] return CommandResponse.SYNTAX_PRINTED; } final StringBuilder urlRequest = new StringBuilder(); - urlRequest.append(args[0]).append("/"); + urlRequest.append(URLEncoder.encode(args[0], StandardCharsets.UTF_8.toString())).append("/"); if (args.length >= 2) { final String text = this.getEscapedText(String.join(" ", Arrays.copyOfRange(args, 1, args.length))) - .replaceAll(" +", " "); + .replaceAll(" +", "_"); final String[] splitText = text.split(";"); + for (int i = 0; i < splitText.length; i++) { + splitText[i] = URLEncoder.encode(splitText[i], StandardCharsets.UTF_8.toString()); + } if (splitText.length == 2) { urlRequest.append(splitText[0]).append("/").append(splitText[1]); } else if (splitText.length == 1) { - urlRequest.append(text); + urlRequest.append(splitText[0]); } else { message.getTextChannel().sendMessage("Es darf maximal ein Semikolon(``;``) in deine Nachricht enthalten sein.").queue(); return CommandResponse.ACCEPTED; } + final String url = MemeGenHelper.REQUEST_URL + MemeGenHelper.TEMPLATE_PATH + urlRequest.toString().toLowerCase(); final HttpRequest.RequestResponse response = HttpRequest.performRequest(new HttpRequest.RequestBuilder( - MemeGenHelper.REQUEST_URL + MemeGenHelper.TEMPLATE_PATH + urlRequest.toString().toLowerCase(), HttpRequest.HttpRequestMethod.GET) + url, HttpRequest.HttpRequestMethod.GET) .addHeader(MemeGenHelper.REQUEST_HEADERS[0], MemeGenHelper.REQUEST_HEADERS[1]) .addHeader(MemeGenHelper.REQUEST_HEADERS[2], MemeGenHelper.REQUEST_HEADERS[3]) .setReadTimeout(FunDiscordBotStarter.getInstance().getConfig().getMemeTimeout())); if (response.getStatus() == GiphyHelper.EXPECTED_RESPONSE_CODE) { final JsonElement jsonElement = new JsonParser().parse(response.getResultMessage()); final JsonObject jsonObject = jsonElement.getAsJsonObject().getAsJsonObject(JSON_DIRECT_KEY); - final String url = jsonObject.get(JSON_MASKED_KEY).getAsString(); - message.getTextChannel().sendMessage(new EmbedBuilder().setColor(Color.GREEN).setTitle(" ").setImage(url) + final String memeUrl = jsonObject.get(JSON_MASKED_KEY).getAsString(); + message.getTextChannel().sendMessage(new EmbedBuilder().setColor(Color.GREEN).setTitle(" ").setImage(memeUrl) .addField("Meme-Name", args[0], true) .addField("Erstellt von", message.getAuthor().getName(), true) - .addField("URL", url, true).build()).queue(); + .addField("URL", memeUrl, true).build()).queue(); return CommandResponse.ACCEPTED; } else { FunDiscordBotStarter.getLogger().warn("The memegen.link server returned an unexpected HTTP Status code (" + response.getStatus() + "): " + response.getResultMessage()); diff --git a/src/main/java/de/devgruppe/fundiscordbot/command/impl/DefaultCommandRegistry.java b/src/main/java/de/devgruppe/fundiscordbot/command/impl/DefaultCommandRegistry.java index 637e008..8c903a0 100644 --- a/src/main/java/de/devgruppe/fundiscordbot/command/impl/DefaultCommandRegistry.java +++ b/src/main/java/de/devgruppe/fundiscordbot/command/impl/DefaultCommandRegistry.java @@ -1,8 +1,13 @@ package de.devgruppe.fundiscordbot.command.impl; +import de.devgruppe.fundiscordbot.FunDiscordBotStarter; import de.devgruppe.fundiscordbot.command.Command; import de.devgruppe.fundiscordbot.command.CommandRegistry; import de.devgruppe.fundiscordbot.command.CommandResponse; +import de.devgruppe.fundiscordbot.cooldown.CooldownManager; +import de.devgruppe.fundiscordbot.cooldown.CooldownResponse; +import de.devgruppe.fundiscordbot.cooldown.ICooldown; + import net.dv8tion.jda.core.entities.ChannelType; import net.dv8tion.jda.core.entities.Message; import net.dv8tion.jda.core.events.message.MessageReceivedEvent; @@ -12,6 +17,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.TimeUnit; /** * Created by GalaxyHD on 11.09.2017. @@ -51,12 +57,27 @@ public void onMessageReceived(MessageReceivedEvent event) { message.getTextChannel().sendMessage("Der Command wurde nicht gefunden.").complete(); return; } + if (command instanceof ICooldown) { + CooldownManager cooldownManager = CooldownManager.getInstance(); + ICooldown cooldown = (ICooldown) command; + CooldownResponse cooldownResponse = cooldownManager.hasCooldown(command, event.getMember()); + if (cooldownResponse == CooldownResponse.TRUE) { + message.getTextChannel() + .sendMessage(String.format("Du hast noch ein Cooldown `(%d sec)`. Bitte warte noch etwas.", + cooldown.cooldownDuration())) + .queue(message1 -> message1.delete().completeAfter(5, TimeUnit.SECONDS)); + return; + } else if (cooldownResponse == CooldownResponse.FALSE) { + cooldownManager.addCooldown(command, message.getMember()); + } + } + FunDiscordBotStarter.getLogger().info(String.format("Command - %s#%s - %s", event.getAuthor().getName(), event.getAuthor().getId(), content)); CommandResponse commandResponse = command.triggerCommand(message, args); if (commandResponse == CommandResponse.SYNTAX_PRINTED) message.getTextChannel() - .sendMessage( - MessageFormat.format("Syntax: `{0}{1} {2}`", PREFIX, command.getCommandName(), command.getSyntax())) - .complete(); + .sendMessage( + MessageFormat.format("Syntax: `{0}{1} {2}`", PREFIX, command.getCommandName(), command.getSyntax())) + .complete(); } @Override @@ -67,9 +88,9 @@ public Command getCommandObjectByClass(Class commandClass) { @Override public Command getCommandObjectByName(String commandName) { return this.commands.stream() - .filter(command -> command.getCommandName().equalsIgnoreCase(commandName)) - .findFirst() - .orElse(null); + .filter(command -> command.getCommandName().equalsIgnoreCase(commandName)) + .findFirst() + .orElse(null); } @Override diff --git a/src/main/java/de/devgruppe/fundiscordbot/cooldown/CooldownEntry.java b/src/main/java/de/devgruppe/fundiscordbot/cooldown/CooldownEntry.java new file mode 100644 index 0000000..aa27bff --- /dev/null +++ b/src/main/java/de/devgruppe/fundiscordbot/cooldown/CooldownEntry.java @@ -0,0 +1,40 @@ +package de.devgruppe.fundiscordbot.cooldown; + +import lombok.Getter; +import net.dv8tion.jda.core.entities.Member; + +import java.util.HashMap; + +/** + * Created by GalaxyHD on 28.09.2017. + */ +public class CooldownEntry { + + private HashMap cooldowns = new HashMap<>(); + @Getter + private int length; + + public CooldownEntry(int length) { + this.length = length; + } + + public void addMember(Member member) { + if (!containsMember(member)) + cooldowns.put(member.getUser().getId(), System.currentTimeMillis()); + } + + public void removeMember(Member member) { + if (containsMember(member)) + cooldowns.remove(member.getUser().getId()); + } + + public boolean containsMember(Member member) { + return cooldowns.containsKey(member.getUser().getId()); + } + + public long getCooldownStart(Member member) { + if (!containsMember(member)) return -1; + return cooldowns.get(member.getUser().getId()); + } + +} diff --git a/src/main/java/de/devgruppe/fundiscordbot/cooldown/CooldownManager.java b/src/main/java/de/devgruppe/fundiscordbot/cooldown/CooldownManager.java new file mode 100644 index 0000000..74e0acb --- /dev/null +++ b/src/main/java/de/devgruppe/fundiscordbot/cooldown/CooldownManager.java @@ -0,0 +1,55 @@ +package de.devgruppe.fundiscordbot.cooldown; + +import de.devgruppe.fundiscordbot.FunDiscordBotStarter; +import de.devgruppe.fundiscordbot.command.Command; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import net.dv8tion.jda.core.entities.Member; + +import java.util.HashMap; + +/** + * Created by GalaxyHD on 28.09.2017. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class CooldownManager { + @Getter + private static CooldownManager instance = new CooldownManager(); + + private HashMap commandCooldowns = new HashMap<>(); + + public CooldownResponse hasCooldown(Command command, Member member) { + if (!(command instanceof ICooldown)) return CooldownResponse.FALSE; + ICooldown cooldown = (ICooldown) command; + if (cooldown.bypassCooldown(member)) return CooldownResponse.BYPASS; + if (!commandCooldowns.containsKey(command)) return CooldownResponse.FALSE; + CooldownEntry cooldownEntry = commandCooldowns.get(command); + if (!cooldownEntry.containsMember(member)) return CooldownResponse.FALSE; + long end = cooldownEntry.getLength() * 1000 + cooldownEntry.getCooldownStart(member); + boolean flag = System.currentTimeMillis() < end; + if (!flag) removeCooldown(command, member); + return flag ? CooldownResponse.TRUE : CooldownResponse.FALSE; + } + + public void addCooldown(Command command, Member member) { + if (!(command instanceof ICooldown)) return; + ICooldown cooldown = (ICooldown) command; + CooldownEntry cooldownEntry = null; + if (!commandCooldowns.containsKey(command)) { + cooldownEntry = commandCooldowns.put(command, new CooldownEntry(cooldown.cooldownDuration())); + } + if (cooldownEntry == null) cooldownEntry = commandCooldowns.get(command); + cooldownEntry.addMember(member); + FunDiscordBotStarter.getLogger().debug("Add Cooldown to " + member.getNickname()); + } + + public void removeCooldown(Command command, Member member) { + if (!(command instanceof ICooldown)) return; + if (!commandCooldowns.containsKey(command)) return; + CooldownEntry cooldownEntry = commandCooldowns.get(command); + cooldownEntry.removeMember(member); + FunDiscordBotStarter.getLogger().debug("Remove Cooldown from " + member.getNickname()); + } + +} diff --git a/src/main/java/de/devgruppe/fundiscordbot/cooldown/CooldownResponse.java b/src/main/java/de/devgruppe/fundiscordbot/cooldown/CooldownResponse.java new file mode 100644 index 0000000..948229c --- /dev/null +++ b/src/main/java/de/devgruppe/fundiscordbot/cooldown/CooldownResponse.java @@ -0,0 +1,12 @@ +package de.devgruppe.fundiscordbot.cooldown; + +/** + * Created by GalaxyHD on 29.09.2017. + */ +public enum CooldownResponse { + + TRUE, + FALSE, + BYPASS + +} diff --git a/src/main/java/de/devgruppe/fundiscordbot/cooldown/ICooldown.java b/src/main/java/de/devgruppe/fundiscordbot/cooldown/ICooldown.java new file mode 100644 index 0000000..843be9a --- /dev/null +++ b/src/main/java/de/devgruppe/fundiscordbot/cooldown/ICooldown.java @@ -0,0 +1,26 @@ +package de.devgruppe.fundiscordbot.cooldown; + +import net.dv8tion.jda.core.entities.Member; + +/** + * Created by GalaxyHD on 28.09.2017. + * This class is used to configure a cooldown for a command + */ +public interface ICooldown { + + /** + * This method is used to allow cooldown bypasses. + * + * @param member the member object from the JDA api. + * @return if the member is allow to bypass the cooldown. + */ + boolean bypassCooldown(Member member); + + /** + * This method is used to set the cooldown duration. + * + * @return the duration from the cooldown in seconds. + */ + int cooldownDuration(); + +} diff --git a/src/main/java/de/devgruppe/fundiscordbot/utils/MessageCollector.java b/src/main/java/de/devgruppe/fundiscordbot/utils/MessageCollector.java new file mode 100644 index 0000000..4c174bd --- /dev/null +++ b/src/main/java/de/devgruppe/fundiscordbot/utils/MessageCollector.java @@ -0,0 +1,17 @@ +package de.devgruppe.fundiscordbot.utils; + +import net.dv8tion.jda.core.entities.Message; + +import java.util.List; + +public interface MessageCollector { + + void onStart(); + + void onEnd(final List messages); + + void onMessageCollect(final Message message, final int position); + + boolean checkStop(final Message message, final int position); + +} diff --git a/src/main/java/de/devgruppe/fundiscordbot/utils/MessagesFetcher.java b/src/main/java/de/devgruppe/fundiscordbot/utils/MessagesFetcher.java new file mode 100644 index 0000000..85152d4 --- /dev/null +++ b/src/main/java/de/devgruppe/fundiscordbot/utils/MessagesFetcher.java @@ -0,0 +1,51 @@ +package de.devgruppe.fundiscordbot.utils; + +import de.devgruppe.fundiscordbot.Constants; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.dv8tion.jda.core.entities.Message; +import net.dv8tion.jda.core.entities.TextChannel; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class MessagesFetcher { + + public static void getMessages(final TextChannel textChannel, final MessageCollector collector) { + Constants.EXECUTOR_SERVICE.execute(() -> { + final AtomicInteger counter = new AtomicInteger(0); + collector.onStart(); + CollectResult result = getAllMessages(textChannel, collector, counter); + final List messages = result.getMessages(); + messages.sort(Comparator.comparing(Message::getCreationTime)); + collector.onEnd(messages); + }); + } + + private static CollectResult getAllMessages(final TextChannel textChannel, final MessageCollector collector, + final AtomicInteger counter) { + final List messages = new ArrayList<>(); + boolean forceBreak = false; + for (final Message message : textChannel.getIterableHistory().cache(false)) { + messages.add(message); + counter.addAndGet(1); + collector.onMessageCollect(message, counter.get()); + if (collector.checkStop(message, counter.get())) { + forceBreak = true; + break; + } + } + return new CollectResult(messages, forceBreak); + } + + + @AllArgsConstructor + @Getter + private static class CollectResult { + private final List messages; + private boolean forceBreak; + } + +} diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties index 4f9f0a1..f1b37a8 100644 --- a/src/main/resources/log4j.properties +++ b/src/main/resources/log4j.properties @@ -1,16 +1,13 @@ # Root logger option -log4j.rootLogger=INFO, stdout, file - +log4j.rootLogger=INFO, stdout, File # Redirect log messages to console log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p - %m%n - # Redirect log messages to a log file, support file rolling. -log4j.appender.file=org.apache.log4j.RollingFileAppender -log4j.appender.file.File=logs/application.log -log4j.appender.file.MaxFileSize=5MB -log4j.appender.file.MaxBackupIndex=10 -log4j.appender.file.layout=org.apache.log4j.PatternLayout -log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p - %m%n +log4j.appender.File=org.apache.log4j.rolling.RollingFileAppender +log4j.appender.File.rollingPolicy=org.apache.log4j.rolling.TimeBasedRollingPolicy +log4j.appender.File.rollingPolicy.FileNamePattern=logs/fundiscordbot-%d{yyyyMMdd-HHmm}.log +log4j.appender.File.layout=org.apache.log4j.PatternLayout +log4j.appender.File.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p - %m%n