From 83302f59f7111cf901034b21d37eca60b3cf464a Mon Sep 17 00:00:00 2001 From: Intelli Date: Mon, 10 Mar 2025 14:06:31 -0600 Subject: [PATCH] Refactor remaining API classes --- .../java/net/coreprotect/api/BlockAPI.java | 79 ++++++---- .../java/net/coreprotect/api/QueueLookup.java | 83 +++++++++-- .../net/coreprotect/api/SessionLookup.java | 140 ++++++++++++++---- 3 files changed, 235 insertions(+), 67 deletions(-) diff --git a/src/main/java/net/coreprotect/api/BlockAPI.java b/src/main/java/net/coreprotect/api/BlockAPI.java index f950000..d9a835c 100644 --- a/src/main/java/net/coreprotect/api/BlockAPI.java +++ b/src/main/java/net/coreprotect/api/BlockAPI.java @@ -8,6 +8,7 @@ import java.util.List; import org.bukkit.block.Block; +import net.coreprotect.config.Config; import net.coreprotect.config.ConfigHandler; import net.coreprotect.database.Database; import net.coreprotect.database.statement.UserStatement; @@ -15,13 +16,41 @@ import net.coreprotect.utility.BlockUtils; import net.coreprotect.utility.StringUtils; import net.coreprotect.utility.WorldUtils; +/** + * Provides API methods for block-related lookups in the CoreProtect database. + */ public class BlockAPI { + /** + * Private constructor to prevent instantiation. + * This is a utility class with static methods only. + */ + private BlockAPI() { + throw new IllegalStateException("API class"); + } + + /** + * Performs a lookup of block-related actions at the specified block. + * + * @param block + * The block to look up + * @param offset + * Time constraint in seconds (0 means no time constraint) + * @return List of results in a String array format + */ public static List performLookup(Block block, int offset) { List result = new ArrayList<>(); + if (!Config.getGlobal().API_ENABLED) { + return result; + } + + if (block == null) { + return result; + } + try (Connection connection = Database.getConnection(false, 1000)) { - if (block == null) { + if (connection == null) { return result; } @@ -31,38 +60,37 @@ public class BlockAPI { int time = (int) (System.currentTimeMillis() / 1000L); int worldId = WorldUtils.getWorldId(block.getWorld().getName()); int checkTime = 0; + if (offset > 0) { checkTime = time - offset; } - if (connection == null) { - return result; - } + try (Statement statement = connection.createStatement()) { + String query = "SELECT time,user,action,type,data,blockdata,rolled_back FROM " + ConfigHandler.prefix + "block " + WorldUtils.getWidIndex("block") + "WHERE wid = '" + worldId + "' AND x = '" + x + "' AND z = '" + z + "' AND y = '" + y + "' AND time > '" + checkTime + "' ORDER BY rowid DESC"; - Statement statement = connection.createStatement(); - String query = "SELECT time,user,action,type,data,blockdata,rolled_back FROM " + ConfigHandler.prefix + "block " + WorldUtils.getWidIndex("block") + "WHERE wid = '" + worldId + "' AND x = '" + x + "' AND z = '" + z + "' AND y = '" + y + "' AND time > '" + checkTime + "' ORDER BY rowid DESC"; - ResultSet results = statement.executeQuery(query); + try (ResultSet results = statement.executeQuery(query)) { + while (results.next()) { + String resultTime = results.getString("time"); + int resultUserId = results.getInt("user"); + String resultAction = results.getString("action"); + int resultType = results.getInt("type"); + String resultData = results.getString("data"); + byte[] resultBlockData = results.getBytes("blockdata"); + String resultRolledBack = results.getString("rolled_back"); - while (results.next()) { - String resultTime = results.getString("time"); - int resultUserId = results.getInt("user"); - String resultAction = results.getString("action"); - int resultType = results.getInt("type"); - String resultData = results.getString("data"); - byte[] resultBlockData = results.getBytes("blockdata"); - String resultRolledBack = results.getString("rolled_back"); - if (ConfigHandler.playerIdCacheReversed.get(resultUserId) == null) { - UserStatement.loadName(connection, resultUserId); + if (ConfigHandler.playerIdCacheReversed.get(resultUserId) == null) { + UserStatement.loadName(connection, resultUserId); + } + + String resultUser = ConfigHandler.playerIdCacheReversed.get(resultUserId); + String blockData = BlockUtils.byteDataToString(resultBlockData, resultType); + + String[] lookupData = new String[] { resultTime, resultUser, String.valueOf(x), String.valueOf(y), String.valueOf(z), String.valueOf(resultType), resultData, resultAction, resultRolledBack, String.valueOf(worldId), blockData }; + + result.add(StringUtils.toStringArray(lookupData)); + } } - String resultUser = ConfigHandler.playerIdCacheReversed.get(resultUserId); - String blockData = BlockUtils.byteDataToString(resultBlockData, resultType); - - String[] lookupData = new String[] { resultTime, resultUser, String.valueOf(x), String.valueOf(y), String.valueOf(z), String.valueOf(resultType), resultData, resultAction, resultRolledBack, String.valueOf(worldId), blockData }; - String[] lineData = StringUtils.toStringArray(lookupData); - result.add(lineData); } - results.close(); - statement.close(); } catch (Exception e) { e.printStackTrace(); @@ -70,5 +98,4 @@ public class BlockAPI { return result; } - } diff --git a/src/main/java/net/coreprotect/api/QueueLookup.java b/src/main/java/net/coreprotect/api/QueueLookup.java index 7746647..8b2de68 100644 --- a/src/main/java/net/coreprotect/api/QueueLookup.java +++ b/src/main/java/net/coreprotect/api/QueueLookup.java @@ -19,67 +19,90 @@ import net.coreprotect.utility.MaterialUtils; import net.coreprotect.utility.StringUtils; import net.coreprotect.utility.WorldUtils; +/** + * Provides API methods for looking up block-related actions in the processing queue. + * This class allows for retrieving actions that have not yet been saved to the database. + */ public class QueueLookup extends Queue { + /** + * Private constructor to prevent instantiation. + * This is a utility class with static methods only. + */ private QueueLookup() { throw new IllegalStateException("API class"); } + /** + * Performs a lookup of block-related actions in the processing queue for the specified block. + * This allows retrieving actions that have not yet been committed to the database. + * + * @param block + * The block to look up in the processing queue + * @return List of results in a String array format, empty list if API is disabled or no results found + */ public static List performLookup(Block block) { List result = new ArrayList<>(); + if (!Config.getGlobal().API_ENABLED) { return result; } + if (block == null) { + return result; + } + try { - int consumerCount = 0; - int currentConsumerSize = Process.getCurrentConsumerSize(); - if (currentConsumerSize == 0) { - consumerCount = Consumer.getConsumerSize(0) + Consumer.getConsumerSize(1); - } - else { - int consumerId = (Consumer.currentConsumer == 1) ? 1 : 0; - consumerCount = Consumer.getConsumerSize(consumerId) + currentConsumerSize; - } + // Determine total count of actions in the consumer queues + int consumerCount = calculateConsumerCount(); if (consumerCount == 0) { return result; } + // Get data from the current consumer int currentConsumer = Consumer.currentConsumer; ArrayList consumerData = Consumer.consumer.get(currentConsumer); Map users = Consumer.consumerUsers.get(currentConsumer); Map consumerObject = Consumer.consumerObjects.get(currentConsumer); - Location oldLocation = block.getLocation(); + // Current block location for comparison with actions in the queue + Location blockLocation = block.getLocation(); + + // Check for block actions in the processing queue ListIterator iterator = consumerData.listIterator(); while (iterator.hasNext()) { Object[] data = iterator.next(); int id = (int) data[0]; int action = (int) data[1]; + + // Only process block break and place actions if (action != Process.BLOCK_BREAK && action != Process.BLOCK_PLACE) { continue; } String[] userData = users.get(id); Object objectData = consumerObject.get(id); - if (userData != null && objectData != null && (objectData instanceof BlockState) && ((BlockState) objectData).getLocation().equals(oldLocation)) { + + // Verify the action pertains to the requested block + if (isActionForBlock(userData, objectData, blockLocation)) { Material blockType = (Material) data[2]; int legacyData = (int) data[3]; String blockData = (String) data[7]; String user = userData[0]; BlockState blockState = (BlockState) objectData; Location location = blockState.getLocation(); - int wid = WorldUtils.getWorldId(location.getWorld().getName()); + int worldId = WorldUtils.getWorldId(location.getWorld().getName()); int resultType = MaterialUtils.getBlockId(blockType); int time = (int) (System.currentTimeMillis() / 1000L); - String[] lookupData = new String[] { String.valueOf(time), user, String.valueOf(location.getBlockX()), String.valueOf(location.getBlockY()), String.valueOf(location.getBlockZ()), String.valueOf(resultType), String.valueOf(legacyData), String.valueOf(action), "0", String.valueOf(wid), blockData }; - String[] lineData = StringUtils.toStringArray(lookupData); - result.add(lineData); + String[] lookupData = new String[] { String.valueOf(time), user, String.valueOf(location.getBlockX()), String.valueOf(location.getBlockY()), String.valueOf(location.getBlockZ()), String.valueOf(resultType), String.valueOf(legacyData), String.valueOf(action), "0", String.valueOf(worldId), blockData }; + + result.add(StringUtils.toStringArray(lookupData)); } } + // Reverse the result list to match database lookup order (most recent first) Collections.reverse(result); } catch (Exception e) { @@ -89,4 +112,34 @@ public class QueueLookup extends Queue { return result; } + /** + * Calculates the total count of actions in the consumer queues. + * + * @return The total count of actions in the consumer queues + */ + private static int calculateConsumerCount() { + int currentConsumerSize = Process.getCurrentConsumerSize(); + if (currentConsumerSize == 0) { + return Consumer.getConsumerSize(0) + Consumer.getConsumerSize(1); + } + else { + int consumerId = (Consumer.currentConsumer == 1) ? 1 : 0; + return Consumer.getConsumerSize(consumerId) + currentConsumerSize; + } + } + + /** + * Determines if an action in the queue pertains to the specified block location. + * + * @param userData + * User data associated with the action + * @param objectData + * Object data associated with the action + * @param blockLocation + * Location of the block being looked up + * @return true if the action pertains to the specified block, false otherwise + */ + private static boolean isActionForBlock(String[] userData, Object objectData, Location blockLocation) { + return userData != null && objectData != null && (objectData instanceof BlockState) && ((BlockState) objectData).getLocation().equals(blockLocation); + } } diff --git a/src/main/java/net/coreprotect/api/SessionLookup.java b/src/main/java/net/coreprotect/api/SessionLookup.java index 6050069..f030dc6 100644 --- a/src/main/java/net/coreprotect/api/SessionLookup.java +++ b/src/main/java/net/coreprotect/api/SessionLookup.java @@ -12,58 +12,69 @@ import net.coreprotect.config.ConfigHandler; import net.coreprotect.database.Database; import net.coreprotect.database.statement.UserStatement; +/** + * Provides API methods for looking up player session data in the CoreProtect database. + * Session data includes login/logout events and their associated timestamps and locations. + */ public class SessionLookup { + /** + * The session type ID used for identifying session-related events. + */ public static final int ID = 0; + /** + * Private constructor to prevent instantiation. + * This is a utility class with static methods only. + */ private SessionLookup() { throw new IllegalStateException("API class"); } + /** + * Performs a lookup of session-related actions for the specified user. + * This returns login and logout events within the specified time constraint. + * + * @param user + * The username to look up session data for + * @param offset + * Time constraint in seconds (0 means no time constraint) + * @return List of results in a String array format, empty list if API is disabled or no results found + */ public static List performLookup(String user, int offset) { List result = new ArrayList<>(); + if (!Config.getGlobal().API_ENABLED) { return result; } + if (user == null) { + return result; + } + try (Connection connection = Database.getConnection(false, 1000)) { - if (connection == null || user == null) { + if (connection == null) { return result; } + // Prepare lookup parameters String type = String.valueOf(ID); int time = (int) (System.currentTimeMillis() / 1000L); - int checkTime = 0; - if (offset > 0) { - checkTime = time - offset; - } + int checkTime = calculateCheckTime(time, offset); - if (ConfigHandler.playerIdCache.get(user.toLowerCase(Locale.ROOT)) == null) { - UserStatement.loadId(connection, user, null); - } - int userId = ConfigHandler.playerIdCache.get(user.toLowerCase(Locale.ROOT)); + // Get user ID from cache or load it + int userId = getUserId(connection, user); + // Query session data from database try (Statement statement = connection.createStatement()) { - String query = "SELECT time,user,wid,x,y,z,action FROM " + ConfigHandler.prefix + "session WHERE user = '" + userId + "' AND time > '" + checkTime + "' ORDER BY rowid DESC"; - ResultSet results = statement.executeQuery(query); - while (results.next()) { - String resultTime = results.getString("time"); - int resultUserId = results.getInt("user"); - String resultWorldId = results.getString("wid"); - String resultX = results.getString("x"); - String resultY = results.getString("y"); - String resultZ = results.getString("z"); - String resultAction = results.getString("action"); + String query = buildSessionQuery(userId, checkTime); - if (ConfigHandler.playerIdCacheReversed.get(resultUserId) == null) { - UserStatement.loadName(connection, resultUserId); + try (ResultSet results = statement.executeQuery(query)) { + while (results.next()) { + String[] sessionData = extractSessionData(connection, results, type); + result.add(sessionData); } - String resultUser = ConfigHandler.playerIdCacheReversed.get(resultUserId); - - String[] lookupData = new String[] { resultTime, resultUser, resultX, resultY, resultZ, resultWorldId, type, resultAction }; - result.add(lookupData); } - results.close(); } } catch (Exception e) { @@ -73,4 +84,81 @@ public class SessionLookup { return result; } + /** + * Calculates the time threshold for the session lookup. + * + * @param currentTime + * The current time in seconds + * @param offset + * The time offset in seconds + * @return The calculated time threshold + */ + private static int calculateCheckTime(int currentTime, int offset) { + return (offset > 0) ? currentTime - offset : 0; + } + + /** + * Gets the user ID for the specified username. + * If the user ID is not in the cache, it will be loaded from the database. + * + * @param connection + * The database connection + * @param username + * The username to get the ID for + * @return The user ID + */ + private static int getUserId(Connection connection, String username) { + String lowerUsername = username.toLowerCase(Locale.ROOT); + + if (ConfigHandler.playerIdCache.get(lowerUsername) == null) { + UserStatement.loadId(connection, username, null); + } + + return ConfigHandler.playerIdCache.get(lowerUsername); + } + + /** + * Builds the SQL query for retrieving session data. + * + * @param userId + * The user ID to query for + * @param checkTime + * The time threshold for the query + * @return The SQL query string + */ + private static String buildSessionQuery(int userId, int checkTime) { + return "SELECT time,user,wid,x,y,z,action FROM " + ConfigHandler.prefix + "session WHERE user = '" + userId + "' AND time > '" + checkTime + "' ORDER BY rowid DESC"; + } + + /** + * Extracts session data from a result set row. + * + * @param connection + * The database connection + * @param results + * The result set to extract data from + * @param type + * The session type ID + * @return An array of session data values + * @throws Exception + * if an error occurs while extracting data + */ + private static String[] extractSessionData(Connection connection, ResultSet results, String type) throws Exception { + String resultTime = results.getString("time"); + int resultUserId = results.getInt("user"); + String resultWorldId = results.getString("wid"); + String resultX = results.getString("x"); + String resultY = results.getString("y"); + String resultZ = results.getString("z"); + String resultAction = results.getString("action"); + + // Get username from cache or load it + if (ConfigHandler.playerIdCacheReversed.get(resultUserId) == null) { + UserStatement.loadName(connection, resultUserId); + } + String resultUser = ConfigHandler.playerIdCacheReversed.get(resultUserId); + + // Create and return the session data array + return new String[] { resultTime, resultUser, resultX, resultY, resultZ, resultWorldId, type, resultAction }; + } }