From 0d0fbf2c0499986654d85ae3956fe12cf3a7a590 Mon Sep 17 00:00:00 2001 From: Paul Reilly Date: Fri, 31 Mar 2023 17:21:19 -0500 Subject: [PATCH] Implement sql properly --- .../totalfreedommod/admin/AdminList.java | 69 +- .../totalfreedommod/banning/BanManager.java | 58 +- .../command/Command_mbconfig.java | 47 +- .../totalfreedommod/player/PlayerList.java | 102 ++- .../sql/ResultSetProvider.java | 33 +- .../totalfreedommod/sql/SQLite.java | 693 +++++++++++------- 6 files changed, 655 insertions(+), 347 deletions(-) diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/admin/AdminList.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/admin/AdminList.java index c9ef00c9..a01e6ab0 100644 --- a/commons/src/main/java/me/totalfreedom/totalfreedommod/admin/AdminList.java +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/admin/AdminList.java @@ -13,14 +13,15 @@ import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import java.sql.SQLException; import java.util.*; +import java.util.concurrent.CompletionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class AdminList extends FreedomService { public static final List vanished = new ArrayList<>(); + public static final String SQL_SAVE_FAILED = "Failed to save admin: "; private final Set allAdmins = Sets.newHashSet(); // Includes disabled admins // Only active admins below private final Set activeAdmins = Sets.newHashSet(); @@ -44,11 +45,11 @@ public class AdminList extends FreedomService public void load() { allAdmins.clear(); - try + plugin.sql.getAdminList().thenAcceptAsync(provider -> { - ResultSetProvider adminList = plugin.sql.getAdminList(); AtomicInteger row = new AtomicInteger(1); - adminList.getAllRowsResultSet().forEach(adminSet -> { + provider.getAllRowsResultSet().forEach(adminSet -> + { try { tryAddAdmin(ResultSetProvider.fromRow(adminSet)); @@ -56,22 +57,25 @@ public class AdminList extends FreedomService } catch (Throwable e) { FLog.warning("An error occurred whilst reading the admin entry at row #" + row.get()); - FLog.warning(e); + throw new CompletionException(e); // handle downstream. } }); - } catch (SQLException e) + }).whenComplete((result, throwable) -> { - FLog.severe("Failed to load admin list: " + e.getMessage()); - } - - updateTables(); - FLog.info("Loaded " + allAdmins.size() + " admins (" + uuidTable.size() + " active, " + ipTable.size() + " IPs)"); + if (throwable != null) + { + FLog.severe(throwable.getMessage()); + return; + } + updateTables(); + FLog.info("Loaded " + allAdmins.size() + " admins (" + uuidTable.size() + " active, " + ipTable.size() + " IPs)"); + }); } private void tryAddAdmin(ResultSetProvider adminSet) { - Admin admin = new Admin(adminSet); - allAdmins.add(admin); + Admin admin = new Admin(adminSet); + allAdmins.add(admin); } public void messageAllAdmins(Component message) @@ -200,7 +204,13 @@ public class AdminList extends FreedomService updateTables(); // Save admin - plugin.sql.addAdmin(admin); + plugin.sql.addAdmin(admin).whenComplete((result, exception) -> + { + if (exception != null) + { + FLog.warning(SQL_SAVE_FAILED + admin.getName() + " to the database.\n" + exception.getMessage()); + } + }); } public boolean removeAdmin(Admin admin) @@ -218,7 +228,13 @@ public class AdminList extends FreedomService updateTables(); // Unsave admin - plugin.sql.removeAdmin(admin); + plugin.sql.removeAdmin(admin).whenComplete((result, exception) -> + { + if (exception != null) + { + FLog.warning("Failed to remove admin: " + admin.getName() + " from the database.\n" + exception.getMessage()); + } + }); return true; } @@ -263,21 +279,30 @@ public class AdminList extends FreedomService public void save(Admin admin) { - try + plugin.sql.getAdminByUuid(admin.getUuid()).thenApplyAsync(result -> { - ResultSetProvider currentSave = plugin.sql.getAdminByUuid(admin.getUuid()); for (Map.Entry entry : admin.toSQLStorable().entrySet()) { - Object storedValue = plugin.sql.getValue(currentSave, entry.getKey(), entry.getValue()); + Object storedValue = plugin.sql.getValue(result, entry.getKey(), entry.getValue()); if (storedValue != null && !storedValue.equals(entry.getValue()) || storedValue == null && entry.getValue() != null || entry.getValue() == null) { - plugin.sql.setAdminValue(admin, entry.getKey(), entry.getValue()); + plugin.sql.setAdminValue(admin, entry.getKey(), entry.getValue()).whenComplete((result2, exception) -> + { + if (exception != null) + { + throw new CompletionException(exception); // We want to handle downstream in #whenComplete() + } + }); } } - } catch (SQLException e) + return null; + }).whenComplete((result, exception) -> { - FLog.severe("Failed to save admin: " + e.getMessage()); - } + if (exception != null) + { + FLog.severe(SQL_SAVE_FAILED + exception.getMessage()); + } + }); } public void deactivateOldEntries(boolean verbose) diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/banning/BanManager.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/banning/BanManager.java index b261a2e5..96c8c81e 100644 --- a/commons/src/main/java/me/totalfreedom/totalfreedommod/banning/BanManager.java +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/banning/BanManager.java @@ -12,7 +12,6 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerLoginEvent; -import java.sql.SQLException; import java.util.*; public class BanManager extends FreedomService @@ -28,9 +27,17 @@ public class BanManager extends FreedomService public void onStart() { bans.clear(); - try + + plugin.sql.getBanList().whenComplete((result, throwable) -> { - plugin.sql.getBanList().getAllRowsResultSet().forEach(row -> { + if (throwable != null) + { + FLog.severe("Failed to load ban list: " + throwable.getMessage()); + return; + } + + result.getAllRowsResultSet().forEach(row -> + { ResultSetProvider banSet = ResultSetProvider.fromRow(row); String name = banSet.getString("name"); UUID uuid = null; @@ -47,10 +54,7 @@ public class BanManager extends FreedomService Ban ban = new Ban(name, uuid, ips, by, at, expires, reason); bans.add(ban); }); - } catch (SQLException e) - { - FLog.severe("Failed to load ban list: " + e.getMessage()); - } + }); // Remove expired bans, repopulate ipBans and nameBans, updateViews(); @@ -191,8 +195,16 @@ public class BanManager extends FreedomService if (bans.add(ban)) { - plugin.sql.addBan(ban); - updateViews(); + plugin.sql.addBan(ban).whenComplete((result, ex) -> + { + if (ex != null) + { + FLog.severe(ex.getMessage()); + return; + } + + updateViews(); + }); } } @@ -201,8 +213,16 @@ public class BanManager extends FreedomService { if (bans.remove(ban)) { - plugin.sql.removeBan(ban); - updateViews(); + plugin.sql.removeBan(ban).whenComplete((result, ex) -> + { + if (ex != null) + { + FLog.severe(ex.getMessage()); + return; + } + + updateViews(); + }); } } @@ -212,7 +232,13 @@ public class BanManager extends FreedomService int size = bans.size(); bans.clear(); updateViews(); - plugin.sql.truncate("bans"); + plugin.sql.truncate("bans").whenComplete((result, ex) -> + { + if (ex != null) + { + FLog.severe(ex.getMessage()); + } + }); return size; } @@ -274,7 +300,13 @@ public class BanManager extends FreedomService if (ban.isExpired()) { bans.remove(ban); - plugin.sql.removeBan(ban); + plugin.sql.removeBan(ban).whenComplete((result, ex) -> + { + if (ex != null) + { + FLog.severe(ex.getMessage()); + } + }); } } diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/command/Command_mbconfig.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/command/Command_mbconfig.java index 455c339f..b0fb71d6 100644 --- a/commons/src/main/java/me/totalfreedom/totalfreedommod/command/Command_mbconfig.java +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/command/Command_mbconfig.java @@ -1,6 +1,7 @@ package me.totalfreedom.totalfreedommod.command; import me.totalfreedom.totalfreedommod.player.PlayerData; +import me.totalfreedom.totalfreedommod.util.FLog; import me.totalfreedom.totalfreedommod.util.FUtil; import org.apache.commons.lang.StringUtils; import org.bukkit.ChatColor; @@ -26,13 +27,12 @@ public class Command_mbconfig extends FreedomCommand switch (args[0]) { - case "list": + case "list" -> { msg("Master Builders: " + StringUtils.join(plugin.pl.getMasterBuilderNames(), ", "), ChatColor.GOLD); return true; } - - case "clearips": + case "clearips" -> { if (args.length > 1) { @@ -55,13 +55,23 @@ public class Command_mbconfig extends FreedomCommand int counter = data.getIps().size() - 1; data.clearIps(); data.addIp(FUtil.getIp(playerSender)); - plugin.sql.addPlayer(data); - msg(counter + " IPs removed."); - msg(data.getIps().get(0) + " is now your only IP address"); - FUtil.adminAction(sender.getName(), "Clearing my IPs", true); + plugin.sql.addPlayer(data).whenComplete((result, ex) -> + { + if (ex != null) + { + FLog.severe(ex.getMessage()); + msgNew("Failed to clear IPs!"); + return; + } + + msg(counter + " IPs removed."); + msg(data.getIps().get(0) + " is now your only IP address"); + FUtil.adminAction(sender.getName(), "Clearing my IPs", true); + }); + return true; } - case "clearip": + case "clearip" -> { if (args.length < 2) { @@ -89,12 +99,21 @@ public class Command_mbconfig extends FreedomCommand return true; } data.removeIp(args[1]); - plugin.sql.addPlayer(data); - msg("Removed IP " + args[1]); - msg("Current IPs: " + StringUtils.join(data.getIps(), ", ")); + plugin.sql.addPlayer(data).whenComplete((result, ex) -> + { + if (ex != null) + { + FLog.severe(ex.getMessage()); + msgNew("Failed to remove IP!"); + return; + } + + msg("Removed IP " + args[1]); + msg("Current IPs: " + StringUtils.join(data.getIps(), ", ")); + }); return true; } - case "add": + case "add" -> { if (args.length < 2) { @@ -131,7 +150,7 @@ public class Command_mbconfig extends FreedomCommand } return true; } - case "remove": + case "remove" -> { if (args.length < 2) { @@ -161,7 +180,7 @@ public class Command_mbconfig extends FreedomCommand } return true; } - default: + default -> { return false; } diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/player/PlayerList.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/player/PlayerList.java index ea9b8d31..3170b6dc 100644 --- a/commons/src/main/java/me/totalfreedom/totalfreedommod/player/PlayerList.java +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/player/PlayerList.java @@ -8,12 +8,14 @@ import me.totalfreedom.totalfreedommod.rank.GroupProvider; import me.totalfreedom.totalfreedommod.sql.ResultSetProvider; import me.totalfreedom.totalfreedommod.util.FLog; import me.totalfreedom.totalfreedommod.util.FUtil; +import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; -import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; public class PlayerList extends FreedomService { @@ -43,16 +45,17 @@ public class PlayerList extends FreedomService public void loadMasterBuilders() { - ResultSetProvider resultSet = plugin.sql.getMasterBuilders(); + plugin.sql.getMasterBuilders().whenComplete((result, throwable) -> { + if (throwable != null) { + FLog.severe("Failed to load master builders: " + throwable.getMessage()); + return; + } - if (resultSet == null) - { - return; - } - - resultSet.getAllRowsResultSet().forEach(row -> { - PlayerData playerData = load(ResultSetProvider.fromRow(row)); - dataMap.put(playerData.getUuid(), playerData); + result.getAllRowsResultSet().forEach(row -> + { + PlayerData playerData = load(ResultSetProvider.fromRow(row)); + dataMap.put(playerData.getUuid(), playerData); + }); }); } @@ -85,10 +88,7 @@ public class PlayerList extends FreedomService { PlayerData data = getData(name); - return (!ConfigEntry.HOST_SENDER_NAMES.getStringList().contains(name.toLowerCase()) && data != null && !ConfigEntry.SERVER_OWNERS.getStringList().contains(data.getName())) - && !ConfigEntry.SERVER_EXECUTIVES.getStringList().contains(data.getName()) - && !isTelnetMasterBuilder(data) - && !ConfigEntry.HOST_SENDER_NAMES.getStringList().contains(name.toLowerCase()); + return (!ConfigEntry.HOST_SENDER_NAMES.getStringList().contains(name.toLowerCase()) && data != null && !ConfigEntry.SERVER_OWNERS.getStringList().contains(data.getName())) && !ConfigEntry.SERVER_EXECUTIVES.getStringList().contains(data.getName()) && !isTelnetMasterBuilder(data) && !ConfigEntry.HOST_SENDER_NAMES.getStringList().contains(name.toLowerCase()); } public boolean isTelnetMasterBuilder(PlayerData playerData) @@ -114,12 +114,52 @@ public class PlayerList extends FreedomService public PlayerData loadByUuid(UUID uuid) { - return load(plugin.sql.getPlayerByUuid(uuid)); + AtomicReference futureData = new AtomicReference<>(null); + AtomicBoolean loaded = new AtomicBoolean(false); + plugin.sql.getPlayerByUuid(uuid).thenApplyAsync(result -> { + futureData.set(load(result)); + return futureData; + }).whenComplete((result, throwable) -> { + if (throwable != null) { + FLog.severe("Failed to load player by UUID: " + throwable.getMessage()); + return; + } + loaded.set(true); + }); + + while (!loaded.get()) // Wait for the future to complete. + { + if (futureData.get() != null) { // This will break the loop if the result is available before the boolean is updated. + break; + } + } + + return futureData.get(); } public PlayerData loadByIp(String ip) { - return load(plugin.sql.getPlayerByIp(ip)); + AtomicReference futureData = new AtomicReference<>(null); + AtomicBoolean loaded = new AtomicBoolean(false); + plugin.sql.getPlayerByIp(ip).thenApplyAsync(result -> { + futureData.set(load(result)); + return futureData; + }).whenComplete((result, throwable) -> { + if (throwable != null) { + FLog.severe("Failed to load player by IP: " + throwable.getMessage()); + return; + } + loaded.set(true); + }); + + while (!loaded.get()) + { + if (futureData.get() != null) { + break; + } + } // Wait for the future to complete. + + return futureData.get(); } public PlayerData load(ResultSetProvider resultSet) @@ -142,21 +182,27 @@ public class PlayerList extends FreedomService public void save(PlayerData player) { - try - { - ResultSetProvider currentSave = plugin.sql.getPlayerByUuid(player.getUuid()); + plugin.sql.getPlayerByUuid(player.getUuid()).whenComplete((result, throwable) -> { + if (throwable != null) { + FLog.severe("Failed to save player: " + throwable.getMessage()); + return; + } + for (Map.Entry entry : player.toSQLStorable().entrySet()) { - Object storedValue = plugin.sql.getValue(currentSave, entry.getKey(), entry.getValue()); + Object storedValue = plugin.sql.getValue(result, entry.getKey(), entry.getValue()); if (storedValue != null && !storedValue.equals(entry.getValue()) || storedValue == null && entry.getValue() != null || entry.getValue() == null) { - plugin.sql.setPlayerValue(player, entry.getKey(), entry.getValue()); + plugin.sql.setPlayerValue(player, entry.getKey(), entry.getValue()).whenComplete((result1, ex) -> + { + if (ex != null) + { + FLog.severe("Failed to save player: " + ex.getMessage()); + } + }); } } - } catch (SQLException e) - { - FLog.severe("Failed to save player: " + e.getMessage()); - } + }); } public PlayerData getData(Player player) @@ -184,7 +230,11 @@ public class PlayerList extends FreedomService dataMap.put(player.getUniqueId(), playerData); // Send it to the SQL database. - plugin.sql.addPlayer(playerData); + plugin.sql.addPlayer(playerData).whenComplete((result, throwable) -> { + if (throwable != null) { + FLog.severe(throwable.getMessage()); + } + }); // Returns it return playerData; diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/sql/ResultSetProvider.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/sql/ResultSetProvider.java index b3cb7373..6118d399 100644 --- a/commons/src/main/java/me/totalfreedom/totalfreedommod/sql/ResultSetProvider.java +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/sql/ResultSetProvider.java @@ -2,15 +2,10 @@ package me.totalfreedom.totalfreedommod.sql; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Wrapper; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiConsumer; -import java.util.function.Consumer; public class ResultSetProvider { @@ -40,34 +35,18 @@ public class ResultSetProvider } } - public static CompletableFuture provideAllRows(ResultSet resultSet) + public static ResultSetProvider provideAllRows(ResultSet resultSet) throws SQLException { - return CompletableFuture.supplyAsync(() -> - { - try - { - return new ResultSetProvider(resultSet, true); - } catch (SQLException e) - { - return null; - } - }); + return new ResultSetProvider(resultSet, true); } - public static CompletableFuture provideSpecificRow(ResultSet resultSet) throws SQLException + public static ResultSetProvider provideSpecificRow(ResultSet resultSet) throws SQLException { - return CompletableFuture.supplyAsync(() -> { - try - { - return new ResultSetProvider(resultSet, false); - } catch (SQLException e) - { - throw new RuntimeException(e); // We don't want to handle this exception, we want the delegate to handle it instead. - } - }); + return new ResultSetProvider(resultSet, false); } - public static ResultSetProvider fromRow(Map row) { + public static ResultSetProvider fromRow(Map row) + { return new ResultSetProvider(row); } diff --git a/commons/src/main/java/me/totalfreedom/totalfreedommod/sql/SQLite.java b/commons/src/main/java/me/totalfreedom/totalfreedommod/sql/SQLite.java index e595edea..05f2f386 100644 --- a/commons/src/main/java/me/totalfreedom/totalfreedommod/sql/SQLite.java +++ b/commons/src/main/java/me/totalfreedom/totalfreedommod/sql/SQLite.java @@ -10,9 +10,12 @@ import me.totalfreedom.totalfreedommod.util.FUtil; import java.sql.*; import java.text.MessageFormat; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; public class SQLite extends FreedomService { + public static final String TABLE_CHECK_FAILURE = "Failed to check tables on database: "; private final String FILE_NAME = "database.db"; private Connection connection; @@ -21,7 +24,13 @@ public class SQLite extends FreedomService public void onStart() { connect(); - checkTables(); + checkTables().whenComplete((result, throwable) -> + { + if (throwable != null) + { + FLog.severe(TABLE_CHECK_FAILURE + throwable.getMessage()); + } + }); } @Override @@ -56,148 +65,293 @@ public class SQLite extends FreedomService } } - public void checkTables() + public CompletableFuture checkTables() { - try + return CompletableFuture.supplyAsync(() -> { - DatabaseMetaData meta = connection.getMetaData(); - if (tableNotExists(meta, "bans")) + try { - createBanTable(); + return connection.getMetaData(); + } catch (SQLException e) + { + throw new CompletionException(TABLE_CHECK_FAILURE, e); + } + }).thenAcceptAsync(meta -> + { + futureBansTable(meta); + + futureAdminsTable(meta); + + futurePlayersTable(meta); + }); + } + + private void futurePlayersTable(DatabaseMetaData meta) + { + tableNotExists(meta, "players").whenComplete((result, throwable) -> + { + if (throwable != null) + { + FLog.severe(throwable.getMessage()); + return; } - if (tableNotExists(meta, "admins")) + if (result) { - createAdminsTable(); + createPlayersTable().whenComplete((result2, throwable2) -> + { + if (throwable2 != null) + { + FLog.severe(throwable2.getMessage()); + } + }); } - if (tableNotExists(meta, "players")) + }); + } + + private void futureAdminsTable(DatabaseMetaData meta) + { + tableNotExists(meta, "admins").whenComplete((result, throwable) -> + { + if (throwable != null) { - createPlayersTable(); + FLog.severe(throwable.getMessage()); + return; } - } catch (SQLException e) - { - FLog.severe("Failed to check tables on database: " + e.getMessage()); - } + + if (result) + { + createAdminsTable().whenComplete((result2, throwable2) -> + { + if (throwable2 != null) + { + FLog.severe(throwable2.getMessage()); + } + }); + } + }); } - private void createPlayersTable() + private void futureBansTable(DatabaseMetaData meta) { - try (PreparedStatement statement = connection.prepareStatement("CREATE TABLE `players` (`uuid` VARCHAR NOT NULL, `ips` VARCHAR NOT NULL, `notes` VARCHAR, `tag` VARCHAR, `discord_id` VARCHAR, `master_builder` BOOLEAN NOT NULL, `ride_mode` VARCHAR NOT NULL, `coins` INT, `items` VARCHAR, `total_votes` INT NOT NULL, `display_discord` BOOLEAN NOT NULL, `login_message` VARCHAR, `inspect` BOOLEAN NOT NULL);")) + tableNotExists(meta, "bans").whenComplete((result, throwable) -> { - statement.executeUpdate(); - } catch (SQLException e) - { - FLog.severe("Failed to create the players table: " + e.getMessage()); - } + if (throwable != null) + { + FLog.severe(throwable.getMessage()); + return; + } + + if (Boolean.TRUE.equals(result)) // using primitive for some reason... ask SonarLint. + { + createBanTable().whenComplete((result2, throwable2) -> + { + if (throwable2 != null) + { + FLog.severe(throwable2.getMessage()); + } + }); + } + }); } - private void createAdminsTable() + private CompletableFuture createPlayersTable() { - try (PreparedStatement statement = connection.prepareStatement("CREATE TABLE `admins` (`uuid` VARCHAR NOT NULL, `ips` VARCHAR NOT NULL, `rank` VARCHAR NOT NULL, `active` BOOLEAN NOT NULL, `last_login` LONG NOT NULL, `command_spy` BOOLEAN NOT NULL, `potion_spy` BOOLEAN NOT NULL, `ac_format` VARCHAR);")) + return CompletableFuture.supplyAsync(() -> { - statement.executeUpdate(); - } catch (SQLException e) - { - FLog.severe("Failed to create the admins table: " + e.getMessage()); - } + try (PreparedStatement statement = connection.prepareStatement("CREATE TABLE `players` (`uuid` VARCHAR NOT NULL, `ips` VARCHAR NOT NULL, `notes` VARCHAR, `tag` VARCHAR, `discord_id` VARCHAR, `master_builder` BOOLEAN NOT NULL, `ride_mode` VARCHAR NOT NULL, `coins` INT, `items` VARCHAR, `total_votes` INT NOT NULL, `display_discord` BOOLEAN NOT NULL, `login_message` VARCHAR, `inspect` BOOLEAN NOT NULL);")) + { + statement.executeUpdate(); + } catch (SQLException e) + { + throw new CompletionException("Failed to create the players table.", e); + } + return null; + }); } - private void createBanTable() + private CompletableFuture createAdminsTable() { - try (PreparedStatement statement = connection.prepareStatement("CREATE TABLE `bans` (`name` VARCHAR, `uuid` VARCHAR, `ips` VARCHAR, `by` VARCHAR NOT NULL, `at` LONG NOT NULL, `expires` LONG, `reason` VARCHAR);")) + return CompletableFuture.supplyAsync(() -> { - statement.executeUpdate(); - } catch (SQLException e) - { - FLog.severe("Failed to create the bans table: " + e.getMessage()); - } + try (PreparedStatement statement = connection.prepareStatement("CREATE TABLE `admins` (`uuid` VARCHAR NOT NULL, `ips` VARCHAR NOT NULL, `rank` VARCHAR NOT NULL, `active` BOOLEAN NOT NULL, `last_login` LONG NOT NULL, `command_spy` BOOLEAN NOT NULL, `potion_spy` BOOLEAN NOT NULL, `ac_format` VARCHAR);")) + { + statement.executeUpdate(); + } catch (SQLException e) + { + throw new CompletionException("Failed to create the admins table.", e); + } + return null; + }); } - public void truncate(String table) + private CompletableFuture createBanTable() { - try (PreparedStatement statement = connection.prepareStatement("DELETE FROM ?")) + return CompletableFuture.supplyAsync(() -> { - statement.setString(1, table); - statement.executeUpdate(); - } catch (SQLException e) - { - FLog.severe("Failed to truncate " + table + ": " + e.getMessage()); - } + try (PreparedStatement statement = connection.prepareStatement("CREATE TABLE `bans` (`name` VARCHAR, `uuid` VARCHAR, `ips` VARCHAR, `by` VARCHAR NOT NULL, `at` LONG NOT NULL, `expires` LONG, `reason` VARCHAR);")) + { + statement.executeUpdate(); + } catch (SQLException e) + { + throw new CompletionException("Failed to create the bans table.", e); + } + return null; + }); } - public ResultSetProvider getBanList() throws SQLException + public CompletableFuture truncate(String table) { - try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM bans")) + return CompletableFuture.supplyAsync(() -> { - return ResultSetProvider.provideAllRows(statement.executeQuery()).join(); - } + try (PreparedStatement statement = connection.prepareStatement("DELETE FROM ?")) + { + statement.setString(1, table); + statement.executeUpdate(); + } catch (SQLException e) + { + FLog.severe("Failed to truncate " + table + ": " + e.getMessage()); + } + return null; + }); } - public ResultSetProvider getAdminList() throws SQLException + public CompletableFuture getBanList() { - try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM bans")) + return CompletableFuture.supplyAsync(() -> { - return ResultSetProvider.provideAllRows(statement.executeQuery()).join(); - } + ResultSetProvider provider; + try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM bans")) + { + try (ResultSet result = statement.executeQuery()) + { + provider = ResultSetProvider.provideAllRows(result); + } + } catch (SQLException e) + { + throw new CompletionException("Failed to get ban list.", e); + } + return provider; + }); } - public void setAdminValue(Admin admin, String key, Object value) + public CompletableFuture getAdminList() { - try + return CompletableFuture.supplyAsync(() -> { - Object[] data = {key, admin.getUuid()}; - PreparedStatement statement = connection.prepareStatement(MessageFormat.format("UPDATE admins SET {0}=? WHERE uuid=''{1}''", data)); - statement = setUnknownType(statement, 1, value); - statement.executeUpdate(); + ResultSetProvider provider; + try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM bans")) + { + try (ResultSet result = statement.executeQuery()) + { + provider = ResultSetProvider.provideAllRows(result); + } + } catch (SQLException ex) + { + throw new CompletionException("Failed to get admin list.", ex); + } + return provider; + }); - } catch (SQLException e) - { - FLog.severe("Failed to update admin value:"); - FLog.severe(e); - } } - public void setPlayerValue(PlayerData player, String key, Object value) + public CompletableFuture setAdminValue(Admin admin, String key, Object value) { - try + return CompletableFuture.supplyAsync(() -> { - Object[] data = {key, player.getUuid()}; - PreparedStatement statement = connection.prepareStatement(MessageFormat.format("UPDATE players SET {0}=? WHERE uuid=''{1}''", data)); - statement = setUnknownType(statement, 1, value); - statement.executeUpdate(); + try + { + Object[] data = {key, admin.getUuid()}; + PreparedStatement statement = connection.prepareStatement(MessageFormat.format("UPDATE admins SET {0}=? WHERE uuid=''{1}''", data)); + setUnknownType(statement, 1, value).whenComplete((result, throwable) -> + { + if (throwable != null) + { + FLog.severe(throwable.getMessage()); + } - } catch (SQLException e) - { - FLog.severe("Failed to update player value: " + e.getMessage()); - } + try + { + result.executeUpdate(); + } catch (SQLException ex) + { + throw new CompletionException("Failed to update admin value.", ex); + } + }); + } catch (SQLException e) + { + throw new CompletionException("Failed to update admin value.", e); + } + return null; + }); } - public PreparedStatement setUnknownType(PreparedStatement statement, int index, Object value) throws SQLException + public CompletableFuture setPlayerValue(PlayerData player, String key, Object value) { - if (value == null) + return CompletableFuture.supplyAsync(() -> { - statement.setString(index, null); - } else if (value.getClass().equals(String.class)) - { - String v = (String) value; - statement.setString(index, v); - } else if (value.getClass().equals(Integer.class)) - { - int v = (int) value; - statement.setInt(index, v); - } else if (value.getClass().equals(Boolean.class)) - { - boolean v = (boolean) value; - statement.setBoolean(index, v); - } else if (value.getClass().equals(Long.class)) - { - long v = (long) value; - statement.setLong(index, v); - } - return statement; + try + { + Object[] data = {key, player.getUuid()}; + PreparedStatement statement = connection.prepareStatement(MessageFormat.format("UPDATE players SET {0}=? WHERE uuid=''{1}''", data)); + setUnknownType(statement, 1, value).whenComplete((result, throwable) -> + { + if (throwable != null) + { + FLog.severe(throwable.getMessage()); + } + + try + { + result.executeUpdate(); + } catch (SQLException ex) + { + throw new CompletionException("Failed to update player value.", ex); + } + }); + } catch (SQLException e) + { + throw new CompletionException("Failed to update player value.", e); + } + return null; + }); } - public Object getValue(ResultSetProvider provider, String key, Object value) throws SQLException + public CompletableFuture setUnknownType(PreparedStatement statement, int index, Object value) + { + return CompletableFuture.supplyAsync(() -> + { + try + { + if (value == null) + { + statement.setString(index, null); + } else if (value.getClass().equals(String.class)) + { + String v = (String) value; + statement.setString(index, v); + } else if (value.getClass().equals(Integer.class)) + { + int v = (int) value; + statement.setInt(index, v); + } else if (value.getClass().equals(Boolean.class)) + { + boolean v = (boolean) value; + statement.setBoolean(index, v); + } else if (value.getClass().equals(Long.class)) + { + long v = (long) value; + statement.setLong(index, v); + } + return statement; + } catch (SQLException ex) + { + throw new CompletionException("Failed to set unknown type.", ex); + } + }); + } + + public Object getValue(ResultSetProvider provider, String key, Object value) { Object result = null; if (value instanceof String) @@ -216,174 +370,223 @@ public class SQLite extends FreedomService return result; } - public void addAdmin(Admin admin) + public CompletableFuture addAdmin(Admin admin) { - - try (PreparedStatement statement = connection.prepareStatement("INSERT INTO admins VALUES (?, ?, ?, ?, ?, ?, ?, ?)")) + return CompletableFuture.supplyAsync(() -> { - statement.setString(1, admin.getUuid().toString()); - statement.setString(2, FUtil.listToString(admin.getIps())); - statement.setString(3, admin.getRank().toString()); - statement.setBoolean(4, admin.isActive()); - statement.setLong(5, admin.getLastLogin().getTime()); - statement.setBoolean(6, admin.getCommandSpy()); - statement.setBoolean(7, admin.getPotionSpy()); - statement.setString(8, admin.getAcFormat()); - statement.executeUpdate(); - } catch (SQLException e) - { - FLog.severe("Failed to add admin:"); - FLog.severe(e); - } - } - - public void addPlayer(PlayerData player) - { - try (PreparedStatement statement = connection.prepareStatement("INSERT INTO players VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) - { - statement.setString(1, player.getUuid().toString()); - statement.setString(2, FUtil.listToString(player.getIps())); - statement.setString(3, FUtil.listToString(player.getNotes())); - statement.setString(4, FUtil.miniMessage(player.getTag())); - statement.setString(5, player.getDiscordID()); - statement.setBoolean(6, player.isMasterBuilder()); - statement.setString(7, player.getRideMode().name()); - statement.setInt(8, player.getCoins()); - statement.setString(9, FUtil.listToString(player.getItems())); - statement.setInt(10, player.getTotalVotes()); - statement.setBoolean(11, player.doesDisplayDiscord()); - statement.setString(12, player.getLoginMessage()); - statement.setBoolean(13, player.hasInspection()); - statement.executeUpdate(); - } catch (SQLException e) - { - FLog.severe("Failed to add player:"); - FLog.severe(e); - } - } - - public ResultSetProvider getAdminByUuid(UUID uuid) - { - try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM admins WHERE uuid=?")) - { - statement.setString(1, uuid.toString()); - return ResultSetProvider.provideSpecificRow(statement.executeQuery()).join(); - } catch (SQLException e) - { - FLog.severe("Failed to get admin by name:"); - FLog.severe(e); - } - - return null; - } - - public ResultSetProvider getPlayerByUuid(UUID uuid) - { - try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM players WHERE uuid=?")) - { - statement.setString(1, uuid.toString()); - return ResultSetProvider.provideSpecificRow(statement.executeQuery()).join(); - } catch (SQLException e) - { - FLog.severe("Failed to get player by UUID:"); - FLog.severe(e); - } - - return null; - } - - public ResultSetProvider getMasterBuilders() - { - try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM players WHERE master_builder=true")) - { - return ResultSetProvider.provideAllRows(statement.executeQuery()).join(); - } catch (SQLException e) - { - FLog.severe("Failed to get Master Builders:"); - FLog.severe(e); - } - - return null; - } - - public ResultSetProvider getPlayerByIp(String ip) - { - try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM players WHERE ips LIKE %?%")) - { - statement.setString(1, ip); - return ResultSetProvider.provideSpecificRow(statement.executeQuery()).join(); - } catch (SQLException e) - { - FLog.severe("Failed to get player by ip:"); - FLog.severe(e); - } - - return null; - } - - public void removeAdmin(Admin admin) - { - try (PreparedStatement statement = connection.prepareStatement("DELETE FROM admins where name=?")) - { - statement.setString(1, admin.getName()); - statement.executeUpdate(); - } catch (SQLException e) - { - FLog.severe("Failed to remove admin:"); - FLog.severe(e); - } - } - - public void addBan(Ban ban) - { - try (PreparedStatement statement = connection.prepareStatement("INSERT INTO bans VALUES (?, ?, ?, ?, ?, ?, ?)")) - { - statement.setString(1, ban.getUsername()); - String uuid = null; - if (ban.hasUUID()) + try (PreparedStatement statement = connection.prepareStatement("INSERT INTO admins VALUES (?, ?, ?, ?, ?, ?, ?, ?)")) { - uuid = ban.getUuid().toString(); + statement.setString(1, admin.getUuid().toString()); + statement.setString(2, FUtil.listToString(admin.getIps())); + statement.setString(3, admin.getRank().toString()); + statement.setBoolean(4, admin.isActive()); + statement.setLong(5, admin.getLastLogin().getTime()); + statement.setBoolean(6, admin.getCommandSpy()); + statement.setBoolean(7, admin.getPotionSpy()); + statement.setString(8, admin.getAcFormat()); + statement.executeUpdate(); + } catch (SQLException e) + { + throw new CompletionException("Failed to add admin.", e); } - statement.setString(2, uuid); - statement.setString(3, FUtil.listToString(ban.getIps())); - statement.setString(4, ban.getBy()); - statement.setLong(5, ban.getAt().getTime()); - statement.setLong(6, ban.getExpiryUnix()); - statement.setString(7, ban.getReason()); - statement.executeUpdate(); - } catch (SQLException e) - { - FLog.severe("Failed to add ban: " + e.getMessage()); - } + return null; + }); + } - public void removeBan(Ban ban) + public CompletableFuture addPlayer(PlayerData player) { - try + return CompletableFuture.supplyAsync(() -> { - try (PreparedStatement statement = connection.prepareStatement("DELETE FROM bans WHERE name=?")) + try (PreparedStatement statement = connection.prepareStatement("INSERT INTO players VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) + { + statement.setString(1, player.getUuid().toString()); + statement.setString(2, FUtil.listToString(player.getIps())); + statement.setString(3, FUtil.listToString(player.getNotes())); + statement.setString(4, FUtil.miniMessage(player.getTag())); + statement.setString(5, player.getDiscordID()); + statement.setBoolean(6, player.isMasterBuilder()); + statement.setString(7, player.getRideMode().name()); + statement.setInt(8, player.getCoins()); + statement.setString(9, FUtil.listToString(player.getItems())); + statement.setInt(10, player.getTotalVotes()); + statement.setBoolean(11, player.doesDisplayDiscord()); + statement.setString(12, player.getLoginMessage()); + statement.setBoolean(13, player.hasInspection()); + statement.executeUpdate(); + } catch (SQLException e) + { + throw new CompletionException("Failed to add player.", e); + } + return null; + }); + } + + public CompletableFuture getAdminByUuid(UUID uuid) + { + return CompletableFuture.supplyAsync(() -> + { + ResultSetProvider provider; + try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM admins WHERE uuid=?")) + { + statement.setString(1, uuid.toString()); + try (ResultSet set = statement.executeQuery()) + { + provider = ResultSetProvider.provideSpecificRow(set); + } + } catch (SQLException ex) + { + throw new CompletionException(ex); + } + return provider; + }); + } + + public CompletableFuture getPlayerByUuid(UUID uuid) + { + return CompletableFuture.supplyAsync(() -> + { + ResultSetProvider provider; + try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM players WHERE uuid=?")) + { + statement.setString(1, uuid.toString()); + try (ResultSet set = statement.executeQuery()) + { + provider = ResultSetProvider.provideSpecificRow(set); + } + } catch (SQLException ex) + { + throw new CompletionException(ex); + } + + return provider; + }); + } + + public CompletableFuture getMasterBuilders() + { + return CompletableFuture.supplyAsync(() -> + { + ResultSetProvider provider; + try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM players WHERE master_builder=true")) + { + try (ResultSet result = statement.executeQuery()) + { + provider = ResultSetProvider.provideAllRows(result); + } + } catch (SQLException ex) + { + throw new CompletionException(ex); + } + return provider; + }); + } + + public CompletableFuture getPlayerByIp(String ip) + { + return CompletableFuture.supplyAsync(() -> + { + ResultSetProvider provider; + try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM players WHERE ips LIKE %?%")) + { + statement.setString(1, ip); + try (ResultSet set = statement.executeQuery()) + { + provider = ResultSetProvider.provideSpecificRow(set); + } + } catch (SQLException e) + { + throw new CompletionException(e); + } + + return provider; + }); + } + + public CompletableFuture removeAdmin(Admin admin) + { + return CompletableFuture.supplyAsync(() -> + { + try (PreparedStatement statement = connection.prepareStatement("DELETE FROM admins where name=?")) + { + statement.setString(1, admin.getName()); + statement.executeUpdate(); + } catch (SQLException e) + { + throw new CompletionException("Failed to remove admin.", e); + } + return null; + }); + } + + + public CompletableFuture addBan(Ban ban) + { + return CompletableFuture.supplyAsync(() -> + { + try (PreparedStatement statement = connection.prepareStatement("INSERT INTO bans VALUES (?, ?, ?, ?, ?, ?, ?)")) { statement.setString(1, ban.getUsername()); - statement.executeUpdate(); - } - - for (String ip : ban.getIps()) - { - try (PreparedStatement statement = connection.prepareStatement("DELETE FROM bans WHERE ips LIKE %?%")) + String uuid = null; + if (ban.hasUUID()) { - statement.setString(1, ip); + uuid = ban.getUuid().toString(); + } + statement.setString(2, uuid); + statement.setString(3, FUtil.listToString(ban.getIps())); + statement.setString(4, ban.getBy()); + statement.setLong(5, ban.getAt().getTime()); + statement.setLong(6, ban.getExpiryUnix()); + statement.setString(7, ban.getReason()); + statement.executeUpdate(); + } catch (SQLException e) + { + throw new CompletionException("Failed to add ban.", e); + } + return null; + }); + } + + public CompletableFuture removeBan(Ban ban) + { + return CompletableFuture.supplyAsync(() -> + { + try + { + try (PreparedStatement statement = connection.prepareStatement("DELETE FROM bans WHERE name=?")) + { + statement.setString(1, ban.getUsername()); statement.executeUpdate(); } + + for (String ip : ban.getIps()) + { + try (PreparedStatement statement = connection.prepareStatement("DELETE FROM bans WHERE ips LIKE %?%")) + { + statement.setString(1, ip); + statement.executeUpdate(); + } + } + } catch (SQLException e) + { + throw new CompletionException("Failed to remove ban.", e); } - } catch (SQLException e) - { - FLog.severe("Failed to remove ban: " + e.getMessage()); - } + return null; + }); } // We've changed this to read tableNotExists because it's more accurate in context. - public boolean tableNotExists(DatabaseMetaData meta, String name) throws SQLException + public CompletableFuture tableNotExists(DatabaseMetaData meta, String name) { - return !meta.getTables(null, null, name, null).next(); + return CompletableFuture.supplyAsync(() -> + { + try + { + return !meta.getTables(null, null, name, null).next(); + } catch (SQLException ex) + { + throw new CompletionException(TABLE_CHECK_FAILURE, ex); + } + }); } } \ No newline at end of file