diff --git a/.gitignore b/.gitignore
index e165b2c..f1cd263 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,3 +47,6 @@ gradle-app.setting
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
+
+.idea/
+/tmp/
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 8306744..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 3e30b74..830f1fc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -30,13 +30,13 @@ dependencies {
implementation group: 'com.vdurmont', name: 'emoji-java', version: '5.1.1'
implementation group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1'
implementation 'io.vavr:vavr:0.10.4'
- implementation 'com.google.code.gson:gson:2.9.0'
+ implementation 'com.google.code.gson:gson:2.14.0'
implementation 'com.github.Alan19:Velen:3e73a4b331'
- implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.17.2'
- implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.17.2'
implementation group: 'org.xerial', name: 'sqlite-jdbc', version: '3.36.0.3'
implementation 'org.jgrapht:jgrapht-jdk1.5:0.7.3'
implementation 'com.io7m.jgrapht:jgrapht-guava:1.2.1-MODULARIZED'
+ implementation 'org.slf4j:slf4j-simple:2.0.18'
+ implementation 'org.apache.logging.log4j:log4j-to-slf4j:2.26.1'
}
distZip {
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 28861d2..afba109 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ffed3a2..b371555 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.6-bin.zip
+networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 4f906e0..65dcd68 100644
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
#
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# 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
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# 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"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# 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
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
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"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
+ 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
@@ -106,80 +140,105 @@ 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
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
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
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# 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
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
# 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\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=`expr $i + 1`
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
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;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
-# 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"
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 107acd3..93e3f59 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 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
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/resources/languages.json b/resources/languages.json
index 1fd0747..6606d66 100644
--- a/resources/languages.json
+++ b/resources/languages.json
@@ -453,7 +453,7 @@
"to": "Cosma"
},
{
- "from": "Coimperial",
+ "from": "Corimperial",
"to": "Cosma"
},
{
@@ -466,7 +466,7 @@
},
{
"from": "Imperial English",
- "to": "Coimperial"
+ "to": "Corimperial"
},
{
"from": "Starword",
diff --git a/resources/settings.json b/resources/settings.json
index 32d6a14..a8e7448 100644
--- a/resources/settings.json
+++ b/resources/settings.json
@@ -10,5 +10,9 @@
"token": "",
"storytellerRoles": []
},
+ "remoteDataSettings": {
+ "url": "http://localhost:8080",
+ "token": ""
+ },
"players": []
}
\ No newline at end of file
diff --git a/src/main/java/calculation/outputs/BigQueryOutput.java b/src/main/java/calculation/outputs/BigQueryOutput.java
index c7c8889..9967ad6 100644
--- a/src/main/java/calculation/outputs/BigQueryOutput.java
+++ b/src/main/java/calculation/outputs/BigQueryOutput.java
@@ -4,8 +4,8 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.vavr.control.Try;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.BufferedWriter;
@@ -19,7 +19,7 @@
* Output class for output a json new line delimited form for Google's Big Query. Dice end up being an array object in the Roll Object
*/
public class BigQueryOutput implements IOutput {
- private final static Logger LOGGER = LogManager.getLogger(BigQueryOutput.class);
+ private final static Logger LOGGER = LoggerFactory.getLogger(BigQueryOutput.class);
private final static Gson GSON = new GsonBuilder()
.create();
diff --git a/src/main/java/calculation/outputs/SQLOutput.java b/src/main/java/calculation/outputs/SQLOutput.java
index 53a0474..ef08626 100644
--- a/src/main/java/calculation/outputs/SQLOutput.java
+++ b/src/main/java/calculation/outputs/SQLOutput.java
@@ -5,8 +5,8 @@
import calculation.models.RollInfo;
import io.vavr.control.Try;
import org.apache.commons.lang3.tuple.Pair;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import rolling.Roller;
import javax.annotation.Nullable;
@@ -24,7 +24,7 @@
* Output that creates a SQLite Database with two Tables: rolls and dice with rolls being the parent table
*/
public class SQLOutput implements IOutput, AutoCloseable {
- private static final Logger LOGGER = LogManager.getLogger(SQLOutput.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(SQLOutput.class);
private final Connection connection;
private final String fileLocation;
diff --git a/src/main/java/configs/RemoteDataSettings.java b/src/main/java/configs/RemoteDataSettings.java
new file mode 100644
index 0000000..196d9f7
--- /dev/null
+++ b/src/main/java/configs/RemoteDataSettings.java
@@ -0,0 +1,23 @@
+package configs;
+
+public class RemoteDataSettings {
+ private final String url;
+ private final String token;
+
+ public RemoteDataSettings() {
+ this("", "");
+ }
+
+ public RemoteDataSettings(String url, String token) {
+ this.url = url;
+ this.token = token;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public String getToken() {
+ return token;
+ }
+}
diff --git a/src/main/java/configs/Settings.java b/src/main/java/configs/Settings.java
index d1705f6..ae1df3f 100644
--- a/src/main/java/configs/Settings.java
+++ b/src/main/java/configs/Settings.java
@@ -3,31 +3,55 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import roles.Player;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
public class Settings {
+ private static final Gson GSON = new GsonBuilder()
+ .setPrettyPrinting()
+ .create();
public static final Settings instance = new Settings();
- private static final Logger LOGGER = LogManager.getLogger(Settings.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(Settings.class);
private SettingsInstance settingsInstance;
private Quotes quotes;
private Settings() {
- try {
- settingsInstance = new Gson().fromJson(new BufferedReader(new FileReader("resources/settings.json")), new TypeToken() {
- }.getType());
- quotes = new Gson().fromJson(new BufferedReader(new FileReader("resources/quotes.json")), new TypeToken() {
- }.getType());
- } catch (FileNotFoundException e) {
+ String settingsFileLocation = Optional.ofNullable(System.getenv("SETTINGS_FILE"))
+ .orElse("resources/settings.json");
+ try (
+ FileReader fileReader = new FileReader(settingsFileLocation);
+ BufferedReader bufferedReader = new BufferedReader(fileReader)
+ ) {
+ settingsInstance = GSON.fromJson(
+ bufferedReader,
+ new TypeToken() {
+ }.getType()
+ );
+ } catch (IOException e) {
LOGGER.error("Unable to find settings file!");
settingsInstance = new SettingsInstance();
+ }
+ String quotesFileLocation = Optional.ofNullable(System.getenv("QUOTES_FILE"))
+ .orElse("resources/quotes.json");
+ try (
+ FileReader fileReader = new FileReader(quotesFileLocation);
+ BufferedReader bufferedReader = new BufferedReader(fileReader)
+ ) {
+ quotes = GSON.fromJson(
+ bufferedReader,
+ new TypeToken() {
+ }.getType()
+ );
+ } catch (IOException e) {
+ LOGGER.error("Unable to find quotes file!");
quotes = new Quotes();
}
}
@@ -48,6 +72,10 @@ public static Quotes getQuotes() {
return instance.quotes;
}
+ public static RemoteDataSettings getRemoteDataSettings() {
+ return getSettingsInstance().getRemoteDataSettings();
+ }
+
private static SettingsInstance getSettingsInstance() {
return instance.settingsInstance;
}
@@ -56,22 +84,28 @@ private static SettingsInstance getSettingsInstance() {
* Serializes the values of the settings and writes it to settings.json. Generally used to update doom pools.
*/
public static void serializePersonalSettings() {
- try {
- final BufferedWriter writer = new BufferedWriter(new FileWriter("resources/settings.json"));
- new GsonBuilder().setPrettyPrinting().create().toJson(Settings.getSettingsInstance(), writer);
- writer.close();
+ String settingsFileLocation = Optional.ofNullable(System.getenv("SETTINGS_FILE"))
+ .orElse("resources/settings.json");
+ try (
+ FileWriter fileWriter = new FileWriter(settingsFileLocation);
+ BufferedWriter writer = new BufferedWriter(fileWriter)
+ ) {
+ GSON.toJson(Settings.getSettingsInstance(), writer);
} catch (IOException e) {
- e.printStackTrace();
+ LOGGER.error("Unable to serialize settings file!", e);
}
}
protected static void serializeQuotes() {
- try {
- final BufferedWriter writer = new BufferedWriter(new FileWriter("resources/quotes.json"));
- new GsonBuilder().setPrettyPrinting().create().toJson(Settings.getQuotes(), writer);
- writer.close();
+ String quotesFileLocation = Optional.ofNullable(System.getenv("QUOTES_FILE"))
+ .orElse("resources/quotes.json");
+ try (
+ FileWriter fileWriter = new FileWriter(quotesFileLocation);
+ BufferedWriter writer = new BufferedWriter(fileWriter)
+ ) {
+ GSON.toJson(Settings.getQuotes(), writer);
} catch (IOException e) {
- e.printStackTrace();
+ LOGGER.error("Unable to serialize quotes file!", e);
}
}
@@ -93,12 +127,14 @@ public static void removeQuote(String quote) {
private static class SettingsInstance {
private final DoomSettings doom;
private final DiscordSettings discordSettings;
+ private final RemoteDataSettings remoteDataSettings;
private final List players;
public SettingsInstance() {
doom = new DoomSettings();
discordSettings = new DiscordSettings();
players = new ArrayList<>();
+ this.remoteDataSettings = new RemoteDataSettings();
}
public DoomSettings getDoom() {
@@ -112,5 +148,9 @@ public DiscordSettings getDiscordSettings() {
public List getPlayers() {
return players;
}
+
+ public RemoteDataSettings getRemoteDataSettings() {
+ return remoteDataSettings;
+ }
}
}
diff --git a/src/main/java/discord/TwoDee.java b/src/main/java/discord/TwoDee.java
index be1705a..e3dd248 100644
--- a/src/main/java/discord/TwoDee.java
+++ b/src/main/java/discord/TwoDee.java
@@ -1,27 +1,31 @@
package discord;
import configs.Settings;
+import doom.DoomHandler;
import language.LanguageLogic;
import listeners.DoomPoolAutocomplete;
import listeners.LanguageAutocompleteListener;
import listeners.PoolAutocompleteListener;
import logic.AwardContextMenu;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
import org.javacord.api.DiscordApiBuilder;
import org.javacord.api.entity.intent.Intent;
import org.javacord.api.util.logging.ExceptionLogger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import pw.mihou.velen.interfaces.Velen;
import pw.mihou.velen.internals.observer.VelenObserver;
import pw.mihou.velen.internals.observer.modes.ObserverMode;
+import roles.PlayerHandler;
import slashcommands.SlashCommandRegister;
import java.io.File;
public class TwoDee {
- private static final Logger LOGGER = LogManager.getLogger(TwoDee.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(TwoDee.class);
public static void main(String[] args) {
+
+ DoomHandler.setupRemoteDoom();
String token = Settings.getDiscordSettings().getToken();
LanguageLogic languageLogic = LanguageLogic.of(new File("resources/languages.json"))
@@ -31,17 +35,23 @@ public static void main(String[] args) {
);
final Velen velen = SlashCommandRegister.setupVelen(languageLogic);
- new DiscordApiBuilder().setToken(token).setAllIntentsExcept(Intent.GUILD_PRESENCES).setUserCacheEnabled(true).addListener(velen).login().thenAccept(api -> {
- System.out.println("You can invite the bot by using the following url: " + api.createBotInvite() + "&scope=bot%20applications.commands");
+ new DiscordApiBuilder()
+ .setToken(token)
+ .setAllIntentsExcept(Intent.GUILD_PRESENCES)
+ .setUserCacheEnabled(true)
+ .addListener(velen)
+ .login()
+ .thenCompose(PlayerHandler.getInstance()::uploadPlayersToRemote)
+ .thenAccept(api -> {
+ LOGGER.info("You can invite the bot by using the following url: {}&scope=bot%20applications.commands", api.createBotInvite());
velen.registerAllSlashCommands(api);
//Send startup message
Settings.getDiscordSettings().getAnnouncementChannels().forEach(id -> {
var channel = api.getTextChannelById(id);
if (channel.isPresent()) {
channel.get().sendMessage(Settings.getQuotes().getRandomStartupQuote());
- }
- else {
- LOGGER.error("Failed to find channel for ID: %d".formatted(id));
+ } else {
+ LOGGER.error("Failed to find channel for ID: {}", id);
}
});
AwardContextMenu.setupContextMenu(api);
diff --git a/src/main/java/doom/ConfigDoom.java b/src/main/java/doom/ConfigDoom.java
new file mode 100644
index 0000000..29f6d52
--- /dev/null
+++ b/src/main/java/doom/ConfigDoom.java
@@ -0,0 +1,44 @@
+package doom;
+
+import configs.Settings;
+
+import java.util.concurrent.CompletableFuture;
+
+public record ConfigDoom(
+ String name,
+ int doom
+) implements DoomPool {
+
+ @Override
+ public String getName() {
+ return this.name();
+ }
+
+ @Override
+ public CompletableFuture getDoom() {
+ return CompletableFuture.completedFuture(this.doom());
+ }
+
+ @Override
+ public CompletableFuture changeDoom(int amount) {
+ int old = this.doom();
+ int current = this.doom() + amount;
+ DoomHandler.getInstance().doomSettings.getDoomPools()
+ .put(this.name(), current);
+ return CompletableFuture.completedFuture(new DoomChange(old, current));
+ }
+
+ @Override
+ public CompletableFuture delete() {
+ Integer removed = DoomHandler.getInstance()
+ .doomSettings
+ .getDoomPools()
+ .remove(this.getName());
+ if (removed == null) {
+ return CompletableFuture.completedFuture(false);
+ } else {
+ Settings.serializePersonalSettings();
+ return CompletableFuture.completedFuture(true);
+ }
+ }
+}
diff --git a/src/main/java/doom/DoomChange.java b/src/main/java/doom/DoomChange.java
new file mode 100644
index 0000000..85a2055
--- /dev/null
+++ b/src/main/java/doom/DoomChange.java
@@ -0,0 +1,7 @@
+package doom;
+
+public record DoomChange(
+ int old,
+ int current
+) {
+}
diff --git a/src/main/java/doom/DoomHandler.java b/src/main/java/doom/DoomHandler.java
index 5fb5a7c..96d4c22 100644
--- a/src/main/java/doom/DoomHandler.java
+++ b/src/main/java/doom/DoomHandler.java
@@ -1,34 +1,106 @@
package doom;
import com.google.common.collect.Lists;
+import com.google.gson.Gson;
import configs.DoomSettings;
import configs.Settings;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
+import org.apache.commons.lang3.tuple.Pair;
import org.javacord.api.entity.message.embed.EmbedBuilder;
import org.javacord.api.entity.user.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import roles.Player;
import roles.PlayerHandler;
import roles.Storytellers;
+import util.CachedValue;
import util.DamerauLevenshtein;
import javax.annotation.Nullable;
import java.awt.*;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
import java.text.MessageFormat;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
public final class DoomHandler {
- private static final Logger LOGGER = LogManager.getLogger(DoomHandler.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(DoomHandler.class);
public static final String DOOM = "Doom!";
+ private static final Gson GSON = new Gson();
private static final DoomHandler instance = new DoomHandler();
- private final DoomSettings doomSettings;
+ public final DoomSettings doomSettings;
+
+ private final CachedValue> remoteDooms;
private DoomHandler() {
doomSettings = Settings.getDoom();
+ remoteDooms = new CachedValue<>(Duration.ofHours(4).toMillis(), this::getRemoteDoom);
+ }
+
+ public static void setupRemoteDoom() {
+ if (!getOldDoomPools().isEmpty()) {
+ instance.doomSettings
+ .getDoomPools()
+ .entrySet()
+ .removeIf(doomPool -> createDoomPool(doomPool.getKey(), doomPool.getValue()));
+ Settings.serializePersonalSettings();
+ }
+
+ instance.remoteDooms.initialize();
+ }
+
+ private static boolean createDoomPool(String name, int count) {
+ HttpClient httpClient = HttpClient.newHttpClient();
+
+ String body = GSON.toJson(new RemoteDoomRequest(name, count));
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(Settings.getRemoteDataSettings().getUrl() + "/doompool"))
+ .header("Authorization", "Bearer " + Settings.getRemoteDataSettings().getToken())
+ .POST(HttpRequest.BodyPublishers.ofString(body))
+ .build();
+
+ try {
+ HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+ LOGGER.info("Wrote Remote Doom: {}", response.body());
+ if (response.statusCode() == 200) {
+ return true;
+ } else {
+ LOGGER.error("Received {}, {}", response.statusCode(), response.body());
+ return false;
+ }
+ } catch (Exception e) {
+ LOGGER.error("Failed to create doom pool", e);
+ return false;
+ }
+
+ }
+
+ private List getRemoteDoom() {
+ try {
+ HttpClient httpClient = HttpClient.newHttpClient();
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(Settings.getRemoteDataSettings().getUrl() + "/doompool"))
+ .header("Authorization", "Bearer " + Settings.getRemoteDataSettings().getToken())
+ .GET()
+ .build();
+
+ HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+
+ return GSON.fromJson(response.body(), RemoteDoomPool.LIST_TYPE_TOKEN.getType());
+ } catch (Exception e) {
+ LOGGER.error("Failed to read Remote Doom", e);
+ return Collections.emptyList();
+ }
}
/**
@@ -40,15 +112,24 @@ private DoomHandler() {
* @return An embed that shows the change in doom points for the specified doom pool
*/
public static EmbedBuilder addDoom(String pool, int doomVal) {
- final int oldDoom = getDoom(pool);
- if (oldDoom == 0) {
- return new EmbedBuilder()
- .setTitle("Error")
- .setDescription("No Doom Pool with Name ''**" + pool + "**'' exists.");
- }
- final int newDoom = getDoomPools().compute(pool, (s, integer) -> integer != null ? integer + doomVal : doomVal);
- Settings.serializePersonalSettings();
- return generateDoomEmbed(pool, oldDoom, newDoom);
+ return getDoomPool(pool)
+ .map(doomPool -> {
+ try {
+ DoomChange doomChange = doomPool.changeDoom(doomVal).get();
+ return generateDoomEmbed(pool, doomChange.old(), doomChange.current());
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.error("Failed to update doom", e);
+ return new EmbedBuilder()
+ .setTitle("Error")
+ .setDescription("Failed to update doom: " + e.getMessage());
+ }
+ })
+ .orElseGet(() -> new EmbedBuilder()
+ .setTitle("Error")
+ .setDescription("No Doom Pool with Name ''**" + pool + "**'' exists.")
+ );
+
+
}
/**
@@ -72,8 +153,7 @@ public static int addDoom(int doomVal) {
public static int addDoomOnOpportunity(User user, int count) {
if (Storytellers.isUserStoryteller(user)) {
return getDoom();
- }
- else {
+ } else {
final String doomPool = PlayerHandler.getPlayerFromUser(user).map(Player::getDoomPool).orElse(getActivePool());
addDoom(doomPool, count);
return getDoom(doomPool);
@@ -87,7 +167,42 @@ public static int addDoomOnOpportunity(User user, int count) {
* @return The number of doom points in that pool
*/
public static int getDoom(String pool) {
- return getDoomPools().getOrDefault(pool, 0);
+ return getDoomPool(pool)
+ .flatMap(doomPool -> {
+ try {
+ return Optional.of(doomPool.getDoom().get());
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.error("Failed to call getDoom(String pool)", e);
+ return Optional.empty();
+ }
+ })
+ .orElse(0);
+ }
+
+ public static Optional getDoomPool(String pool) {
+ return getDoomPools()
+ .stream()
+ .filter(doomPool -> doomPool.getName().equalsIgnoreCase(pool))
+ .findFirst();
+ }
+
+ public static List getRemoteDoomPools() {
+ return instance.remoteDooms.get();
+ }
+
+ public static List getOldDoomPools() {
+ return instance.doomSettings.getDoomPools()
+ .entrySet()
+ .stream()
+ .map(entry -> new ConfigDoom(entry.getKey(), entry.getValue()))
+ .toList();
+ }
+
+ public static List getDoomPools() {
+ ArrayList doomPools = new ArrayList<>();
+ doomPools.addAll(getRemoteDoomPools());
+ doomPools.addAll(getOldDoomPools());
+ return doomPools;
}
/**
@@ -105,23 +220,34 @@ public static int getDoom() {
* @param newDoom The new value of the doom pool
* @return The embed with a new doom value
*/
- public static EmbedBuilder setDoom(String pool, int newDoom) {
- int oldDoom = getDoom(pool);
- if (oldDoom == 0) {
+ public static EmbedBuilder setDoom(String poolName, int newDoom) {
+ try {
+ return setDoomAsync(poolName, newDoom).get();
+ } catch (InterruptedException | ExecutionException e) {
+ LOGGER.error("Failed to set doom", e);
return new EmbedBuilder()
.setTitle("Error")
- .setDescription("No Doom Pool with Name ''**" + pool + "**'' exists.");
+ .setDescription("Failed to set doom for ''**" + poolName + "**'':" + e.getMessage());
}
- getDoomPools().put(pool, newDoom);
- Settings.serializePersonalSettings();
- return generateDoomEmbed(pool, oldDoom, newDoom);
+ }
+
+ public static CompletableFuture setDoomAsync(String poolName, int newDoom) {
+ return getDoomPool(poolName)
+ .map(pool -> pool.getDoom()
+ .thenCompose(doom -> pool.changeDoom(newDoom - doom))
+ .thenApply(doomChange -> generateDoomEmbed(pool.getName(), doomChange.old(), doomChange.current()))
+ )
+ .orElseGet(() -> CompletableFuture.completedFuture(new EmbedBuilder()
+ .setTitle("Error")
+ .setDescription("No Doom Pool with Name ''**" + poolName + "**'' exists.")
+ ));
}
/**
* Generates an embed that shows the amount of doom points in the specified doom pool.
*
* @param pool The name of the doom pool to check
- * @return The an embed containing the value of the doom pool
+ * @return The embed containing the value of the doom pool
*/
public static EmbedBuilder generateDoomEmbed(String pool) {
final int doom = getDoom(pool);
@@ -154,28 +280,43 @@ public static EmbedBuilder generateDoomEmbed(String pool, int oldDoom, int newDo
* @return An embed containing information about the deleted doom pool and the number of doom points it had
*/
public static EmbedBuilder deletePool(String pool) {
- final Integer removedDoom = getDoomPools().remove(pool);
- final String description = Optional.ofNullable(removedDoom).map(doom -> MessageFormat.format("I''ve removed the ''**{0}**'' doom pool, which contained {1} doom points.", pool, doom)).orElseGet(() -> MessageFormat.format("I was unable to find the ''**{0}**'' doom pool", pool));
- Settings.serializePersonalSettings();
+ String description = getDoomPool(pool)
+ .map(doomPool -> MessageFormat.format("I''ve removed the ''**{0}**'' doom pool, which contained {1} doom points.", pool, doomPool))
+ .orElseGet(() -> MessageFormat.format("I was unable to find the ''**{0}**'' doom pool", pool));
+
return new EmbedBuilder()
.setTitle(DOOM)
.setDescription(description);
}
/**
- * Generates an embed that provides a summary of all of the doom pools.
+ * Generates an embed that provides a summary of the doom pools.
*
* @return Am embed with information on the names and values of all available doom pools and the name and value of
* the active doom pool
*/
- public static EmbedBuilder generateDoomEmbed() {
- final EmbedBuilder embedBuilder = new EmbedBuilder().setTitle(DOOM).setDescription(MessageFormat.format("Here are the values of all doom pools.\nThe current active doom pool is ''**{0}**'' with {1} doom points", getActivePool(), getDoom(getActivePool()))).setColor(new Color((int) (getDoom() % 101 * (2.55))));
- getDoomPools().forEach((key, value) -> embedBuilder.addField(key, String.valueOf(value)));
- return embedBuilder;
- }
+ public static CompletableFuture generateDoomEmbed() {
+ final EmbedBuilder embedBuilder = new EmbedBuilder()
+ .setTitle(DOOM)
+ .setDescription(MessageFormat.format(
+ "Here are the values of all doom pools.\nThe current active doom pool is ''**{0}**'' with {1} doom points",
+ getActivePool(),
+ getDoom(getActivePool())
+ ))
+ .setColor(new Color((int) (getDoom() % 101 * (2.55))));
+ List>> futures = new ArrayList<>();
+ for (DoomPool doomPool : getDoomPools()) {
+ futures.add(doomPool.getDoom().thenApply(doom -> Pair.of(doomPool.getName(), doom)));
+ }
+ return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
+ .thenApply(v -> {
+ futures.forEach(pairFuture -> {
+ Pair pair = pairFuture.join();
+ embedBuilder.addField(pair.getLeft(), String.valueOf(pair.getRight()));
+ });
- public static Map getDoomPools() {
- return instance.doomSettings.getDoomPools();
+ return embedBuilder;
+ });
}
/**
@@ -208,49 +349,52 @@ public static String getDoomPoolOrDefault(User user) {
}
public static EmbedBuilder createPool(String poolName, int count) {
- getDoomPools().put(poolName, count);
- Settings.serializePersonalSettings();
- return new EmbedBuilder()
- .setTitle(DOOM)
- .setDescription(MessageFormat.format("I''ve created the doom pool ''**{0}**'', which contains {1} doom points.", poolName, count));
+ if (createDoomPool(poolName, count)) {
+ return new EmbedBuilder()
+ .setTitle(DOOM)
+ .setDescription(MessageFormat.format("I''ve created the doom pool ''**{0}**'', which contains {1} doom points.", poolName, count));
+ } else {
+ return new EmbedBuilder()
+ .setTitle(DOOM)
+ .setDescription(MessageFormat.format("Failed to create doom pool ''**{0}**''.", poolName));
+ }
}
@Nullable
public static String findPool(String poolName) {
- if (getDoomPools().containsKey(poolName)) {
+ if (getDoomPools().stream().anyMatch(pool -> pool.getName().equalsIgnoreCase(poolName))) {
return poolName;
- }
- else {
+ } else {
List potentialPoolNames = Lists.newArrayList();
int currentDistance = Integer.MAX_VALUE;
- for (String existingPool : getDoomPools().keySet()) {
- int distance = DamerauLevenshtein.calculateDistance(poolName, existingPool);
+ for (DoomPool existingPool : getDoomPools()) {
+ int distance = DamerauLevenshtein.calculateDistance(poolName, existingPool.getName());
if (distance < currentDistance) {
potentialPoolNames.clear();
- potentialPoolNames.add(existingPool);
+ potentialPoolNames.add(existingPool.getName());
currentDistance = distance;
- }
- else if (distance == currentDistance) {
- potentialPoolNames.add(existingPool);
+ } else if (distance == currentDistance) {
+ potentialPoolNames.add(existingPool.getName());
}
}
if (potentialPoolNames.isEmpty()) {
return null;
- }
- else if (potentialPoolNames.size() == 1) {
+ } else if (potentialPoolNames.size() == 1) {
if (currentDistance <= 2) {
return potentialPoolNames.get(0);
- }
- else {
+ } else {
return null;
}
- }
- else {
+ } else {
LOGGER.warn("Found multiple doom pool names with same level of similarity");
return null;
}
}
}
+ public static DoomHandler getInstance() {
+ return instance;
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/doom/DoomPool.java b/src/main/java/doom/DoomPool.java
new file mode 100644
index 0000000..8e28183
--- /dev/null
+++ b/src/main/java/doom/DoomPool.java
@@ -0,0 +1,13 @@
+package doom;
+
+import java.util.concurrent.CompletableFuture;
+
+public interface DoomPool {
+ String getName();
+
+ CompletableFuture getDoom();
+
+ CompletableFuture changeDoom(int amount);
+
+ CompletableFuture delete();
+}
diff --git a/src/main/java/doom/RemoteDoomPool.java b/src/main/java/doom/RemoteDoomPool.java
new file mode 100644
index 0000000..450b04f
--- /dev/null
+++ b/src/main/java/doom/RemoteDoomPool.java
@@ -0,0 +1,100 @@
+package doom;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import configs.Settings;
+
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse.BodyHandlers;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+public record RemoteDoomPool(
+ long id,
+ String name,
+ int doom
+) implements DoomPool {
+ public static final TypeToken> LIST_TYPE_TOKEN = new TypeToken<>() {
+ };
+
+ private static final Gson GSON = new Gson();
+ private static final HttpClient httpClient = HttpClient.newHttpClient();
+
+ @Override
+ public String getName() {
+ return this.name();
+ }
+
+ @Override
+ public CompletableFuture getDoom() {
+ return httpClient.sendAsync(
+ HttpRequest.newBuilder()
+ .GET()
+ .uri(URI.create(Settings.getRemoteDataSettings().getUrl() + "/doompool/" + this.id()))
+ .header("Authorization", "Bearer " + Settings.getRemoteDataSettings().getToken())
+ .build(),
+ BodyHandlers.ofString()
+ ).thenComposeAsync(httpResponse -> {
+ if (httpResponse.statusCode() == 200) {
+ try {
+ RemoteDoomPool doomPool = GSON.fromJson(httpResponse.body(), RemoteDoomPool.class);
+ return CompletableFuture.completedFuture(doomPool.doom());
+ } catch (Exception e) {
+ return CompletableFuture.failedFuture(e);
+ }
+ } else {
+ return CompletableFuture.failedFuture(
+ new Exception("Received %s for Http Response for getDoom".formatted(httpResponse.statusCode()))
+ );
+ }
+ });
+ }
+
+ @Override
+ public CompletableFuture changeDoom(int amount) {
+ return httpClient.sendAsync(
+ HttpRequest.newBuilder()
+ .POST(HttpRequest.BodyPublishers.ofString(GSON.toJson(Map.of("amount", amount))))
+ .uri(URI.create(Settings.getRemoteDataSettings().getUrl() + "/doompool/" + this.id() + "/doom"))
+ .header("Authorization", "Bearer " + Settings.getRemoteDataSettings().getToken())
+ .build(),
+ BodyHandlers.ofString()
+ ).thenComposeAsync(httpResponse -> {
+ if (httpResponse.statusCode() == 200) {
+ try {
+ DoomChange doomChange = GSON.fromJson(httpResponse.body(), DoomChange.class);
+ return CompletableFuture.completedFuture(doomChange);
+ } catch (Exception e) {
+ return CompletableFuture.failedFuture(e);
+ }
+ } else {
+ return CompletableFuture.failedFuture(
+ new Exception("Received %s for Http Response for getDoom".formatted(httpResponse.statusCode()))
+ );
+ }
+ });
+ }
+
+ @Override
+ public CompletableFuture delete() {
+ return httpClient.sendAsync(
+ HttpRequest.newBuilder()
+ .DELETE()
+ .uri(URI.create(Settings.getRemoteDataSettings().getUrl() + "/doompool/" + this.id()))
+ .header("Authorization", "Bearer " + Settings.getRemoteDataSettings().getToken())
+ .build(),
+ BodyHandlers.ofString()
+ ).thenComposeAsync(httpResponse -> {
+ if (httpResponse.statusCode() == 200) {
+ return CompletableFuture.completedFuture(true);
+ } else {
+ return CompletableFuture.failedFuture(
+ new Exception("Received %s for Http Response for getDoom".formatted(httpResponse.statusCode()))
+ );
+ }
+ });
+ }
+}
diff --git a/src/main/java/doom/RemoteDoomRequest.java b/src/main/java/doom/RemoteDoomRequest.java
new file mode 100644
index 0000000..b39d99e
--- /dev/null
+++ b/src/main/java/doom/RemoteDoomRequest.java
@@ -0,0 +1,7 @@
+package doom;
+
+public record RemoteDoomRequest(
+ String name,
+ int doom
+) {
+}
diff --git a/src/main/java/language/LanguageLogic.java b/src/main/java/language/LanguageLogic.java
index bd03fd5..296d863 100644
--- a/src/main/java/language/LanguageLogic.java
+++ b/src/main/java/language/LanguageLogic.java
@@ -8,11 +8,11 @@
import com.google.gson.*;
import io.vavr.control.Try;
import org.apache.commons.lang3.tuple.Pair;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
import org.jgrapht.Graph;
import org.jgrapht.alg.DijkstraShortestPath;
import org.jgrapht.graph.guava.MutableGraphAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import util.DamerauLevenshtein;
import util.GsonHelper;
import util.Match;
@@ -30,7 +30,7 @@
@SuppressWarnings("UnstableApiUsage")
public class LanguageLogic {
- private static final Logger LOGGER = LogManager.getLogger(LanguageLogic.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(LanguageLogic.class);
private static final Gson GSON = new GsonBuilder()
.setPrettyPrinting()
.create();
diff --git a/src/main/java/listeners/DoomPoolAutocomplete.java b/src/main/java/listeners/DoomPoolAutocomplete.java
index bfcd535..43bb0ec 100644
--- a/src/main/java/listeners/DoomPoolAutocomplete.java
+++ b/src/main/java/listeners/DoomPoolAutocomplete.java
@@ -15,9 +15,9 @@ public class DoomPoolAutocomplete implements AutocompleteCreateListener {
public void onAutocompleteCreate(AutocompleteCreateEvent event) {
if (event.getAutocompleteInteraction().getFocusedOption().getName().equals(DoomLogic.POOL_NAME)) {
final String enteredValue = event.getAutocompleteInteraction().getFocusedOption().getStringValue().orElse("");
- final List choices = DoomHandler.getDoomPools().keySet().stream()
- .filter(poolName -> UtilFunctions.containsIgnoreCase(poolName, enteredValue))
- .map(s -> SlashCommandOptionChoice.create(s, s))
+ final List choices = DoomHandler.getDoomPools().stream()
+ .filter(pool -> UtilFunctions.containsIgnoreCase(pool.getName(), enteredValue))
+ .map(s -> SlashCommandOptionChoice.create(s.getName(), s.getName()))
.collect(Collectors.toList());
event.getAutocompleteInteraction().respondWithChoices(choices);
}
diff --git a/src/main/java/listeners/RollComponentInteractionListener.java b/src/main/java/listeners/RollComponentInteractionListener.java
index 3e4b31d..8bcd688 100644
--- a/src/main/java/listeners/RollComponentInteractionListener.java
+++ b/src/main/java/listeners/RollComponentInteractionListener.java
@@ -202,8 +202,13 @@ private void handleReroll(ButtonInteraction interaction, Message interactionMess
* @return A completable future indicating that the plot points and doom points have been rolled back
*/
private CompletableFuture rollBackChanges() {
- PlayerHandler.getPlayerFromUser(user).map(Player::getDoomPool).ifPresent(s -> DoomHandler.setDoom(s, originalDoomPoints));
- return SheetsHandler.setPlotPoints(user, originalPlotPoints).thenAccept(integer -> {});
+ return CompletableFuture.allOf(
+ PlayerHandler.getPlayerFromUser(user)
+ .map(Player::getDoomPool)
+ .map(s -> DoomHandler.setDoomAsync(s, originalDoomPoints))
+ .orElseGet(() -> CompletableFuture.completedFuture(null)),
+ SheetsHandler.setPlotPoints(user, originalPlotPoints)
+ );
}
/**
diff --git a/src/main/java/logic/CalculationLogic.java b/src/main/java/logic/CalculationLogic.java
index 731519b..dd66563 100644
--- a/src/main/java/logic/CalculationLogic.java
+++ b/src/main/java/logic/CalculationLogic.java
@@ -9,8 +9,6 @@
import exceptions.UserException;
import io.vavr.Tuple;
import io.vavr.control.Try;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
import org.javacord.api.entity.channel.Channel;
import org.javacord.api.entity.channel.ChannelType;
import org.javacord.api.entity.channel.TextChannel;
@@ -20,6 +18,8 @@
import org.javacord.api.event.message.MessageCreateEvent;
import org.javacord.api.interaction.*;
import org.javacord.api.interaction.callback.InteractionImmediateResponseBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import pw.mihou.velen.interfaces.*;
import pw.mihou.velen.interfaces.routed.VelenRoutedOptions;
@@ -34,7 +34,7 @@
* Command Class for Calculation. Handles IO, as well as streaming all messages into the Collector
*/
public class CalculationLogic implements VelenEvent, VelenSlashEvent {
- private final static Logger LOGGER = LogManager.getLogger(CalculationLogic.class);
+ private final static Logger LOGGER = LoggerFactory.getLogger(CalculationLogic.class);
@SuppressWarnings("ResultOfMethodCallIgnored")
@Override
diff --git a/src/main/java/logic/DoomLogic.java b/src/main/java/logic/DoomLogic.java
index 6d41eff..ce56e05 100644
--- a/src/main/java/logic/DoomLogic.java
+++ b/src/main/java/logic/DoomLogic.java
@@ -20,6 +20,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
public class DoomLogic implements VelenHybridHandler {
@@ -73,38 +74,29 @@ private static SlashCommandOptionBuilder getCountOption() {
.setRequired(false);
}
- private EmbedBuilder handleCommand(String mode, String poolName, int count) {
+ private CompletableFuture handleCommand(String mode, String poolName, int count) {
String actualPoolName = DoomHandler.findPool(poolName);
if (actualPoolName == null) {
if (mode == null || mode.isEmpty() || mode.equalsIgnoreCase("list")) {
return DoomHandler.generateDoomEmbed();
- }
- else {
- return new EmbedBuilder()
+ } else {
+ return CompletableFuture.completedFuture(new EmbedBuilder()
.setTitle("Error")
- .setDescription("No Doom Pool with Name ''**" + poolName + "**'' exists.");
- }
- }
- else {
- switch (mode) {
- case "add":
- return DoomHandler.addDoom(actualPoolName, count);
- case "sub":
- return DoomHandler.addDoom(actualPoolName, count * -1);
- case "select":
- return DoomHandler.setActivePool(actualPoolName);
- case "set":
- return DoomHandler.setDoom(actualPoolName, count);
- case "delete":
- return DoomHandler.deletePool(actualPoolName);
- case "create":
- return DoomHandler.createPool(actualPoolName, count);
- case "list":
- return DoomHandler.generateDoomEmbed();
- case "query":
- default:
- return actualPoolName.equals("") ? DoomHandler.generateDoomEmbed() : DoomHandler.generateDoomEmbed(actualPoolName);
+ .setDescription("No Doom Pool with Name ''**" + poolName + "**'' exists.")
+ );
}
+ } else {
+ return switch (mode) {
+ case "add" -> CompletableFuture.completedFuture(DoomHandler.addDoom(actualPoolName, count));
+ case "sub" -> CompletableFuture.completedFuture(DoomHandler.addDoom(actualPoolName, count * -1));
+ case "select" -> CompletableFuture.completedFuture(DoomHandler.setActivePool(actualPoolName));
+ case "set" -> CompletableFuture.completedFuture(DoomHandler.setDoom(actualPoolName, count));
+ case "delete" -> CompletableFuture.completedFuture(DoomHandler.deletePool(actualPoolName));
+ case "create" -> CompletableFuture.completedFuture(DoomHandler.createPool(actualPoolName, count));
+ case "list" -> DoomHandler.generateDoomEmbed();
+ default ->
+ actualPoolName.isEmpty() ? DoomHandler.generateDoomEmbed() : CompletableFuture.completedFuture(DoomHandler.generateDoomEmbed(actualPoolName));
+ };
}
}
@@ -120,7 +112,8 @@ public void onEvent(VelenGeneralEvent event, VelenGeneralResponder responder, Us
final String name = subcommand.flatMap(velenSubcommand -> velenSubcommand.withName(POOL_NAME))
.flatMap(VelenOption::asString)
.orElse(DoomHandler.getActivePool());
- responder.addEmbed(handleCommand(subcommandName, name, count)).respond();
+ handleCommand(subcommandName, name, count)
+ .thenCompose(embed -> responder.addEmbed(embed).respond());
}
}
}
diff --git a/src/main/java/roles/PlayerHandler.java b/src/main/java/roles/PlayerHandler.java
index 779b6a0..2e12f37 100644
--- a/src/main/java/roles/PlayerHandler.java
+++ b/src/main/java/roles/PlayerHandler.java
@@ -1,18 +1,31 @@
package roles;
+import com.google.gson.Gson;
import configs.Settings;
+import doom.DoomHandler;
+import doom.RemoteDoomPool;
import org.apache.commons.lang3.tuple.Pair;
+import org.javacord.api.DiscordApi;
import org.javacord.api.entity.Mentionable;
import org.javacord.api.entity.permission.Role;
import org.javacord.api.entity.user.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import sheets.SheetsHandler;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
import java.util.stream.Collectors;
public class PlayerHandler {
+ private static final Logger LOGGER = LoggerFactory.getLogger(PlayerHandler.class);
+ private static final HttpClient HTTP_CLIENT = HttpClient.newHttpClient();
+ private static final Gson GSON = new Gson();
private static final PlayerHandler instance = new PlayerHandler();
private final List players;
@@ -40,14 +53,12 @@ public static Collection> getPlayersFromMentionable(Mentionab
)
.flatMap(Optional::stream)
.collect(Collectors.toSet());
- }
- else if (mentionable instanceof User) {
+ } else if (mentionable instanceof User) {
return getPlayerFromUser((User) mentionable)
.map(player -> Pair.of((User) mentionable, player))
.map(Collections::singleton)
.orElse(Collections.emptySet());
- }
- else {
+ } else {
return Collections.emptyList();
}
}
@@ -55,4 +66,115 @@ else if (mentionable instanceof User) {
public List getPlayers() {
return players;
}
+
+ public CompletableFuture uploadPlayersToRemote(DiscordApi discordApi) {
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(Settings.getRemoteDataSettings().getUrl() + "/character"))
+ .header("Authorization", "Bearer " + Settings.getRemoteDataSettings().getToken())
+ .GET()
+ .build();
+
+ return HTTP_CLIENT.sendAsync(request, HttpResponse.BodyHandlers.ofString())
+ .>thenApply(response -> GSON.fromJson(
+ response.body(),
+ RemoteCharacter.LIST_TYPE_TOKEN.getType()
+ ))
+ .thenApply(this::getPlayersWithoutRemoteCharacters)
+ .thenCompose(players -> CompletableFuture.allOf(players.stream()
+ .map(player -> createCharacterFor(discordApi, player))
+ .toArray(CompletableFuture[]::new)
+ ))
+ .thenApply(ignore -> discordApi);
+ }
+
+ private List getPlayersWithoutRemoteCharacters(List remoteCharacters) {
+ List existingSheets = remoteCharacters.stream()
+ .map(RemoteCharacter::sheet)
+ .toList();
+
+ return players.stream()
+ .filter(player -> !existingSheets.contains(player.getSheetId()))
+ .toList();
+ }
+
+ private CompletableFuture createCharacterFor(DiscordApi discordApi, Player player) {
+ return this.findUserForPlayer(Long.toString(player.getDiscordId()))
+ .thenCompose(existingUser -> existingUser.map(CompletableFuture::completedFuture)
+ .orElseGet(() -> this.createUserForPlayer(discordApi, player))
+ )
+ .thenCompose(remoteUser -> createCharacterFor(remoteUser, player))
+ .thenAccept(remoteCharacter -> LOGGER.info("Created new Remote Character {}", remoteCharacter.name()));
+ }
+
+ private CompletableFuture createCharacterFor(RemoteUser remoteUser, Player player) {
+ LOGGER.info("Creating new character for user {}", player.getDiscordId());
+ return SheetsHandler.getName(player.getSheetId())
+ .thenCompose(name -> {
+ if (!name.isEmpty()) {
+ Map map = new HashMap<>();
+
+ map.put("name", name);
+ map.put("sheet", player.getSheetId());
+ map.put("ownerId", remoteUser.id());
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(Settings.getRemoteDataSettings().getUrl() + "/character"))
+ .header("Authorization", "Bearer " + Settings.getRemoteDataSettings().getToken())
+ .POST(HttpRequest.BodyPublishers.ofString(GSON.toJson(map)))
+ .build();
+
+ return HTTP_CLIENT.sendAsync(request, HttpResponse.BodyHandlers.ofString())
+ .thenApply(response -> GSON.fromJson(response.body(), RemoteCharacter.class));
+ } else {
+ throw new CompletionException(new IllegalStateException("Failed to get name for " + player.getSheetId()));
+ }
+ });
+ }
+
+ private CompletableFuture> findUserForPlayer(String discordId) {
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(Settings.getRemoteDataSettings().getUrl() + "/user?external_id=" + discordId))
+ .header("Authorization", "Bearer " + Settings.getRemoteDataSettings().getToken())
+ .GET()
+ .build();
+
+ return HTTP_CLIENT.sendAsync(request, HttpResponse.BodyHandlers.ofString())
+ .>thenApply(response -> GSON.fromJson(response.body(), RemoteUser.LIST_TYPE_TOKEN.getType()))
+ .thenApply(existingUsers -> existingUsers.stream()
+ .filter(user -> Optional.ofNullable(user.externalId())
+ .filter(discordId::equals)
+ .isPresent()
+ )
+ .findFirst()
+ );
+ }
+
+ private CompletableFuture createUserForPlayer(DiscordApi discordApi, Player player) {
+ Optional doomPoolId = DoomHandler.getDoomPool(player.getDoomPool())
+ .flatMap(doomPool -> {
+ if (doomPool instanceof RemoteDoomPool remoteDoomPool) {
+ return Optional.of(remoteDoomPool.id());
+ } else {
+ return Optional.empty();
+ }
+ });
+ LOGGER.info("Creating new user for user {}", player.getDiscordId());
+ return discordApi.getUserById(player.getDiscordId())
+ .thenCompose(user -> {
+ Map requestValues = new HashMap<>();
+ requestValues.put("name", user.getName());
+ requestValues.put("externalId", Long.toString(player.getDiscordId()));
+ requestValues.put("notes", "Created by TwoDee");
+ doomPoolId.ifPresent(id -> requestValues.put("doomPermission", id.toString()));
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create(Settings.getRemoteDataSettings().getUrl() + "/user"))
+ .header("Authorization", "Bearer " + Settings.getRemoteDataSettings().getToken())
+ .POST(HttpRequest.BodyPublishers.ofString(GSON.toJson(requestValues)))
+ .build();
+
+ return HTTP_CLIENT.sendAsync(request, HttpResponse.BodyHandlers.ofString());
+ })
+ .thenApply(response -> GSON.fromJson(response.body(), RemoteUser.class));
+ }
}
diff --git a/src/main/java/roles/RemoteCharacter.java b/src/main/java/roles/RemoteCharacter.java
new file mode 100644
index 0000000..e125c89
--- /dev/null
+++ b/src/main/java/roles/RemoteCharacter.java
@@ -0,0 +1,18 @@
+package roles;
+
+import com.google.gson.reflect.TypeToken;
+
+import java.util.List;
+import java.util.Map;
+
+public record RemoteCharacter(
+ long id,
+ String name,
+ String sheet,
+ long ownerId,
+ int plotPoints,
+ Map skills
+) {
+ public static final TypeToken> LIST_TYPE_TOKEN = new TypeToken<>() {
+ };
+}
diff --git a/src/main/java/roles/RemoteUser.java b/src/main/java/roles/RemoteUser.java
new file mode 100644
index 0000000..22510c6
--- /dev/null
+++ b/src/main/java/roles/RemoteUser.java
@@ -0,0 +1,22 @@
+package roles;
+
+import com.google.gson.reflect.TypeToken;
+
+import javax.annotation.Nullable;
+import java.util.List;
+
+public record RemoteUser(
+ long id,
+ String name,
+ String characterPermission,
+ String doomPermission,
+ String userPermission,
+ String tokenPermission,
+ @Nullable String externalId,
+ String notes,
+ boolean active,
+ @Nullable Long createdBy
+) {
+ public static final TypeToken> LIST_TYPE_TOKEN = new TypeToken<>() {
+ };
+}
diff --git a/src/main/java/sheets/SheetsHandler.java b/src/main/java/sheets/SheetsHandler.java
index 80f6e1e..8b1f51d 100644
--- a/src/main/java/sheets/SheetsHandler.java
+++ b/src/main/java/sheets/SheetsHandler.java
@@ -19,6 +19,8 @@
import org.apache.commons.lang3.tuple.Pair;
import org.javacord.api.entity.user.User;
import org.javacord.api.interaction.SlashCommandOptionChoice;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import roles.Player;
import roles.PlayerHandler;
@@ -30,9 +32,11 @@
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
import java.util.stream.Collectors;
public class SheetsHandler {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SheetsHandler.class);
private static final String APPLICATION_NAME = "Skill Lookup";
private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
private static final String TOKENS_DIRECTORY_PATH = "tokens";
@@ -117,7 +121,7 @@ private static Optional getPlotPointRange(User user) {
try {
return Optional.of(instance.service.spreadsheets().values().get(spreadsheetForUser.get(), "PlotPoints").execute());
} catch (IOException e) {
- e.printStackTrace();
+ LOGGER.error("Error while reading plot point range for user {}", spreadsheetForUser, e);
}
}
return Optional.empty();
@@ -159,7 +163,7 @@ public static CompletableFuture> setPlotPoints(User user, int
final int updatedPlotPointCount = Integer.parseInt((String) plotPointsCellUpdateRequest.getUpdatedData().getValues().get(0).get(0));
return Optional.of(updatedPlotPointCount);
} catch (IOException e) {
- e.printStackTrace();
+ LOGGER.error("Error while setting plot points for user {}", user, e);
}
return Optional.empty();
}
@@ -167,16 +171,6 @@ public static CompletableFuture> setPlotPoints(User user, int
});
}
- /**
- * A functon used to throw an exception. Used in completable futures to allow exceptions to be handled in exceptonally
- *
- * @throws T The exception to throw
- */
- @SuppressWarnings("all")
- public static R sneakyThrow(Throwable t) throws T {
- throw (T) t;
- }
-
/**
* Gets the current bleed value of a player
@@ -190,7 +184,7 @@ public static Optional getPlayerBleed(User user) {
try {
return Optional.of(instance.service.spreadsheets().values().get(spreadsheetForUser.get(), "PlotPointBleed").execute()).map(valueRange -> Integer.parseInt((String) valueRange.getValues().get(0).get(0)));
} catch (IOException e) {
- e.printStackTrace();
+ LOGGER.error("Error while reading player bleed for user {}", user, e);
}
}
return Optional.empty();
@@ -300,4 +294,20 @@ private static ValueRange getRange(String spreadsheetID, String range) throws IO
.get(spreadsheetID, range)
.execute();
}
+
+ public static CompletableFuture getName(String spreadsheetId) {
+ return CompletableFuture.supplyAsync(() -> {
+ try {
+ ValueRange valueRange = getRange(spreadsheetId, "B1:L2");
+ return valueRange.getValues()
+ .stream()
+ .flatMap(List::stream)
+ .findFirst()
+ .map(Object::toString)
+ .orElse("");
+ } catch (IOException e) {
+ throw new CompletionException(e);
+ }
+ });
+ }
}
diff --git a/src/main/java/util/CachedValue.java b/src/main/java/util/CachedValue.java
new file mode 100644
index 0000000..a6d217a
--- /dev/null
+++ b/src/main/java/util/CachedValue.java
@@ -0,0 +1,42 @@
+package util;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+public class CachedValue {
+ private final long ttlMillis;
+ private final Supplier refresh;
+
+ private final AtomicLong expiryTime;
+ private final AtomicReference value;
+
+ public CachedValue(long ttlMillis, Supplier refresh) {
+ this.ttlMillis = ttlMillis;
+ this.refresh = refresh;
+ this.value = new AtomicReference<>();
+ this.expiryTime = new AtomicLong();
+ }
+
+ public T get() {
+ if (expiryTime.get() < System.currentTimeMillis()) {
+ this.value.set(null);
+ }
+
+ T currentValue = this.value.get();
+ if (currentValue == null) {
+ currentValue = refresh.get();
+ this.value.set(currentValue);
+ this.expiryTime.set(System.currentTimeMillis() + ttlMillis);
+ }
+ return currentValue;
+ }
+
+ public void initialize() {
+ this.get();
+ }
+
+ public void forceRefresh() {
+ this.value.set(null);
+ }
+}
diff --git a/src/main/java/util/DamerauLevenshtein.java b/src/main/java/util/DamerauLevenshtein.java
index 79a3f75..df46874 100644
--- a/src/main/java/util/DamerauLevenshtein.java
+++ b/src/main/java/util/DamerauLevenshtein.java
@@ -1,16 +1,15 @@
package util;
import com.google.common.collect.Lists;
-import doom.DoomHandler;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
public class DamerauLevenshtein {
- private static final Logger LOGGER = LogManager.getLogger(DamerauLevenshtein.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(DamerauLevenshtein.class);
/**
* Calculates the string distance between source and target strings using
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
deleted file mode 100644
index 4a20803..0000000
--- a/src/main/resources/log4j2.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file