Creates all (?) endpoints

This commit is contained in:
Guillaume Tâche
2025-04-21 22:10:24 +02:00
commit 8a05f63687
263 changed files with 4821 additions and 0 deletions

5
.dockerignore Normal file
View File

@@ -0,0 +1,5 @@
*
!target/*-runner
!target/*-runner.jar
!target/lib/*
!target/quarkus-app/*

45
.gitignore vendored Normal file
View File

@@ -0,0 +1,45 @@
#Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
release.properties
.flattened-pom.xml
# Eclipse
.project
.classpath
.settings/
bin/
# IntelliJ
.idea
*.ipr
*.iml
*.iws
# NetBeans
nb-configuration.xml
# Visual Studio Code
.vscode
.factorypath
# OSX
.DS_Store
# Vim
*.swp
*.swo
# patch
*.orig
*.rej
# Local environment
.env
# Plugin directory
/.quarkus/cli/plugins/
# TLS Certificates
.certs/

1
.mvn/wrapper/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
maven-wrapper.jar

View File

@@ -0,0 +1,93 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.
*/
import java.io.IOException;
import java.io.InputStream;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.concurrent.ThreadLocalRandom;
public final class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "3.3.2";
private static final boolean VERBOSE = Boolean.parseBoolean(System.getenv("MVNW_VERBOSE"));
public static void main(String[] args) {
log("Apache Maven Wrapper Downloader " + WRAPPER_VERSION);
if (args.length != 2) {
System.err.println(" - ERROR wrapperUrl or wrapperJarPath parameter missing");
System.exit(1);
}
try {
log(" - Downloader started");
final URL wrapperUrl = URI.create(args[0]).toURL();
final String jarPath = args[1].replace("..", ""); // Sanitize path
final Path wrapperJarPath = Paths.get(jarPath).toAbsolutePath().normalize();
downloadFileFromURL(wrapperUrl, wrapperJarPath);
log("Done");
} catch (IOException e) {
System.err.println("- Error downloading: " + e.getMessage());
if (VERBOSE) {
e.printStackTrace();
}
System.exit(1);
}
}
private static void downloadFileFromURL(URL wrapperUrl, Path wrapperJarPath)
throws IOException {
log(" - Downloading to: " + wrapperJarPath);
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
final String username = System.getenv("MVNW_USERNAME");
final char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
Path temp = wrapperJarPath
.getParent()
.resolve(wrapperJarPath.getFileName() + "."
+ Long.toUnsignedString(ThreadLocalRandom.current().nextLong()) + ".tmp");
try (InputStream inStream = wrapperUrl.openStream()) {
Files.copy(inStream, temp, StandardCopyOption.REPLACE_EXISTING);
Files.move(temp, wrapperJarPath, StandardCopyOption.REPLACE_EXISTING);
} finally {
Files.deleteIfExists(temp);
}
log(" - Downloader complete");
}
private static void log(String msg) {
if (VERBOSE) {
System.out.println(msg);
}
}
}

20
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View File

@@ -0,0 +1,20 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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
#
# http://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.
wrapperVersion=3.3.2
distributionType=source
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar

84
README.md Normal file
View File

