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 net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
import net.coreprotect.database.statement.UserStatement;
@ -15,34 +16,59 @@ 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<String[]> performLookup(Block block, int offset) {
List<String[]> result = new ArrayList<>();
try (Connection connection = Database.getConnection(false, 1000)) {
if (!Config.getGlobal().API_ENABLED) {
return result;
}
if (block == null) {
return result;
}
try (Connection connection = Database.getConnection(false, 1000)) {
if (connection == null) {
return result;
}
int x = block.getX();
int y = block.getY();
int z = block.getZ();
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;
}
Statement statement = connection.createStatement();
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";
ResultSet results = statement.executeQuery(query);
try (ResultSet results = statement.executeQuery(query)) {
while (results.next()) {
String resultTime = results.getString("time");
int resultUserId = results.getInt("user");
@ -51,18 +77,20 @@ public class BlockAPI {
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);
}
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);
result.add(StringUtils.toStringArray(lookupData));
}
}
}
results.close();
statement.close();
}
catch (Exception e) {
e.printStackTrace();
@ -70,5 +98,4 @@ public class BlockAPI {
return result;
}
}

View file

@ -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<String[]> performLookup(Block block) {
List<String[]> 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<Object[]> consumerData = Consumer.consumer.get(currentConsumer);
Map<Integer, String[]> users = Consumer.consumerUsers.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();
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);
}
}

View file

@ -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<String[]> performLookup(String user, int offset) {
List<String[]> result = new ArrayList<>();
if (!Config.getGlobal().API_ENABLED) {
return result;
}
try (Connection connection = Database.getConnection(false, 1000)) {
if (connection == null || user == null) {
if (user == null) {
return result;
}
try (Connection connection = Database.getConnection(false, 1000)) {
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);
String query = buildSessionQuery(userId, checkTime);
try (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) {
UserStatement.loadName(connection, resultUserId);
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 };
}
}