Tyr Backbone Creation

# Changes:

## Patchwork
- Renamed FreedomExecutor to ExecutorProvider and moved the class to the provider package.
- Created an SQL Registry to prevent dependencies on Datura for SQL data. SQL is returned through an Optional, in the event that there is no SQL service registered.
- Created SQLResult, a generic ORM for ResultSets to avoid working directly with SQL data.

## Tyr
- Created Identity, which houses a username and related secret key.
- Created SQLEntry which stores the information from the Identity class into an SQL table called sessionData.
- Created TOTP, a simple static class that allows easy access to TimeBasedOneTimePasswordUtils class.
- Created OAuth2 which houses identities and performs the appropriate credential validations (incomplete)
This commit is contained in:
Paul Reilly
2023-09-09 18:57:15 -05:00
parent 85cc1f7ae0
commit 33731b611f
20 changed files with 889 additions and 172 deletions

View File

@ -32,7 +32,7 @@ import fns.datura.punishment.Locker;
import fns.datura.sql.MySQL;
import fns.patchwork.base.Registration;
import fns.patchwork.command.CommandHandler;
import fns.patchwork.service.SubscriptionProvider;
import fns.patchwork.provider.SubscriptionProvider;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;

View File

@ -26,11 +26,11 @@ package fns.datura.sql;
import fns.patchwork.base.Patchwork;
import fns.patchwork.base.Shortcuts;
import fns.patchwork.sql.SQL;
import fns.patchwork.sql.SQLResult;
import fns.patchwork.utils.container.Identity;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
@ -74,7 +74,7 @@ public class MySQL implements SQL
.append(password);
}
public CompletableFuture<ResultSet> getRow(final String table, final String column, final Identity identity)
public CompletableFuture<SQLResult> getRow(final String table, final String column, final Identity identity)
{
return executeQuery("SELECT * FROM ? WHERE ? = ?", table, column, identity.getId());
}
@ -83,99 +83,104 @@ public class MySQL implements SQL
public CompletableFuture<PreparedStatement> prepareStatement(final String query, final Object... args)
{
return getConnection()
.thenApplyAsync(connection ->
{
try
{
final PreparedStatement statement = connection.prepareStatement(query);
for (int i = 0; i < args.length; i++)
{
statement.setObject(i + 1, args[i]);
}
return statement;
} catch (SQLException ex)
{
throw new CompletionException("Failed to prepare statement: "
+ query + "\n", ex);
}
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
.thenApplyAsync(connection ->
{
try
{
final PreparedStatement statement = connection.prepareStatement(query);
for (int i = 0; i < args.length; i++)
{
statement.setObject(i + 1, args[i]);
}
return statement;
}
catch (SQLException ex)
{
throw new CompletionException("Failed to prepare statement: "
+ query + "\n", ex);
}
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
}
private CompletableFuture<Connection> getConnection()
{
return CompletableFuture.supplyAsync(() ->
{
try
{
return DriverManager.getConnection(url.toString());
} catch (SQLException ex)
{
throw new CompletionException("Failed to connect to the database: "
+ url.toString() + "\n", ex);
}
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
{
try
{
return DriverManager.getConnection(url.toString());
}
catch (SQLException ex)
{
throw new CompletionException("Failed to connect to the database: "
+ url.toString() + "\n", ex);
}
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
}
@Override
public CompletableFuture<ResultSet> executeQuery(final String query, final Object... args)
public CompletableFuture<SQLResult> executeQuery(final String query, final Object... args)
{
return prepareStatement(query, args)
.thenApplyAsync(statement ->
{
try
{
return statement.executeQuery();
} catch (SQLException ex)
{
throw new CompletionException(
"Failed to retrieve a result set from query: "
.thenApplyAsync(statement ->
{
try
{
return new SQLResult(statement.executeQuery());
}
catch (SQLException ex)
{
throw new CompletionException(
"Failed to retrieve a result set from query: "
+ query + "\n", ex);
}
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
}
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
}
@Override
public CompletableFuture<Integer> executeUpdate(final String query, final Object... args)
{
return prepareStatement(query, args)
.thenApplyAsync(statement ->
{
try
{
return statement.executeUpdate();
} catch (SQLException ex)
{
throw new CompletionException("Failed to execute update: "
+ query + "\n", ex);
}
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
.thenApplyAsync(statement ->
{
try
{
return statement.executeUpdate();
}
catch (SQLException ex)
{
throw new CompletionException("Failed to execute update: "
+ query + "\n", ex);
}
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
}
@Override
public CompletableFuture<Boolean> execute(final String query, final Object... args)
{
return prepareStatement(query, args)
.thenApplyAsync(statement ->
{
try
{
return statement.execute();
} catch (SQLException ex)
{
throw new CompletionException("Failed to execute statement: "
+ query + "\n", ex);
}
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
.thenApplyAsync(statement ->
{
try
{
return statement.execute();
}
catch (SQLException ex)
{
throw new CompletionException("Failed to execute statement: "
+ query + "\n", ex);
}
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
}
@Override
@ -201,42 +206,27 @@ public class MySQL implements SQL
final Identity identity, final Class<T> type)
{
return executeQuery("SELECT ? FROM ? WHERE ? = ?", column, table, key, identity.getId())
.thenApplyAsync(resultSet ->
{
try
{
if (resultSet.next())
{
return resultSet.getObject(column, type);
}
} catch (SQLException ex)
{
throw new CompletionException(
"Failed to retrieve column: " + column + " from table: " + table + " " +
"where primary key: " + key + " is equal to: " + identity.getId() + "\n",
ex);
}
return null;
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
.thenApplyAsync(resultSet -> (resultSet.hasNext()) ? resultSet.autoCast(1, column, type) : null,
Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
}
public CompletableFuture<Boolean> updateColumn(final String table, final String column, final Object value,
final String key, final Identity identity)
{
return executeUpdate("UPDATE ? SET ? = ? WHERE ? = ?", table, column, value, key, identity.getId())
.thenApplyAsync(result -> result > 0, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
.thenApplyAsync(result -> result > 0, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
}
public CompletableFuture<Boolean> deleteRow(final String table, final String key, final Identity identity)
{
return executeUpdate("DELETE FROM ? WHERE ? = ?", table, key, identity.getId())
.thenApplyAsync(result -> result > 0, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
.thenApplyAsync(result -> result > 0, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync());
}
public CompletableFuture<Boolean> insertRow(final String table, final Object... values)

View File

@ -34,10 +34,8 @@ import fns.patchwork.sql.SQL;
import fns.patchwork.user.User;
import fns.patchwork.user.UserData;
import fns.patchwork.utils.logging.FNS4J;
import java.sql.SQLException;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@ -69,14 +67,14 @@ public class SimpleUserData implements UserData
}
private SimpleUserData(
final UUID uuid,
final String username,
final User user,
final Group group,
final long playtime,
final boolean canInteract,
final long balance,
final boolean transactionsFrozen)
final UUID uuid,
final String username,
final User user,
final Group group,
final long playtime,
final boolean canInteract,
final long balance,
final boolean transactionsFrozen)
{
this.uuid = uuid;
this.username = username;
@ -93,56 +91,53 @@ public class SimpleUserData implements UserData
{
return sql.executeQuery("SELECT * FROM users WHERE UUID = ?", uuid)
.thenApplyAsync(result ->
{
try
{
if (result.next())
{
final String g = result.getString("group");
{
final UUID u = UUID.fromString(uuid);
final String username = result.getString("username");
if (result.hasNext())
{
final String g = result.getString("group");
final Player player = Bukkit.getPlayer(u);
final UUID u = UUID.fromString(uuid);
final String username = result.getString("username");
if (player == null)
throw new IllegalStateException("Player should be online but they are not!");
final Player player = Bukkit.getPlayer(u);
final User user = new FreedomUser(player);
final Group group = Registration
.getGroupRegistry()
.getGroup(g);
if (player == null)
throw new IllegalStateException(
"Player should be online but they are not!");
final long playtime = result.getLong("playtime");
final boolean canInteract = result.getBoolean("canInteract");
final long balance = result.getLong("balance");
final boolean transactionsFrozen = result.getBoolean("transactionsFrozen");
final User user = new FreedomUser(player);
final Group group = Registration
.getGroupRegistry()
.getGroup(g);
return new SimpleUserData(u, username, user, group, playtime,
canInteract, balance, transactionsFrozen);
}
} catch (SQLException ex)
{
final String sb = "An error occurred while trying to retrieve user data for" +
" UUID " +
uuid +
" from the database." +
"\nCaused by: " +
ExceptionUtils.getRootCauseMessage(ex) +
"\nStack trace: " +
ExceptionUtils.getStackTrace(ex);
final long playtime = result.getLong("playtime");
final boolean canInteract = result.getBoolean("canInteract");
final long balance = result.getLong("balance");
final boolean transactionsFrozen = result.getBoolean("transactionsFrozen");
FNS4J.getLogger("Datura")
.error(sb);
}
return new SimpleUserData(u, username, user, group, playtime,
canInteract, balance, transactionsFrozen);
}
else
{
final String sb = "An error occurred while trying to retrieve user data for" +
" UUID " +
uuid +
" from the database.";
final Player player = Bukkit.getPlayer(UUID.fromString(uuid));
if (player == null) throw new IllegalStateException("Player should be online but they are not!");
FNS4J.getLogger("Datura")
.error(sb);
}
return new SimpleUserData(player);
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync())
final Player player = Bukkit.getPlayer(UUID.fromString(uuid));
if (player == null)
throw new IllegalStateException("Player should be online but they are not!");
return new SimpleUserData(player);
}, Shortcuts.provideModule(Patchwork.class)
.getExecutor()
.getAsync())
.join();
}