Refactor remaining API classes

This commit is contained in:
Intelli 2025-03-10 14:06:31 -06:00
parent 5c965b8a68
commit 83302f59f7
3 changed files with 235 additions and 67 deletions

View file

@ -8,6 +8,7 @@ import java.util.List;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler; import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database; import net.coreprotect.database.Database;
import net.coreprotect.database.statement.UserStatement; import net.coreprotect.database.statement.UserStatement;
@ -15,13 +16,41 @@ import net.coreprotect.utility.BlockUtils;
import net.coreprotect.utility.StringUtils; import net.coreprotect.utility.StringUtils;
import net.coreprotect.utility.WorldUtils; import net.coreprotect.utility.WorldUtils;
/**
* Provides API methods for block-related lookups in the CoreProtect database.
*/
public class BlockAPI { 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<String[]> performLookup(Block block, int offset) { public static List<String[]> performLookup(Block block, int offset) {
List<String[]> result = new ArrayList<>(); List<String[]> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) {
return result;
}
if (block == null) {
return result;
}
try (Connection connection = Database.getConnection(false, 1000)) { try (Connection connection = Database.getConnection(false, 1000)) {
if (block == null) { if (connection == null) {
return result; return result;
} }
@ -31,38 +60,37 @@ public class BlockAPI {
int time = (int) (System.currentTimeMillis() / 1000L); int time = (int) (System.currentTimeMillis() / 1000L);
int worldId = WorldUtils.getWorldId(block.getWorld().getName()); int worldId = WorldUtils.getWorldId(block.getWorld().getName());
int checkTime = 0; int checkTime = 0;
if (offset > 0) { if (offset > 0) {
checkTime = time - offset; checkTime = time - offset;
} }
if (connection == null) { try (Statement statement = connection.createStatement()) {
return result; 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(); try (ResultSet results = statement.executeQuery(query)) {
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"; while (results.next()) {
ResultSet results = statement.executeQuery(query); 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()) { if (ConfigHandler.playerIdCacheReversed.get(resultUserId) == null) {
String resultTime = results.getString("time"); UserStatement.loadName(connection, resultUserId);
int resultUserId = results.getInt("user"); }
String resultAction = results.getString("action");
int resultType = results.getInt("type"); String resultUser = ConfigHandler.playerIdCacheReversed.get(resultUserId);
String resultData = results.getString("data"); String blockData = BlockUtils.byteDataToString(resultBlockData, resultType);
byte[] resultBlockData = results.getBytes("blockdata");
String resultRolledBack = results.getString("rolled_back"); 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 };
if (ConfigHandler.playerIdCacheReversed.get(resultUserId) == null) {
UserStatement.loadName(connection, resultUserId); 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) { catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -70,5 +98,4 @@ public class BlockAPI {
return result; return result;
} }
} }

View file

@ -19,67 +19,90 @@ import net.coreprotect.utility.MaterialUtils;
import net.coreprotect.utility.StringUtils; import net.coreprotect.utility.StringUtils;
import net.coreprotect.utility.WorldUtils; 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 { public class QueueLookup extends Queue {
/**
* Private constructor to prevent instantiation.
* This is a utility class with static methods only.
*/
private QueueLookup() { private QueueLookup() {
throw new IllegalStateException("API class"); 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<String[]> performLookup(Block block) { public static List<String[]> performLookup(Block block) {
List<String[]> result = new ArrayList<>(); List<String[]> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) { if (!Config.getGlobal().API_ENABLED) {
return result; return result;
} }
if (block == null) {
return result;
}
try { try {
int consumerCount = 0; // Determine total count of actions in the consumer queues
int currentConsumerSize = Process.getCurrentConsumerSize(); int consumerCount = calculateConsumerCount();
if (currentConsumerSize == 0) {
consumerCount = Consumer.getConsumerSize(0) + Consumer.getConsumerSize(1);
}
else {
int consumerId = (Consumer.currentConsumer == 1) ? 1 : 0;
consumerCount = Consumer.getConsumerSize(consumerId) + currentConsumerSize;
}
if (consumerCount == 0) { if (consumerCount == 0) {
return result; return result;
} }
// Get data from the current consumer
int currentConsumer = Consumer.currentConsumer; int currentConsumer = Consumer.currentConsumer;
ArrayList<Object[]> consumerData = Consumer.consumer.get(currentConsumer); ArrayList<Object[]> consumerData = Consumer.consumer.get(currentConsumer);
Map<Integer, String[]> users = Consumer.consumerUsers.get(currentConsumer); Map<Integer, String[]> users = Consumer.consumerUsers.get(currentConsumer);
Map<Integer, Object> consumerObject = Consumer.consumerObjects.get(currentConsumer); Map<Integer, Object> 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<Object[]> iterator = consumerData.listIterator(); ListIterator<Object[]> iterator = consumerData.listIterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
Object[] data = iterator.next(); Object[] data = iterator.next();
int id = (int) data[0]; int id = (int) data[0];
int action = (int) data[1]; int action = (int) data[1];
// Only process block break and place actions
if (action != Process.BLOCK_BREAK && action != Process.BLOCK_PLACE) { if (action != Process.BLOCK_BREAK && action != Process.BLOCK_PLACE) {
continue; continue;
} }
String[] userData = users.get(id); String[] userData = users.get(id);
Object objectData = consumerObject.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]; Material blockType = (Material) data[2];
int legacyData = (int) data[3]; int legacyData = (int) data[3];
String blockData = (String) data[7]; String blockData = (String) data[7];
String user = userData[0]; String user = userData[0];
BlockState blockState = (BlockState) objectData; BlockState blockState = (BlockState) objectData;
Location location = blockState.getLocation(); Location location = blockState.getLocation();
int wid = WorldUtils.getWorldId(location.getWorld().getName()); int worldId = WorldUtils.getWorldId(location.getWorld().getName());
int resultType = MaterialUtils.getBlockId(blockType); int resultType = MaterialUtils.getBlockId(blockType);
int time = (int) (System.currentTimeMillis() / 1000L); 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[] 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 };
String[] lineData = StringUtils.toStringArray(lookupData);
result.add(lineData); result.add(StringUtils.toStringArray(lookupData));
} }
} }
// Reverse the result list to match database lookup order (most recent first)
Collections.reverse(result); Collections.reverse(result);
} }
catch (Exception e) { catch (Exception e) {
@ -89,4 +112,34 @@ public class QueueLookup extends Queue {
return result; 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);
}
} }

View file

@ -12,58 +12,69 @@ import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database; import net.coreprotect.database.Database;
import net.coreprotect.database.statement.UserStatement; 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 { public class SessionLookup {
/**
* The session type ID used for identifying session-related events.
*/
public static final int ID = 0; public static final int ID = 0;
/**
* Private constructor to prevent instantiation.
* This is a utility class with static methods only.
*/
private SessionLookup() { private SessionLookup() {
throw new IllegalStateException("API class"); 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<String[]> performLookup(String user, int offset) { public static List<String[]> performLookup(String user, int offset) {
List<String[]> result = new ArrayList<>(); List<String[]> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) { if (!Config.getGlobal().API_ENABLED) {
return result; return result;
} }
if (user == null) {
return result;
}
try (Connection connection = Database.getConnection(false, 1000)) { try (Connection connection = Database.getConnection(false, 1000)) {
if (connection == null || user == null) { if (connection == null) {
return result; return result;
} }
// Prepare lookup parameters
String type = String.valueOf(ID); String type = String.valueOf(ID);
int time = (int) (System.currentTimeMillis() / 1000L); int time = (int) (System.currentTimeMillis() / 1000L);
int checkTime = 0; int checkTime = calculateCheckTime(time, offset);
if (offset > 0) {
checkTime = time - offset;
}
if (ConfigHandler.playerIdCache.get(user.toLowerCase(Locale.ROOT)) == null) { // Get user ID from cache or load it
UserStatement.loadId(connection, user, null); int userId = getUserId(connection, user);
}
int userId = ConfigHandler.playerIdCache.get(user.toLowerCase(Locale.ROOT));
// Query session data from database
try (Statement statement = connection.createStatement()) { 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"; String query = buildSessionQuery(userId, checkTime);
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");
if (ConfigHandler.playerIdCacheReversed.get(resultUserId) == null) { try (ResultSet results = statement.executeQuery(query)) {
UserStatement.loadName(connection, resultUserId); 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) { catch (Exception e) {
@ -73,4 +84,81 @@ public class SessionLookup {
return result; 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 };
}
} }