mirror of
https://gitlab.com/SamB440/rpgregions-2.git
synced 2026-01-06 15:41:35 +00:00
Fix various potential memory leak and concurrency issues with acccount storage
This commit is contained in:
@@ -42,11 +42,17 @@ public interface IStorageManager {
|
||||
void clearDiscovery(UUID uuid, String regionId);
|
||||
|
||||
void deleteAccount(UUID uuid);
|
||||
|
||||
/**
|
||||
* Removes an account from the storage cache and saves its data.
|
||||
* Removes an account from the storage cache and optionally saves its data.
|
||||
* @param uuid player's UUID
|
||||
* @param save whether to save the player's data
|
||||
*/
|
||||
CompletableFuture<Void> removeCachedAccount(UUID uuid);
|
||||
CompletableFuture<Void> removeCachedAccount(UUID uuid, boolean save);
|
||||
|
||||
default CompletableFuture<Void> removeCachedAccount(UUID uuid) {
|
||||
return removeCachedAccount(uuid, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a UUID safe to use in databases.
|
||||
|
||||
@@ -5,8 +5,11 @@ import net.islandearth.rpgregions.managers.data.account.RPGRegionsAccount;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
@@ -14,12 +17,46 @@ import java.util.UUID;
|
||||
public record ConnectionListener(RPGRegions plugin) implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (!plugin.getManagers().getStorageManager().getCachedAccounts().containsKey(player.getUniqueId())) {
|
||||
player.kickPlayer(ChatColor.RED + "Player user data not present! Please contact an administrator.");
|
||||
}
|
||||
}
|
||||
|
||||
// PlayerLoginEvent is called AFTER AsyncPlayerPreLoginEvent
|
||||
// We can't really avoid loading the user first unfortunately
|
||||
@EventHandler(priority = EventPriority.HIGHEST) // Highest so we are always the last called
|
||||
public void onValidate(final PlayerLoginEvent event) {
|
||||
if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
|
||||
// DO NOT save the user if this is due to whitelist!
|
||||
// If they are a new user that was prevented from joining due to whitelist
|
||||
// Then when they join after whitelist is disabled, they will not be considered new
|
||||
// Also saves performance
|
||||
plugin.getManagers().getStorageManager().removeCachedAccount(event.getPlayer().getUniqueId(), false);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST) // Highest so we are always the last called
|
||||
public void onJoin(AsyncPlayerPreLoginEvent event) {
|
||||
// If something else has prevented the player from joining, we don't want to load the user.
|
||||
// Otherwise, we will get memory leaks.
|
||||
if (event.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) return;
|
||||
|
||||
UUID uuid = event.getUniqueId();
|
||||
|
||||
// If the user is present then we still haven't saved, prevent them joining to avoid corrupt data
|
||||
if (plugin.getManagers().getStorageManager().getCachedAccounts().containsKey(uuid)) {
|
||||
event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, ChatColor.YELLOW + "You're rejoining too quickly! Give us a moment to save your data.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
RPGRegionsAccount account = plugin.getManagers().getStorageManager().getAccount(uuid).get();
|
||||
if (account != null) return;
|
||||
} catch (Exception e) {
|
||||
// If there was an error, don't allow entry!
|
||||
event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, ChatColor.RED + "An error occurred whilst loading player user data! Please contact an administrator.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
@@ -98,8 +98,13 @@ public abstract class SQLCommonStorage implements IStorageManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> removeCachedAccount(UUID uuid) {
|
||||
public CompletableFuture<Void> removeCachedAccount(UUID uuid, boolean save) {
|
||||
RPGRegionsAccount account = cachedAccounts.get(uuid);
|
||||
if (!save) {
|
||||
cachedAccounts.remove(uuid);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
return DB.getResultsAsync(SELECT_REGION, getDatabaseUuid(uuid)).thenAccept(results -> {
|
||||
List<String> current = new ArrayList<>();
|
||||
for (DbRow row : results) {
|
||||
|
||||
@@ -135,8 +135,9 @@ public class YamlStorage implements IStorageManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> removeCachedAccount(UUID uuid) {
|
||||
RPGRegionsAccount account = cachedAccounts.get(uuid);
|
||||
public CompletableFuture<Void> removeCachedAccount(UUID uuid, boolean save) {
|
||||
RPGRegionsAccount account = cachedAccounts.remove(uuid);
|
||||
if (!save) return CompletableFuture.completedFuture(null);
|
||||
File file = new File(plugin.getDataFolder() + "/accounts/" + uuid.toString() + ".yml");
|
||||
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||
|
||||
@@ -151,7 +152,6 @@ public class YamlStorage implements IStorageManager {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
cachedAccounts.remove(uuid);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user