@@ -0,0 +1,84 @@
# elders-scrolls-legends-service
This project uses Quarkus, the Supersonic Subatomic Java Framework.
If you want to learn more about Quarkus, please visit its website: <https://quarkus.io/>.
## Running the application in dev mode
You can run your application in dev mode that enables live coding using:
```shell script
./mvnw quarkus:dev
```
> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at <http://localhost:8080/q/dev/>.
## Packaging and running the application
The application can be packaged using:
```shell script
./mvnw package
```
It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory.
Be aware that its not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory.
The application is now runnable using `java -jar target/quarkus-app/quarkus-run.jar`.
If you want to build an _über-jar_, execute the following command:
```shell script
./mvnw package -Dquarkus.package.jar.type=uber-jar
```
The application, packaged as an _über-jar_, is now runnable using `java -jar target/*-runner.jar`.
## Creating a native executable
You can create a native executable using:
```shell script
./mvnw package -Dnative
```
Or, if you don't have GraalVM installed, you can run the native executable build in a container using:
```shell script
./mvnw package -Dnative -Dquarkus.native.container-build=true
```
You can then execute your native executable with: `./target/elders-scrolls-legends-service-1.0-SNAPSHOT-runner`
If you want to learn more about building native executables, please consult <https://quarkus.io/guides/maven-tooling>.
## Related Guides
- REST ([guide](https://quarkus.io/guides/rest)): A Jakarta REST implementation utilizing build time processing and
Vert.x. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on
it.
- Elytron Security OAuth 2.0 ([guide](https://quarkus.io/guides/security-oauth2)): Secure your applications with OAuth2
opaque tokens
- WebSockets Next ([guide](https://quarkus.io/guides/websockets-next-reference)): Implementation of the WebSocket API
with enhanced efficiency and usability
- SmallRye OpenAPI ([guide](https://quarkus.io/guides/openapi-swaggerui)): Document your REST APIs with OpenAPI - comes
with Swagger UI
- REST Jackson ([guide](https://quarkus.io/guides/rest#json-serialisation)): Jackson serialization support for Quarkus
REST. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on it
- Logging GELF ([guide](https://quarkus.io/guides/centralized-log-management)): Log using the Graylog Extended Log
Format and centralize your logs in ELK or EFK
- Elytron Security JDBC ([guide](https://quarkus.io/guides/security-jdbc)): Secure your applications with
username/password stored in a database
- Jacoco - Code Coverage ([guide](https://quarkus.io/guides/tests-with-coverage)): Jacoco test coverage support
- Mailer ([guide](https://quarkus.io/guides/mailer)): Send emails
- SmallRye Metrics ([guide](https://quarkus.io/guides/smallrye-metrics)): Expose metrics for your services
- JDBC Driver - PostgreSQL ([guide](https://quarkus.io/guides/datasource)): Connect to the PostgreSQL database via JDBC
## Provided Code
### REST
Easily start your REST Web Services
[Related guide section...](https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources)

332
mvnw vendored Normal file
View File

@@ -0,0 +1,332 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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
#
# http://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.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.3.2
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ]; then
if [ -f /usr/local/etc/mavenrc ]; then
. /usr/local/etc/mavenrc
fi
if [ -f /etc/mavenrc ]; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ]; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false
darwin=false
mingw=false
case "$(uname)" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true ;;
Darwin*)
darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
JAVA_HOME="$(/usr/libexec/java_home)"
export JAVA_HOME
else
JAVA_HOME="/Library/Java/Home"
export JAVA_HOME
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ]; then
if [ -r /etc/gentoo-release ]; then
JAVA_HOME=$(java-config --jre-home)
fi
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin; then
[ -n "$JAVA_HOME" ] \
&& JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
[ -n "$CLASSPATH" ] \
&& CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw; then
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] \
&& JAVA_HOME="$(
cd "$JAVA_HOME" || (
echo "cannot cd into $JAVA_HOME." >&2
exit 1
)
pwd
)"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="$(which javac)"
if [ -n "$javaExecutable" ] && ! [ "$(expr "$javaExecutable" : '\([^ ]*\)')" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=$(which readlink)
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
if $darwin; then
javaHome="$(dirname "$javaExecutable")"
javaExecutable="$(cd "$javaHome" && pwd -P)/javac"
else
javaExecutable="$(readlink -f "$javaExecutable")"
fi
javaHome="$(dirname "$javaExecutable")"
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ]; then
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
else
JAVACMD="$(
\unset -f command 2>/dev/null
\command -v java
)"
fi
fi
if [ ! -x "$JAVACMD" ]; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ]; then
echo "Warning: JAVA_HOME environment variable is not set." >&2
fi
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]; then
echo "Path not specified to find_maven_basedir" >&2
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ]; do
if [ -d "$wdir"/.mvn ]; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=$(
cd "$wdir/.." || exit 1
pwd
)
fi
# end of workaround
done
printf '%s' "$(
cd "$basedir" || exit 1
pwd
)"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
# Remove \r in case we run on Windows within Git Bash
# and check out the repository with auto CRLF management
# enabled. Otherwise, we may read lines that are delimited with
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
# splitting rules.
tr -s '\r\n' ' ' <"$1"
fi
}
log() {
if [ "$MVNW_VERBOSE" = true ]; then
printf '%s\n' "$1"
fi
}
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
if [ -z "$BASE_DIR" ]; then
exit 1
fi
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
export MAVEN_PROJECTBASEDIR
log "$MAVEN_PROJECTBASEDIR"
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
if [ -r "$wrapperJarPath" ]; then
log "Found $wrapperJarPath"
else
log "Couldn't find $wrapperJarPath, downloading it ..."
if [ -n "$MVNW_REPOURL" ]; then
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
else
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
fi
while IFS="=" read -r key value; do
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
safeValue=$(echo "$value" | tr -d '\r')
case "$key" in wrapperUrl)
wrapperUrl="$safeValue"
break
;;
esac
done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
log "Downloading from: $wrapperUrl"
if $cygwin; then
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
fi
if command -v wget >/dev/null; then
log "Found wget ... using wget"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl >/dev/null; then
log "Found curl ... using curl"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
else
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
fi
else
log "Falling back to using Java to download"
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaSource=$(cygpath --path --windows "$javaSource")
javaClass=$(cygpath --path --windows "$javaClass")
fi
if [ -e "$javaSource" ]; then
if [ ! -e "$javaClass" ]; then
log " - Compiling MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/javac" "$javaSource")
fi
if [ -e "$javaClass" ]; then
log " - Running MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
wrapperSha256Sum=""
while IFS="=" read -r key value; do
case "$key" in wrapperSha256Sum)
wrapperSha256Sum=$value
break
;;
esac
done <"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
if [ -n "$wrapperSha256Sum" ]; then
wrapperSha256Result=false
if command -v sha256sum >/dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c >/dev/null 2>&1; then
wrapperSha256Result=true
fi
elif command -v shasum >/dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c >/dev/null 2>&1; then
wrapperSha256Result=true
fi
else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties." >&2
exit 1
fi
if [ $wrapperSha256Result = false ]; then
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
exit 1
fi
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$JAVA_HOME" ] \
&& JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
[ -n "$CLASSPATH" ] \
&& CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
[ -n "$MAVEN_PROJECTBASEDIR" ] \
&& MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
# shellcheck disable=SC2086 # safe args
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

206
mvnw.cmd vendored Normal file
View File

@@ -0,0 +1,206 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Apache Maven Wrapper startup batch script, version 3.3.2
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo. >&2
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo. >&2
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo. >&2
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo. >&2
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %WRAPPER_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
SET WRAPPER_SHA_256_SUM=""
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
)
IF NOT %WRAPPER_SHA_256_SUM%=="" (
powershell -Command "&{"^
"Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash;"^
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
" Write-Error 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
" Write-Error 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
" Write-Error 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
" exit 1;"^
"}"^
"}"
if ERRORLEVEL 1 goto error
)
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %WRAPPER_JAR% ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%

173
pom.xml Normal file
View File

@@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.gtache</groupId>
<artifactId>elders-scrolls-legends-service</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.14.0</compiler-plugin.version>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.21.2</quarkus.platform.version>
<skipITs>true</skipITs>
<steamworks.version>1.9.0</steamworks.version>
<surefire-plugin.version>3.5.2</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.code-disaster.steamworks4j</groupId>
<artifactId>steamworks4j</artifactId>
<version>${steamworks.version}</version>
</dependency>
<dependency>
<groupId>com.code-disaster.steamworks4j</groupId>
<artifactId>steamworks4j-server</artifactId>
<version>${steamworks.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-websockets-next</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-openapi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-logging-gelf</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jacoco</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-mailer</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-metrics</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
<goal>native-image-agent</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<parameters>true</parameters>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<skipITs>false</skipITs>
<quarkus.native.enabled>true</quarkus.native.enabled>
</properties>
</profile>
</profiles>
</project>

View File

@@ -0,0 +1,98 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
#
# Before building the container image run:
#
# ./mvnw package
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/elders-scrolls-legends-service-jvm .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/elders-scrolls-legends-service-jvm
#
# If you want to include the debug port into your docker image
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
# when running the container
#
# Then run the container using :
#
# docker run -i --rm -p 8080:8080 quarkus/elders-scrolls-legends-service-jvm
#
# This image uses the `run-java.sh` script to run the application.
# This scripts computes the command line to execute your Java application, and
# includes memory/GC tuning.
# You can configure the behavior using the following environment properties:
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") - Be aware that this will override
# the default JVM options, use `JAVA_OPTS_APPEND` to append options
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
# in JAVA_OPTS (example: "-Dsome.property=foo")
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
# used to calculate a default maximal heap memory based on a containers restriction.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
# of the container available memory as set here. The default is `50` which means 50%
# of the available memory is used as an upper boundary. You can skip this mechanism by
# setting this value to `0` in which case no `-Xmx` option is added.
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
# is used to calculate a default initial heap memory based on the maximum heap memory.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
# is used as the initial heap size. You can skip this mechanism by setting this value
# to `0` in which case no `-Xms` option is added (example: "25")
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
# This is used to calculate the maximum value of the initial heap memory. If used in
# a container without any memory constraints for the container then this option has
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
# here. The default is 4096MB which means the calculated value of `-Xms` never will
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
# when things are happening. This option, if set to true, will set
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
# true").
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
# (example: "20")
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
# (example: "40")
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
# (example: "4")
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
# previous GC times. (example: "90")
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
# contain the necessary JRE command-line options to specify the required GC, which
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
# accessed directly. (example: "foo.example.com,bar.example.com")
#
###
FROM registry.access.redhat.com/ubi9/openjdk-21:1.21
ENV LANGUAGE='en_US:en'
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]

View File

@@ -0,0 +1,94 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
#
# Before building the container image run:
#
# ./mvnw package -Dquarkus.package.jar.type=legacy-jar
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/elders-scrolls-legends-service-legacy-jar .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/elders-scrolls-legends-service-legacy-jar
#
# If you want to include the debug port into your docker image
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
# when running the container
#
# Then run the container using :
#
# docker run -i --rm -p 8080:8080 quarkus/elders-scrolls-legends-service-legacy-jar
#
# This image uses the `run-java.sh` script to run the application.
# This scripts computes the command line to execute your Java application, and
# includes memory/GC tuning.
# You can configure the behavior using the following environment properties:
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class") - Be aware that this will override
# the default JVM options, use `JAVA_OPTS_APPEND` to append options
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
# in JAVA_OPTS (example: "-Dsome.property=foo")
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
# used to calculate a default maximal heap memory based on a containers restriction.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
# of the container available memory as set here. The default is `50` which means 50%
# of the available memory is used as an upper boundary. You can skip this mechanism by
# setting this value to `0` in which case no `-Xmx` option is added.
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
# is used to calculate a default initial heap memory based on the maximum heap memory.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
# is used as the initial heap size. You can skip this mechanism by setting this value
# to `0` in which case no `-Xms` option is added (example: "25")
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
# This is used to calculate the maximum value of the initial heap memory. If used in
# a container without any memory constraints for the container then this option has
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
# here. The default is 4096MB which means the calculated value of `-Xms` never will
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
# when things are happening. This option, if set to true, will set
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
# true").
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
# (example: "20")
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
# (example: "40")
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
# (example: "4")
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
# previous GC times. (example: "90")
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
# contain the necessary JRE command-line options to specify the required GC, which
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
# accessed directly. (example: "foo.example.com,bar.example.com")
#
###
FROM registry.access.redhat.com/ubi9/openjdk-21:1.21
ENV LANGUAGE='en_US:en'
COPY target/lib/* /deployments/lib/
COPY target/*-runner.jar /deployments/quarkus-run.jar
EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]

View File

@@ -0,0 +1,29 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
#
# Before building the container image run:
#
# ./mvnw package -Dnative
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.native -t quarkus/elders-scrolls-legends-service .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/elders-scrolls-legends-service
#
# The ` registry.access.redhat.com/ubi9/ubi-minimal:9.5` base image is based on UBI 9.
# To use UBI 8, switch to `quay.io/ubi8/ubi-minimal:8.10`.
###
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.5
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root --chmod=0755 target/*-runner /work/application
EXPOSE 8080
USER 1001
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]

View File

@@ -0,0 +1,32 @@
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
# It uses a micro base image, tuned for Quarkus native executables.
# It reduces the size of the resulting container image.
# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image.
#
# Before building the container image run:
#
# ./mvnw package -Dnative
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/elders-scrolls-legends-service .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/elders-scrolls-legends-service
#
# The `quay.io/quarkus/ubi9-quarkus-micro-image:2.0` base image is based on UBI 9.
# To use UBI 8, switch to `quay.io/quarkus/quarkus-micro-image:2.0`.
###
FROM quay.io/quarkus/ubi9-quarkus-micro-image:2.0
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root --chmod=0755 target/*-runner /work/application
EXPOSE 8080
USER 1001
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]

View File

@@ -0,0 +1,46 @@
package ch.gtache.elderscrollslegends.service;
import com.codedisaster.steamworks.SteamException;
import com.codedisaster.steamworks.SteamGameServerAPI;
import io.quarkus.runtime.Quarkus;
import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;
import static java.util.Objects.requireNonNull;
@ApplicationScoped
public class ApplicationLifecycle {
private static final Logger logger = Logger.getLogger(ApplicationLifecycle.class);
private final SteamService steamService;
@Inject
ApplicationLifecycle(final SteamService steamService) {
this.steamService = requireNonNull(steamService);
}
void onStart(@Observes final StartupEvent event) {
logger.info("Starting up");
try {
SteamGameServerAPI.loadLibraries();
if (!SteamGameServerAPI.init(0, (short) 8080, (short) 8081,
SteamGameServerAPI.ServerMode.AuthenticationAndSecure, "1.0.0")) {
logger.error("SteamAPI failed to initialize");
Quarkus.asyncExit();
}
} catch (final SteamException e) {
logger.error("SteamAPI failed to initialize", e);
Quarkus.asyncExit();
}
}
void onShutdown(@Observes final ShutdownEvent event) {
logger.info("Shutting down");
steamService.endAllAuthSessions();
SteamGameServerAPI.shutdown();
}
}

View File

@@ -0,0 +1,150 @@
package ch.gtache.elderscrollslegends.service;
import com.codedisaster.steamworks.*;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HexFormat;
public class Main {
public static void main(String[] args) throws SteamException, InterruptedException {
SteamGameServerAPI.loadLibraries();
if (SteamGameServerAPI.init(0, (short) 8080, (short) 8081, SteamGameServerAPI.ServerMode.AuthenticationAndSecure, "1.0.0")) {
final var server = new SteamGameServer(new GameServerCallback());
server.setDedicatedServer(true);
server.setGameDescription("The Elder Scrolls Legends");
server.setProduct("364470");
server.setServerName("TESL");
server.logOnAnonymous();
Thread.sleep(5000L);
SteamAPI.loadLibraries();
if (SteamAPI.init()) {
final var steamUser = new SteamUser(new SteamUserCallback());
final var buffer = ByteBuffer.allocateDirect(1024);
final var ticket = steamUser.getAuthSessionTicket(buffer, new int[]{1024});
if (ticket != null && ticket.isValid()) {
final var baos = new java.io.ByteArrayOutputStream();
var i = 0;
while (i < buffer.limit()) {
baos.write(buffer.get(i));
i++;
}
final var bytes = baos.toByteArray();
buffer.position(0);
final var hex = HexFormat.of().formatHex(bytes);
System.out.println(hex + " <=> " + Arrays.toString(bytes));
final var result = server.beginAuthSession(buffer, steamUser.getSteamID());
final var result2 = steamUser.beginAuthSession(buffer, steamUser.getSteamID());
System.out.println(result + " - " + result2);
Thread.sleep(5000L);
SteamAPI.runCallbacks();
SteamGameServerAPI.runCallbacks();
server.endAuthSession(steamUser.getSteamID());
steamUser.cancelAuthTicket(ticket);
server.logOff();
Thread.sleep(5000L);
SteamAPI.runCallbacks();
SteamGameServerAPI.runCallbacks();
System.out.println("Closed ticket");
} else {
System.out.println("Couldn't get auth session ticket");
}
} else {
System.out.println("Couldn't init SteamAPI");
}
} else {
System.out.println("Couldn't init SteamGameServerAPI");
}
SteamGameServerAPI.shutdown();
SteamAPI.shutdown();
}
private static class GameServerCallback implements SteamGameServerCallback {
@Override
public void onValidateAuthTicketResponse(final SteamID steamID,
final SteamAuth.AuthSessionResponse authSessionResponse,
final SteamID ownerSteamID) {
System.out.println("Validate auth ticket response : " + steamID +
" (" + authSessionResponse + " : " + ownerSteamID + ")");
}
@Override
public void onSteamServersConnected() {
System.out.println("Steam servers connected");
}
@Override
public void onSteamServerConnectFailure(final SteamResult result, final boolean stillRetrying) {
System.out.println("Steam server connect failure : " + result + " (" + stillRetrying + ")");
}
@Override
public void onSteamServersDisconnected(final SteamResult result) {
System.out.println("Steam server disconnected : " + result);
}
@Override
public void onClientApprove(final SteamID steamID, final SteamID ownerSteamID) {
System.out.println("Client approved : " + steamID + " (" + ownerSteamID + ")");
}
@Override
public void onClientDeny(final SteamID steamID, final SteamGameServer.DenyReason denyReason,
final String optionalText) {
System.out.println("Client denied : " + steamID + " (" + denyReason + " : " + optionalText + ")");
}
@Override
public void onClientKick(final SteamID steamID, final SteamGameServer.DenyReason denyReason) {
System.out.println("Client kicked : " + steamID + " (" + denyReason + ")");
}
@Override
public void onClientGroupStatus(final SteamID steamID, final SteamID steamIDGroup,
final boolean isMember, final boolean isOfficer) {
System.out.println("Client group status : " + steamID +
" (" + steamIDGroup + " : " + isMember + " : " + isOfficer + ")");
}
@Override
public void onAssociateWithClanResult(final SteamResult result) {
System.out.println("Associate with clan result : " + result);
}
@Override
public void onComputeNewPlayerCompatibilityResult(final SteamResult result,
final int playersThatDontLikeCandidate,
final int playersThatCandidateDoesntLike,
final int clanPlayersThatDontLikeCandidate,
final SteamID steamIDCandidate) {
System.out.println("onComputeNewPlayerCompatibilityResult : " + result + " (" + playersThatDontLikeCandidate +
" : " + playersThatCandidateDoesntLike + " : " + clanPlayersThatDontLikeCandidate +
" : " + steamIDCandidate + ")");
}
}
private static class SteamUserCallback implements com.codedisaster.steamworks.SteamUserCallback {
@Override
public void onAuthSessionTicket(final SteamAuthTicket authTicket, final SteamResult result) {
System.out.println("Auth session ticket : " + authTicket + " (" + result + ")");
}
@Override
public void onValidateAuthTicket(final SteamID steamID, final SteamAuth.AuthSessionResponse authSessionResponse, final SteamID ownerSteamID) {
System.out.println("Validate auth ticket : " + steamID +
" (" + authSessionResponse + " : " + ownerSteamID + ")");
}
@Override
public void onMicroTxnAuthorization(final int appID, final long orderID, final boolean authorized) {
System.out.println("Micro txn authorization : " + appID + " (" + orderID + " : " + authorized + ")");
}
@Override
public void onEncryptedAppTicket(final SteamResult result) {
System.out.println("Encrypted app ticket : " + result);
}
}
}

View File

@@ -0,0 +1,8 @@
package ch.gtache.elderscrollslegends.service;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class Producers {
}

View File

@@ -0,0 +1,182 @@
package ch.gtache.elderscrollslegends.service;
import com.codedisaster.steamworks.SteamAuth;
import com.codedisaster.steamworks.SteamGameServer;
import com.codedisaster.steamworks.SteamGameServerAPI;
import com.codedisaster.steamworks.SteamGameServerCallback;
import com.codedisaster.steamworks.SteamID;
import com.codedisaster.steamworks.SteamNativeHandle;
import com.codedisaster.steamworks.SteamResult;
import org.jboss.logging.Logger;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import static java.util.Objects.requireNonNull;
class ServerCallback implements SteamGameServerCallback {
private static final Logger logger = Logger.getLogger(ServerCallback.class);
private SteamGameServer steamServer;
private final String token;
private final AtomicBoolean running;
private final AtomicLong validating;
private final AtomicBoolean valid;
private final Thread callbacksThread;
ServerCallback(final String token) {
this.token = requireNonNull(token);
this.running = new AtomicBoolean(false);
this.validating = new AtomicLong(0L);
this.valid = new AtomicBoolean(false);
this.callbacksThread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
trySleep();
SteamGameServerAPI.runCallbacks();
}
});
callbacksThread.setDaemon(true);
}
void setSteamServer(final SteamGameServer steamServer) {
this.steamServer = requireNonNull(steamServer);
callbacksThread.start();
}
void setRunning() {
while (setRunFailed()) {
trySleep();
}
}
void waitForCallback() {
while (isRunningOrNotInterrupted()) {
trySleep();
}
}
void setValidating(final long steamIDHandle) {
setRunning();
while (setValidatingFailed(steamIDHandle)) {
trySleep();
}
}
boolean checkValid(final long steamIDHandle) {
if (validating.get() == steamIDHandle) {
while (isRunningOrNotInterrupted()) {
trySleep();
}
final var isValid = valid.get();
validating.compareAndSet(steamIDHandle, 0L);
valid.set(false);
return isValid;
} else {
throw new IllegalStateException("SteamID " + steamIDHandle + " is not validating");
}
}
@Override
public void onValidateAuthTicketResponse(final SteamID steamID,
final SteamAuth.AuthSessionResponse authSessionResponse,
final SteamID ownerSteamID) {
logger.info("Validate auth ticket response : " + steamID +
" (" + authSessionResponse + " : " + ownerSteamID + ")");
final var steamIDHandle = SteamNativeHandle.getNativeHandle(steamID);
final var isValid = authSessionResponse == SteamAuth.AuthSessionResponse.OK;
if (steamIDHandle == validating.get()) {
valid.compareAndSet(false, isValid);
running.compareAndSet(true, false);
} else {
throw new IllegalStateException("SteamID " + steamIDHandle + " is not validating");
}
}
@Override
public void onSteamServersConnected() {
logger.info("Steam servers connected");
running.compareAndSet(true, false);
}
@Override
public void onSteamServerConnectFailure(final SteamResult result, final boolean stillRetrying) {
logger.warn("Steam server connect failure : " + result + " (" + stillRetrying + ")");
if (result == SteamResult.TryAnotherCM) {
logger.info("Trying another CM");
steamServer.logOn(token);
} else {
running.compareAndSet(true, false);
}
}
@Override
public void onSteamServersDisconnected(final SteamResult result) {
logger.info("Steam server disconnected : " + result);
running.compareAndSet(true, false);
}
@Override
public void onClientApprove(final SteamID steamID, final SteamID ownerSteamID) {
logger.info("Client approved : " + steamID + " (" + ownerSteamID + ")");
running.compareAndSet(true, false);
}
@Override
public void onClientDeny(final SteamID steamID, final SteamGameServer.DenyReason denyReason,
final String optionalText) {
logger.warn("Client denied : " + steamID + " (" + denyReason + " : " + optionalText + ")");
running.compareAndSet(true, false);
}
@Override
public void onClientKick(final SteamID steamID, final SteamGameServer.DenyReason denyReason) {
logger.info("Client kicked : " + steamID + " (" + denyReason + ")");
running.compareAndSet(true, false);
}
@Override
public void onClientGroupStatus(final SteamID steamID, final SteamID steamIDGroup,
final boolean isMember, final boolean isOfficer) {
logger.info("Client group status : " + steamID +
" (" + steamIDGroup + " : " + isMember + " : " + isOfficer + ")");
running.compareAndSet(true, false);
}
@Override
public void onAssociateWithClanResult(final SteamResult result) {
logger.info("Associate with clan result : " + result);
running.compareAndSet(true, false);
}
@Override
public void onComputeNewPlayerCompatibilityResult(final SteamResult result,
final int playersThatDontLikeCandidate,
final int playersThatCandidateDoesntLike,
final int clanPlayersThatDontLikeCandidate,
final SteamID steamIDCandidate) {
logger.info("onComputeNewPlayerCompatilibityResult : " + result + " (" + playersThatDontLikeCandidate +
" : " + playersThatCandidateDoesntLike + " : " + clanPlayersThatDontLikeCandidate +
" : " + steamIDCandidate + ")");
running.compareAndSet(true, false);
}
private boolean setRunFailed() {
return !Thread.currentThread().isInterrupted() && !running.compareAndSet(false, true);
}
private boolean setValidatingFailed(final long steamIDHandle) {
return !Thread.currentThread().isInterrupted() && !validating.compareAndSet(0L, steamIDHandle);
}
private boolean isRunningOrNotInterrupted() {
return !Thread.currentThread().isInterrupted() && running.get();
}
private static void trySleep() {
try {
Thread.sleep(500L);
} catch (final InterruptedException ignored) {
Thread.currentThread().interrupt();
}
}
}

View File

@@ -0,0 +1,96 @@
package ch.gtache.elderscrollslegends.service;
import com.codedisaster.steamworks.SteamAuth;
import com.codedisaster.steamworks.SteamException;
import com.codedisaster.steamworks.SteamGameServer;
import com.codedisaster.steamworks.SteamID;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.logging.Logger;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.ByteBuffer;
import java.util.HexFormat;
import java.util.regex.Pattern;
@ApplicationScoped
public class SteamService {
private static final Logger logger = Logger.getLogger(SteamService.class);
private static final Pattern NAME_PATTERN = Pattern.compile("<span class=\"actual_persona_name\">(?<name>.+)</span>");
private final SteamGameServer steamServer;
private final ServerCallback serverCallback;
private final HttpClient client;
@Inject
SteamService(@ConfigProperty(name = "steam.server.token") final String token) {
this.serverCallback = new ServerCallback(token);
this.steamServer = new SteamGameServer(serverCallback);
serverCallback.setSteamServer(steamServer);
this.client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.ALWAYS).build();
steamServer.setDedicatedServer(true);
steamServer.setGameDescription("The Elder Scrolls Legends");
steamServer.setProduct("364470");
steamServer.setServerName("TESL");
serverCallback.setRunning();
steamServer.logOn(token);
serverCallback.waitForCallback();
}
public boolean authenticate(final String sessionTicket, final String steamID) throws SteamException {
final var steamIDHandle = Long.parseLong(steamID);
final var id = SteamID.createFromNativeHandle(steamIDHandle);
final var bytes = HexFormat.of().parseHex(sessionTicket);
final var buffer = ByteBuffer.allocateDirect(bytes.length);
buffer.put(bytes);
buffer.position(0);
final var result = steamServer.beginAuthSession(buffer, id);
if (result == SteamAuth.BeginAuthSessionResult.OK) {
serverCallback.setValidating(steamIDHandle);
return serverCallback.checkValid(steamIDHandle);
} else {
logger.warn("Couldn't authenticate " + steamIDHandle + " with " + sessionTicket + " : " + result);
return false;
}
}
public String getName(final String steamID) {
final var request = HttpRequest.newBuilder().uri(URI.create("https://steamcommunity.com/profiles/" + steamID)).build();
try {
final var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
final var matcher = NAME_PATTERN.matcher(response.body());
if (matcher.find()) {
return matcher.group("name");
} else {
logger.warn("Couldn't get name for " + steamID + "in " + response.body() + ")");
}
} else {
logger.warn("Couldn't get name for " + steamID + " (" + response.statusCode() + ")");
}
} catch (final IOException e) {
logger.error("Error getting name for " + steamID, e);
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
logger.error("Error getting name for " + steamID, e);
}
return steamID;
}
public void endAuthSession(final String steamID) {
final var id = SteamID.createFromNativeHandle(Long.parseLong(steamID));
steamServer.endAuthSession(id);
}
public void endAllAuthSessions() {
}
}

View File

@@ -0,0 +1,6 @@
package ch.gtache.elderscrollslegends.service;
import java.time.Instant;
public record Token(String token, Instant expirationTimestamp) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account;
public record ABTestingSet(String setKey, String groupKey) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account;
public record AcceptLegalDocumentRequest(String legalDocumentId, String fingerprint, String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,143 @@
package ch.gtache.elderscrollslegends.service.account;
import ch.gtache.elderscrollslegends.service.SteamService;
import ch.gtache.elderscrollslegends.service.account.auth.AuthBNETGamecodeRequest;
import ch.gtache.elderscrollslegends.service.account.auth.AuthBNETSteamRequest;
import ch.gtache.elderscrollslegends.service.account.auth.AuthResult;
import ch.gtache.elderscrollslegends.service.account.auth.LogoutSteamRequest;
import ch.gtache.elderscrollslegends.service.account.check.CheckEmailRequest;
import ch.gtache.elderscrollslegends.service.account.check.CheckEmailResponse;
import ch.gtache.elderscrollslegends.service.account.check.CheckEmailResponseBody;
import ch.gtache.elderscrollslegends.service.account.check.CheckUsernameRequest;
import ch.gtache.elderscrollslegends.service.account.check.CheckUsernameResponse;
import ch.gtache.elderscrollslegends.service.account.check.CheckUsernameResponseBody;
import ch.gtache.elderscrollslegends.service.account.transfer.LegalDocumentsResponse;
import com.codedisaster.steamworks.SteamException;
import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import org.jboss.logging.Logger;
import java.time.Duration;
import java.util.List;
import static java.util.Objects.requireNonNull;
@Path("/account")
public class AccountEndpoints {
private static final Logger logger = Logger.getLogger(AccountEndpoints.class);
private final SteamService steamService;
private final AccountService accountService;
@Inject
AccountEndpoints(final SteamService steamService, final AccountService accountService) {
this.steamService = requireNonNull(steamService);
this.accountService = requireNonNull(accountService);
}
@POST
@Path("bnetSteamLogin")
@Consumes("application/json")
@Produces("application/json")
public AuthResult steamLogin(final AuthBNETSteamRequest request) {
logger.info("SteamLogin called : " + request);
try {
if (steamService.authenticate(request.sessionTicket(), request.steamId())) {
logger.info("SteamLogin succeeded for " + request);
final var data = accountService.authenticate(request.steamId());
return new AuthResult(data, 0, null, List.of());
} else {
return new AuthResult(null, 2, "SteamLogin failed", List.of());
}
} catch (final SteamException e) {
logger.error("SteamLogin failed for " + request, e);
return new AuthResult(null, 1, "SteamLogin failed", List.of());
}
}
@POST
@Path("bnetSteamLogout")
@Consumes("application/json")
public void steamLogout(final LogoutSteamRequest request) {
logger.info("SteamLogout called : " + request);
steamService.endAuthSession(request.steamId());
}
@POST
@Path("bnetGamecodeLogin")
@Consumes("application/json")
@Produces("application/json")
public AuthResult gamecodeLogin(final AuthBNETGamecodeRequest request) {
logger.info("GamecodeLogin called : " + request);
return null;
}
@POST
@Path("bnetCheckUsername")
@Consumes("application/json")
@Produces("application/json")
public CheckUsernameResponse checkUsername(final CheckUsernameRequest request) {
logger.info("CheckUsername called : " + request);
if (accountService.exists(request.username())) {
return new CheckUsernameResponse(new CheckUsernameResponseBody(true, true, 0));
} else {
return new CheckUsernameResponse(new CheckUsernameResponseBody(false, false, 1));
}
}
@POST
@Path("bnetCheckEmail")
@Consumes("application/json")
@Produces("application/json")
public CheckEmailResponse checkEmail(final CheckEmailRequest request) {
logger.info("CheckEmail called : " + request);
if (accountService.exists(request.email())) {
return new CheckEmailResponse(new CheckEmailResponseBody(true, 0));
} else {
return new CheckEmailResponse(new CheckEmailResponseBody(false, 1));
}
}
@POST
@Path("bnetRefreshSession")
@Consumes("application/json")
@Produces("application/json")
public RefreshSessionResponse refreshSession(final RefreshSessionRequest request) {
logger.info("RefreshSession called : " + request);
final var token = accountService.refresh(request.bnetKeyPlatform());
final var timeToRefresh = Duration.between(java.time.Instant.now(), token.expirationTimestamp()).getSeconds();
return new RefreshSessionResponse((int) timeToRefresh, token.token());
}
@POST
@Path("bnetGetLegalDocumentsForUser")
@Consumes("application/json")
@Produces("application/json")
public LegalDocumentsResponse getLegalDocumentsForUser(@HeaderParam("Authorization") final String authentication,
final GetLegalDocumentsForUserRequest request) {
logger.info("GetLegalDocumentsForUser called : " + request);
return null;
}
@POST
@Path("bnetAcceptLegalDocument")
@Consumes("application/json")
public void acceptLegalDocument(@HeaderParam("Authorization") final String authentication,
final AcceptLegalDocumentRequest request) {
logger.info("acceptLegalDocument called : " + request);
}
@POST
@Path("bnetGetAllLegalDocuments")
@Consumes("application/json")
@Produces("application/json")
public LegalDocumentsResponse getAllLegalDocuments(final GetAllLegalDocumentsRequest request) {
logger.info("GetAllLegalDocuments called : " + request);
return null;
}
}

View File

@@ -0,0 +1,144 @@
package ch.gtache.elderscrollslegends.service.account;
import ch.gtache.elderscrollslegends.service.SteamService;
import ch.gtache.elderscrollslegends.service.Token;
import ch.gtache.elderscrollslegends.service.account.auth.AuthData;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.time.Duration;
import java.util.List;
import static java.util.Objects.requireNonNull;
@ApplicationScoped
public class AccountService {
private static final Logger logger = Logger.getLogger(AccountService.class);
private final SteamService steamService;
private final DataSource dataSource;
@Inject
AccountService(final SteamService steamService, final DataSource dataSource) {
this.steamService = requireNonNull(steamService);
this.dataSource = requireNonNull(dataSource);
}
public AuthData authenticate(final String steamID) {
if (!exists(steamID)) {
final var longId = Long.parseLong(steamID);
final var name = steamService.getName(steamID);
try (final var connection = dataSource.getConnection();
final var statement = connection.prepareStatement("INSERT INTO player (steam_id, name) VALUES (?, ?)")) {
statement.setLong(1, longId);
statement.setString(2, name);
statement.executeUpdate();
} catch (final SQLException e) {
logger.error("Error inserting player " + steamID, e);
return null;
}
}
updateNameIfNeeded(steamID);
final var token = getOrCreateToken(steamID);
return getAuthData(steamID, token);
}
private void updateNameIfNeeded(final String steamID) {
final var longId = Long.parseLong(steamID);
final var name = steamService.getName(steamID);
try (final var connection = dataSource.getConnection();
final var statement = connection.prepareStatement("UPDATE player SET name=? WHERE steam_id=?")) {
statement.setString(1, name);
statement.setLong(2, longId);
statement.executeUpdate();
} catch (final SQLException e) {
logger.error("Error updating player " + steamID, e);
}
}
private Token getOrCreateToken(final String steamID) {
final var longId = Long.parseLong(steamID);
try (final var connection = dataSource.getConnection();
final var statement = connection.prepareStatement("SELECT token, expiration FROM token WHERE player_id=(SELECT id FROM player WHERE steam_id=?)")) {
statement.setLong(1, longId);
try (final var rs = statement.executeQuery()) {
if (rs.next()) {
final var token = rs.getString(1);
final var expiration = rs.getTimestamp(2).toInstant();
if (expiration.isAfter(java.time.Instant.now())) {
return new Token(token, expiration);
}
}
}
} catch (final SQLException e) {
logger.error("Error checking for player " + steamID, e);
}
try (final var connection = dataSource.getConnection();
final var statement = connection.prepareStatement("INSERT INTO token (player_id) VALUES ((SELECT id FROM player WHERE steam_id=?)) RETURNING token, expiration")) {
statement.setLong(1, longId);
try (final var rs = statement.executeQuery()) {
return rs.next() ? new Token(rs.getString(1), rs.getTimestamp(2).toInstant()) : null;
}
} catch (final SQLException e) {
logger.error("Error inserting player " + steamID, e);
}
return null;
}
private AuthData getAuthData(final String steamID, final Token token) {
if (token != null) {
final var longId = Long.parseLong(steamID);
try (final var connection = dataSource.getConnection();
final var statement = connection.prepareStatement("SELECT 1 FROM player WHERE steam_id=?")) {
statement.setLong(1, longId);
try (final var rs = statement.executeQuery()) {
if (rs.next()) {
final var uuid = token.token();
final var timeToRefresh = Duration.between(java.time.Instant.now(), token.expirationTimestamp()).getSeconds();
return new AuthData(uuid, "", "", "", "", steamID, steamID, steamID,
"", steamID, "CH", false, false, (int) timeToRefresh,
5, 5, false, "", "",
0, List.of(), false);
}
}
} catch (final SQLException e) {
logger.error("Error checking for player " + steamID, e);
}
}
return null;
}
public boolean exists(final String steamID) {
final var longId = Long.parseLong(steamID);
try (final var connection = dataSource.getConnection();
final var statement = connection.prepareStatement("SELECT 1 FROM player WHERE steam_id=?")) {
statement.setLong(1, longId);
try (final var rs = statement.executeQuery()) {
return rs.next();
}
} catch (final SQLException e) {
logger.error("Error checking for player " + steamID, e);
}
return false;
}
public Token refresh(final String steamID) {
if (exists(steamID)) {
final var longId = Long.parseLong(steamID);
try (final var connection = dataSource.getConnection();
final var statement = connection.prepareStatement("DELETE FROM token WHERE player_id=(SELECT id FROM player WHERE steam_id=?)")) {
statement.setLong(1, longId);
statement.executeUpdate();
} catch (final SQLException e) {
logger.error("Error checking for player " + steamID, e);
}
return getOrCreateToken(steamID);
} else {
return null;
}
}
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account;
public record DeviceIdMapRequest(String deviceId, String fingerprint) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account;
public record GetAllLegalDocumentsRequest(String platform, String country, String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account;
public record GetLegalDocumentsForUserRequest(String platform, String fingerprint, String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account;
public record RefreshSessionRequest(String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account;
public record RefreshSessionResponse(int timeToRefresh, String sessionToken) {
}

View File

@@ -0,0 +1,33 @@
package ch.gtache.elderscrollslegends.service.account;
import java.util.List;
record UpgradeAccountRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String platformName,
String loginPlatform,
String bnetKeyPlatform,
String username,
String emailAddress,
String password,
String passwordConfirmation,
boolean newsOffersOptIn,
String country,
String language,
int secret1Question,
String secret1Answer,
List<Integer> legalDocumentIds) {
}

View File

@@ -0,0 +1,20 @@
package ch.gtache.elderscrollslegends.service.account.auth;
public record AuthBNETDeviceIdRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
boolean createAccount, String language, String loginPlatform,
String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,20 @@
package ch.gtache.elderscrollslegends.service.account.auth;
public record AuthBNETGamecodeRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String gamecode, String loginPlatform,
String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,23 @@
package ch.gtache.elderscrollslegends.service.account.auth;
record AuthBNETGoogleAndroidRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String loginPlatform,
String bnetKeyPlatform,
boolean createAccount,
String language,
String serverAuthCode) {
}

View File

@@ -0,0 +1,19 @@
package ch.gtache.elderscrollslegends.service.account.auth;
public record AuthBNETLoginTokenRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String build, String loginPlatform, String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,20 @@
package ch.gtache.elderscrollslegends.service.account.auth;
public record AuthBNETSteamRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String steamId, String sessionTicket, boolean createAccount, String language,
String loginPlatform, String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,30 @@
package ch.gtache.elderscrollslegends.service.account.auth;
record AuthBNETiOSGameCenterRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String loginPlatform,
String bnetKeyPlatform,
boolean createAccount,
String language,
String bundleId,
String playerId,
String KeyUrl,
String signature,
String salt,
String teamPlayerId,
String gamePlayerId,
long timestamp) {
}

View File

@@ -0,0 +1,29 @@
package ch.gtache.elderscrollslegends.service.account.auth;
import ch.gtache.elderscrollslegends.service.account.ABTestingSet;
import java.util.List;
public record AuthData(String token,
String channel,
String sessionId,
String sessionType,
String sessionToken,
String buid,
String steamId,
String kpiId,
String deviceGrade,
String nickname,
String bnetCountry,
boolean isLimitedAccount,
boolean isAnonymousAccount,
int timeToRefresh,
int maxRefreshFailures,
float secondsBetweenRefreshFailures,
boolean allowTP,
String unityBundleUrl,
String unityBundleHash,
int buildSetId,
List<ABTestingSet> abTestingSets,
boolean wasNativeSignOn) {
}

View File

@@ -0,0 +1,19 @@
package ch.gtache.elderscrollslegends.service.account.auth;
record AuthDevRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String secretDevKey, String nickname, String accountId, String group) {
}

View File

@@ -0,0 +1,18 @@
package ch.gtache.elderscrollslegends.service.account.auth;
public record AuthRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform) {
}

View File

@@ -0,0 +1,6 @@
package ch.gtache.elderscrollslegends.service.account.auth;
import java.util.List;
public record AuthResult(AuthData data, int errorCode, String errorMessage, List<String> validChangelists) {
}

View File

@@ -0,0 +1,11 @@
package ch.gtache.elderscrollslegends.service.account.auth;
public enum AuthType {
Dev,
Dev_UsernamePassword,
Dev_DeviceId,
BNETSteam,
BNETGamecode,
BNETiOSGameCenter,
BNETGoogleAndroid,
}

View File

@@ -0,0 +1,20 @@
package ch.gtache.elderscrollslegends.service.account.auth;
public record AuthUsernameAndPasswordRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String username, String password,
String loginPlatform, String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account.auth;
public record LogoutSteamRequest(String steamId) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account.check;
public record CheckEmailRequest(String fingerprint, String email, String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account.check;
public record CheckEmailResponse(CheckEmailResponseBody body) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account.check;
public record CheckEmailResponseBody(boolean valid, int status_code) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account.check;
public record CheckUsernameRequest(String fingerprint, String username, String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account.check;
public record CheckUsernameResponse(CheckUsernameResponseBody body) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account.check;
public record CheckUsernameResponseBody(boolean valid, boolean exists, int status_code) {
}

View File

@@ -0,0 +1,20 @@
package ch.gtache.elderscrollslegends.service.account.link;
public record AndroidSessionLinkRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String loginPlatform, String language, String bnetKeyPlatform,
String serverAuthCode) {
}

View File

@@ -0,0 +1,22 @@
package ch.gtache.elderscrollslegends.service.account.link;
public record IOSSessionLinkRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String loginPlatform, String language, String bnetKeyPlatform,
String bundleId, String playerId, String publicKeyUrl,
String signature, String salt, String teamPlayerId,
String gamePlayerId, long timestamp) {
}

View File

@@ -0,0 +1,19 @@
package ch.gtache.elderscrollslegends.service.account.link;
public record SessionLinkBase(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String loginPlatform, String language, String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,20 @@
package ch.gtache.elderscrollslegends.service.account.link;
public record SteamSessionLinkRequest(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String loginPlatform, String language, String bnetKeyPlatform,
String steamId, String encryptedAppTicket) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.account.transfer;
public record LegalDocEntry(String doctype, String full_name, int id, String url) {
}

View File

@@ -0,0 +1,6 @@
package ch.gtache.elderscrollslegends.service.account.transfer;
import java.util.List;
public record LegalDocumentsResponse(List<LegalDocEntry> items) {
}

View File

@@ -0,0 +1,5 @@
package ch.gtache.elderscrollslegends.service.account.transfer;
record TransferRequest_Phase0(String legalDocsPlatform, String username, String password, String fingerprint,
String loginPlatform, String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,20 @@
package ch.gtache.elderscrollslegends.service.account.transfer;
record TransferRequest_Phase1(String channel,
String componentType,
String majorVersion,
String changelist,
String fingerprint,
String deviceId,
String os,
int dpi,
int resolutionX,
int resolutionY,
String deltaDNAId,
String appsFlyerId,
String osVersion,
String deviceName,
String platform,
String selectedUser, String username, String password,
String loginPlatform, String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,10 @@
package ch.gtache.elderscrollslegends.service.account.transfer;
import ch.gtache.elderscrollslegends.service.inventory.SelectedItem;
import ch.gtache.elderscrollslegends.service.profile.ProfileStruct;
import java.util.List;
record TransferResponse_Phase0(List<LegalDocEntry> items, String buid, String sessionToken, boolean hasTeslUserData,
ProfileStruct profile, List<SelectedItem> categories) {
}

View File

@@ -0,0 +1,8 @@
package ch.gtache.elderscrollslegends.service.account.transfer;
import ch.gtache.elderscrollslegends.service.account.auth.AuthData;
import java.util.List;
record TransferResponse_Phase1(AuthData data, int errorCode, String errorMessage, List<String> validChangelists) {
}

View File

@@ -0,0 +1,5 @@
package ch.gtache.elderscrollslegends.service.account.transfer;
record Transfer_AcceptLegalDocumentRequest(String fingerprint, String sessionToken, String legalDocumentId,
String bnetKeyPlatform) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.analytics;
public record AnalysticsEventPayload(AnalyticsEventType eventType, String data) {
}

View File

@@ -0,0 +1,38 @@
package ch.gtache.elderscrollslegends.service.analytics;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import org.jboss.logging.Logger;
@Path("/analytics")
public class AnalyticsEndpoints {
private static final Logger logger = Logger.getLogger(AnalyticsEndpoints.class);
@POST
@Path("/clientEvent")
public void newAnalytics(@HeaderParam("Authorization") final String authentication,
final AnalyticsEvent analyticsEvent) {
logger.info("Report analytics called by " + authentication + " : " + analyticsEvent);
//Do nothing
}
@POST
@Path("/clientEventPA")
public void newAnalyticsPA(@HeaderParam("Authorization") final String authentication,
final AnalyticsEvent analyticsEvent) {
logger.info("Report analyticsPA called by " + authentication + " : " + analyticsEvent);
//Do nothing
}
@GET
@Path("/reportingConfig")
@Produces("application/json")
public FetchResponse getReportingConfig(@HeaderParam("Authorization") final String authentication) {
logger.info("ReportingConfig called by " + authentication);
return null;
}
}

View File

@@ -0,0 +1,6 @@
package ch.gtache.elderscrollslegends.service.analytics;
import java.util.List;
public record AnalyticsEvent(int platformId, int clientVersion, String eventData, List<AnalysticsEventPayload> events) {
}

View File

@@ -0,0 +1,35 @@
package ch.gtache.elderscrollslegends.service.analytics;
public enum AnalyticsEventType {
None,
ConfigDownloaded,
AuthCompleted,
FirstTimeSignOnChoiceShown,
FirstTimeSignOnChoiceOption1,
FirstTimeSignOnChoiceOption2,
InitializeAssetCatalog,
AssetCatalogPreloadChoice,
AssetDownloadWarning,
AssetStartDownload,
AssetFinishDownload,
GameManagerSetup,
CheckForMatchRejoin,
InitializationStateComplete,
EulaShow,
EulaAgree,
EulaCancel,
AvatarPrompt,
AvatarChosen,
TutorialTextBoxShow,
TutorialTextBoxHide,
WindowEnable,
WindowDisable,
VideoStart,
VideoPause,
VideoUnpause,
VideoSkip,
VideoReplay,
VideoStop,
VideoPrepareTimeout,
Count,
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.analytics;
public record FetchResponse(boolean enableReporting) {
}

View File

@@ -0,0 +1,7 @@
package ch.gtache.elderscrollslegends.service.arena;
import java.util.List;
public record ArenaClientDataStruct(int costGold, int costTickets, List<ArenaClientInstance> instances) {
}

View File

@@ -0,0 +1,9 @@
package ch.gtache.elderscrollslegends.service.arena;
import java.util.List;
public record ArenaClientInstance(ArenaPhase phase, ArenaType arenaType, ArenaType arenaTypeEnum, boolean isCompleted,
boolean hasRewards, int selectedClassTypeHash, List<Integer> potentialClassTypeHashes,
List<Integer> cardSelectionTypeHashes, List<Integer> cardTypeHashes,
List<Boolean> premiums, List<ArenaClientMatch> matches) {
}

View File

@@ -0,0 +1,6 @@
package ch.gtache.elderscrollslegends.service.arena;
public record ArenaClientMatch(int orderIndex, int avatarTypeHash, int scenarioModifierTypeHash, int scenarioTypeHash,
int laneTypeHash1, int laneTypeHash2, int featuredMatchTypeHash, int deckTypeHash,
int losses, int wins, boolean completed, boolean canSelect) {
}

View File

@@ -0,0 +1,57 @@
package ch.gtache.elderscrollslegends.service.arena;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
@Path("/arena")
public class ArenaEndpoints {
@Path("purchaseArena")
@POST
@Consumes("application/json")
@Produces("application/json")
public FetchArenaInstancesResult purchaseArena(@HeaderParam("Authorization") final String authentication,
final PurchaseArenaRequest request) {
return null;
}
@Path("resignArena")
@POST
@Consumes("application/json")
@Produces("application/json")
public ResignArenaResult resignArena(@HeaderParam("Authorization") final String authentication,
final ResignArenaRequest request) {
return null;
}
@Path("selectCard")
@POST
@Consumes("application/json")
@Produces("application/json")
public SelectCardResult selectCard(@HeaderParam("Authorization") final String authentication,
final SelectCardRequest request) {
return null;
}
@Path("selectClassType")
@POST
@Consumes("application/json")
@Produces("application/json")
public SelectClassResult selectClassType(@HeaderParam("Authorization") final String authentication,
final SelectClassRequest request) {
return null;
}
@Path("fetchActiveArenaInstances")
@GET
@Consumes("application/json")
@Produces("application/json")
public FetchArenaInstancesResult fetchActiveArenaInstances() {
return null;
}
}

View File

@@ -0,0 +1,7 @@
package ch.gtache.elderscrollslegends.service.arena;
public enum ArenaPhase {
ClassSelection,
CardSelection,
MatchSelection,
}

View File

@@ -0,0 +1,6 @@
package ch.gtache.elderscrollslegends.service.arena;
public enum ArenaPurchaseCurrencyType {
Gold,
Tickets,
}

View File

@@ -0,0 +1,7 @@
package ch.gtache.elderscrollslegends.service.arena;
public enum ArenaType {
Unknown,
Solo,
Versus,
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.arena;
public record FetchArenaInstancesResult(ArenaClientDataStruct clientData) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.arena;
public record PurchaseArenaRequest(ArenaType arenaType, ArenaPurchaseCurrencyType currencyType) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.arena;
public record PurchaseArenaResult(ArenaClientDataStruct clientData) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.arena;
public record ResignArenaRequest(ArenaType arenaType) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.arena;
public record ResignArenaResult() {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.arena;
public record SelectCardRequest(ArenaType arenaType, int cardTypeHash) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.arena;
public record SelectCardResult(ArenaClientDataStruct clientData) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.arena;
public record SelectClassRequest(ArenaType arenaType, int classTypeHash) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.arena;
public record SelectClassResult(ArenaClientDataStruct clientData) {
}

View File

@@ -0,0 +1,76 @@
package ch.gtache.elderscrollslegends.service.campaign;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import org.jboss.logging.Logger;
@Path("/campaign")
public class CampaignEndpoints {
private static final Logger logger = Logger.getLogger(CampaignEndpoints.class);
@POST
@Path("checkCampaignProgress")
@Consumes("application/json")
public void checkCampaignProgress(@HeaderParam("Authorization") final String authentication,
final CheckCampaignRequest request) {
logger.info("CheckCampaignProgress called by " + authentication + " : " + request);
//TODO
}
@POST
@Path("debugAddNextChapter")
@Consumes("application/json")
@Produces("application/json")
public void debugAddNextChapter(@HeaderParam("Authorization") final String authentication,
final DebugAddNextChapterRequest request) {
logger.info("DebugAddNextChapter called by " + authentication + " : " + request);
//Do nothing
}
@POST
@Path("debugAddNextEvent")
@Consumes("application/json")
@Produces("application/json")
public void debugAddNextEvent(@HeaderParam("Authorization") final String authentication,
final DebugAddNextEventRequest request) {
logger.info("DebugAddNextEvent called by " + authentication + " : " + request);
//Do nothing
}
@POST
@Path("setChapterDialogStatus")
@Consumes("application/json")
@Produces("application/json")
public SetChapterDialogResult setChapterDialogStatus(@HeaderParam("Authorization") final String authentication,
final SetChapterDialogStatusRequest request) {
logger.info("SetChapterDialogStatus called by " + authentication + " : " + request);
//TODO
return null;
}
@POST
@Path("setChapterEventChoice")
@Consumes("application/json")
@Produces("application/json")
public SetChapterEventResult setChapterEventChoice(@HeaderParam("Authorization") final String authentication,
final SetChapterEventChoiceRequest request) {
logger.info("SetChapterEventChoice called by " + authentication + " : " + request);
//TODO
return null;
}
@GET
@Path("list")
@Produces("application/json")
public ListCampaignsResponse getList(@HeaderParam("Authorization") final String authentication) {
logger.info("List called by " + authentication);
//TODO
return null;
}
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.campaign;
public record CheckCampaignRequest(int campaignId, boolean isMastery) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.campaign;
public record DebugAddNextChapterRequest(int campaignId, int actId, boolean isMastery) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.campaign;
public record DebugAddNextEventRequest(int campaignId, int actId, int chapterId, boolean isMastery) {
}

View File

@@ -0,0 +1,7 @@
package ch.gtache.elderscrollslegends.service.campaign;
public enum DialogModalType {
None,
Intro,
Ending,
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.campaign;
public record ListCampaignsResponse(UserCampaignData campaignDatas) {
}

View File

@@ -0,0 +1,8 @@
package ch.gtache.elderscrollslegends.service.campaign;
import ch.gtache.elderscrollslegends.service.reward.RewardDescription;
import java.util.List;
public record SetChapterDialogResult(List<RewardDescription> rewards) {
}

View File

@@ -0,0 +1,5 @@
package ch.gtache.elderscrollslegends.service.campaign;
public record SetChapterDialogStatusRequest(int campaignId, int actId, int chapterId, int cinematicId,
boolean isMastery, DialogModalType modalType, boolean seen) {
}

View File

@@ -0,0 +1,5 @@
package ch.gtache.elderscrollslegends.service.campaign;
public record SetChapterEventChoiceRequest(int campaignId, int actId, int chapterId, int cinematicId,
boolean isMastery, DialogModalType modalType, UserCampaignChoice choiceType) {
}

View File

@@ -0,0 +1,8 @@
package ch.gtache.elderscrollslegends.service.campaign;
import ch.gtache.elderscrollslegends.service.reward.RewardDescription;
import java.util.List;
public record SetChapterEventResult(List<RewardDescription> rewards) {
}

View File

@@ -0,0 +1,6 @@
package ch.gtache.elderscrollslegends.service.campaign;
import java.util.List;
public record UserActData(int actId, boolean isMastery, List<UserChapterData> chapterData) {
}

View File

@@ -0,0 +1,8 @@
package ch.gtache.elderscrollslegends.service.campaign;
public enum UserCampaignChoice {
None,
First,
Second,
Third,
}

View File

@@ -0,0 +1,7 @@
package ch.gtache.elderscrollslegends.service.campaign;
import java.util.List;
public record UserCampaignData(int campaignId, boolean isActive, int lastPlayedActIndex, int lastPlayedChapterIndex,
int lastPlayedChapterEventINdex, List<UserActData> actData, List<Integer> ownedActs) {
}

View File

@@ -0,0 +1,9 @@
package ch.gtache.elderscrollslegends.service.campaign;
import java.util.List;
public record UserChapterData(int chapterId, boolean isComplete, boolean hasIntroBeenShown,
boolean hasEndingBeenShown, List<UserChapterEventData> chapterEventData,
UserCampaignChoice introChoice, UserCampaignChoice endingChoice,
List<Integer> chapterSeenCinematicTypeHashes) {
}

View File

@@ -0,0 +1,6 @@
package ch.gtache.elderscrollslegends.service.campaign;
public record UserChapterEventData(int chapterEventId, int chapterId, boolean isComplete,
UserCampaignChoice introChoice,
UserCampaignChoice endingChoice) {
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.campaign;
public record UserDialogModalData(DialogModalType modalType, int choiceIndex) {
}

View File

@@ -0,0 +1,18 @@
package ch.gtache.elderscrollslegends.service.chat;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
@Path("/chat")
public class ChatEndpoints {
@Path("sendChatMessage")
@POST
@Consumes("application/json")
public void sendChatMessage(@HeaderParam("Authorization") final String authentication,
final OutgoingMessage message) {
//Do nothing
}
}

View File

@@ -0,0 +1,4 @@
package ch.gtache.elderscrollslegends.service.chat;
public record OutgoingMessage(String toBuid, String message) {
}

View File

@@ -0,0 +1,24 @@
package ch.gtache.elderscrollslegends.service.config;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.Cache;
import java.io.InputStream;
@Path("config.json")
public class ConfigResource {
private static final Logger logger = Logger.getLogger(ConfigResource.class);
@GET
@Produces("application/json")
@Cache
public InputStream getConfiguration() {
logger.info("Config called");
return ConfigResource.class.getResourceAsStream("config.json");
}
}

View File

@@ -0,0 +1,38 @@
package ch.gtache.elderscrollslegends.service.crafting;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
@Path("/crafting")
public class CraftingEndpoints {
@Path("soulTrapExtras")
@POST
@Consumes("application/json")
@Produces("application/json")
public SoulTrapExtrasResponse soulTrapExtras(@HeaderParam("Authorization") final String authentication,
final SoulTrapExtrasRequest request) {
return null;
}
@Path("sell")
@POST
@Consumes("application/json")
@Produces("application/json")
public CraftingResponse sell(@HeaderParam("Authorization") final String authentication,
final CraftingRequest request) {
return null;
}
@Path("purchase")
@POST
@Consumes("application/json")
@Produces("application/json")
public CraftingResponse purchase(@HeaderParam("Authorization") final String authentication,
final CraftingRequest request) {
return null;
}
}

Some files were not shown because too many files have changed in this diff Show More