From 7811279b26025c8ae4ab5da34bde4eb5f0ce31cb Mon Sep 17 00:00:00 2001 From: Ty Sayers Date: Sat, 14 Mar 2015 17:41:16 -0400 Subject: [PATCH] Convert friend system over to redis-based PlayerStatus data tracking from old SQL storage. --- .../bungee/playerTracker/PlayerStatus.java | 33 ------- .../bungee/playerTracker/PlayerTracker.java | 1 + .../mineplex/core/friend/FriendManager.java | 2 +- .../core/friend/data/FriendRepository.java | 90 ++++++++++++++++--- .../src/mineplex/serverdata/Region.java | 10 +++ .../serverdata/data/DataRepository.java | 2 + .../serverdata/redis/RedisDataRepository.java | 11 ++- 7 files changed, 103 insertions(+), 46 deletions(-) delete mode 100644 Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerTracker/PlayerStatus.java diff --git a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerTracker/PlayerStatus.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerTracker/PlayerStatus.java deleted file mode 100644 index 2e00dcd3a..000000000 --- a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerTracker/PlayerStatus.java +++ /dev/null @@ -1,33 +0,0 @@ -package mineplex.bungee.playerTracker; - -import mineplex.serverdata.data.Data; - -public class PlayerStatus implements Data -{ - // The name of this server. - private String _name; - public String getName() { return _name; } - - // The current message of the day (MOTD) of the server. - private String _server; - public String getServer() { return _server; } - - /** - * Class constructor - * @param name - * @param server - */ - public PlayerStatus(String name, String server) - { - _name = name; - _server = server; - } - - /** - * Unique identifying String ID associated with this {@link PlayerStatus}. - */ - public String getDataId() - { - return _name; - } -} diff --git a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerTracker/PlayerTracker.java b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerTracker/PlayerTracker.java index 5fd51a7a8..24e40892c 100644 --- a/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerTracker/PlayerTracker.java +++ b/Plugins/Mineplex.Bungee.Mineplexer/src/mineplex/bungee/playerTracker/PlayerTracker.java @@ -4,6 +4,7 @@ import java.io.File; import mineplex.serverdata.Region; import mineplex.serverdata.data.DataRepository; +import mineplex.serverdata.data.PlayerStatus; import mineplex.serverdata.redis.RedisDataRepository; import mineplex.serverdata.servers.ServerManager; import net.md_5.bungee.api.event.PlayerDisconnectEvent; diff --git a/Plugins/Mineplex.Core/src/mineplex/core/friend/FriendManager.java b/Plugins/Mineplex.Core/src/mineplex/core/friend/FriendManager.java index fe6a0d892..373ca16cb 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/friend/FriendManager.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/friend/FriendManager.java @@ -409,7 +409,7 @@ public class FriendManager extends MiniDbClientPlugin @Override public String getQuery(String uuid, String name) { - return "SELECT tA.Name, status, serverName, tA.lastLogin, now() FROM accountFriend INNER Join accounts AS fA ON fA.uuid = uuidSource INNER JOIN accounts AS tA ON tA.uuid = uuidTarget LEFT JOIN playerMap ON tA.name = playerName WHERE uuidSource = '" + return "SELECT tA.Name, status, tA.lastLogin, now() FROM accountFriend INNER Join accounts AS fA ON fA.uuid = uuidSource INNER JOIN accounts AS tA ON tA.uuid = uuidTarget WHERE uuidSource = '" + uuid + "';"; } } diff --git a/Plugins/Mineplex.Core/src/mineplex/core/friend/data/FriendRepository.java b/Plugins/Mineplex.Core/src/mineplex/core/friend/data/FriendRepository.java index 3b29e9a1d..359220020 100644 --- a/Plugins/Mineplex.Core/src/mineplex/core/friend/data/FriendRepository.java +++ b/Plugins/Mineplex.Core/src/mineplex/core/friend/data/FriendRepository.java @@ -2,6 +2,12 @@ package mineplex.core.friend.data; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; @@ -12,18 +18,29 @@ import mineplex.core.database.RepositoryBase; import mineplex.core.database.ResultSetCallable; import mineplex.core.database.column.ColumnVarChar; import mineplex.core.friend.FriendStatusType; +import mineplex.serverdata.Region; +import mineplex.serverdata.data.DataRepository; +import mineplex.serverdata.data.PlayerStatus; +import mineplex.serverdata.redis.RedisDataRepository; +import mineplex.serverdata.servers.ServerManager; public class FriendRepository extends RepositoryBase { private static String CREATE_FRIEND_TABLE = "CREATE TABLE IF NOT EXISTS accountFriend (id INT NOT NULL AUTO_INCREMENT, uuidSource VARCHAR(100), uuidTarget VARCHAR(100), status VARCHAR(100), PRIMARY KEY (id), UNIQUE INDEX uuidIndex (uuidSource, uuidTarget));"; - private static String RETRIEVE_MULTIPLE_FRIEND_RECORDS = "SELECT uuidSource, tA.Name, status, serverName, tA.lastLogin, now() FROM accountFriend INNER Join accounts AS fA ON fA.uuid = uuidSource INNER JOIN accounts AS tA ON tA.uuid = uuidTarget LEFT JOIN playerMap ON tA.name = playerName WHERE uuidSource IN "; + private static String RETRIEVE_MULTIPLE_FRIEND_RECORDS = "SELECT uuidSource, tA.Name, status, tA.lastLogin, now() FROM accountFriend INNER Join accounts AS fA ON fA.uuid = uuidSource INNER JOIN accounts AS tA ON tA.uuid = uuidTarget WHERE uuidSource IN "; private static String ADD_FRIEND_RECORD = "INSERT INTO accountFriend (uuidSource, uuidTarget, status, created) SELECT fA.uuid AS uuidSource, tA.uuid AS uuidTarget, ?, now() FROM accounts as fA LEFT JOIN accounts AS tA ON tA.name = ? WHERE fA.name = ?;"; private static String UPDATE_MUTUAL_RECORD = "UPDATE accountFriend AS aF INNER JOIN accounts as fA ON aF.uuidSource = fA.uuid INNER JOIN accounts AS tA ON aF.uuidTarget = tA.uuid SET aF.status = ? WHERE tA.name = ? AND fA.name = ?;"; private static String DELETE_FRIEND_RECORD = "DELETE aF FROM accountFriend AS aF INNER JOIN accounts as fA ON aF.uuidSource = fA.uuid INNER JOIN accounts AS tA ON aF.uuidTarget = tA.uuid WHERE fA.name = ? AND tA.name = ?;"; + // Repository holding active PlayerStatus data. + private DataRepository _repository; + public FriendRepository(JavaPlugin plugin) { super(plugin, DBPool.ACCOUNT); + + _repository = new RedisDataRepository(ServerManager.getMasterConnection(), ServerManager.getSlaveConnection(), + Region.currentRegion(), PlayerStatus.class, "playerStatus"); } @Override @@ -81,29 +98,35 @@ public class FriendRepository extends RepositoryBase { public void processResultSet(ResultSet resultSet) throws SQLException { + Set friendDatas = new HashSet(); while (resultSet.next()) { FriendStatus friend = new FriendStatus(); String uuidSource = resultSet.getString(1); friend.Name = resultSet.getString(2); - friend.Status = Enum.valueOf(FriendStatusType.class, resultSet.getString(3)); - friend.ServerName = resultSet.getString(4); - friend.Online = !(friend.ServerName == null || friend.ServerName.isEmpty()); - - friend.LastSeenOnline = resultSet.getTimestamp(6).getTime() - resultSet.getTimestamp(5).getTime(); + friend.Status = Enum.valueOf(FriendStatusType.class, resultSet.getString(3)); + friend.LastSeenOnline = resultSet.getTimestamp(5).getTime() - resultSet.getTimestamp(4).getTime(); if (!friends.containsKey(uuidSource)) friends.put(uuidSource, new FriendData()); friends.get(uuidSource).getFriends().add(friend); + + friendDatas.add(friends.get(uuidSource)); + } + + // Load the server status of friends for all sources. + for(FriendData friendData : friendDatas) + { + loadFriendStatuses(friendData); } } }); return friends; } - + public FriendData loadClientInformation(ResultSet resultSet) throws SQLException { FriendData friendData = new FriendData(); @@ -114,12 +137,59 @@ public class FriendRepository extends RepositoryBase friend.Name = resultSet.getString(1); friend.Status = Enum.valueOf(FriendStatusType.class, resultSet.getString(2)); - friend.ServerName = resultSet.getString(3); - friend.LastSeenOnline = resultSet.getTimestamp(5).getTime() - resultSet.getTimestamp(4).getTime(); - + friend.LastSeenOnline = resultSet.getTimestamp(4).getTime() - resultSet.getTimestamp(3).getTime(); + friend.ServerName = null; + friend.Online = (friend.ServerName != null); friendData.getFriends().add(friend); } + + loadFriendStatuses(friendData); return friendData; } + + /** + * Load the server status information for a list of {@link FriendStatus}. + * @param friendData - the {@link FriendStatus} object friends server status' are to be updated + * @param statuses - the fetched {@link PlayerStatus} associated with all online {@code friends}. + */ + public void loadFriendStatuses(FriendData friendData) + { + // Generate a set of all friend names + Set friendNames = new HashSet(); + for(FriendStatus status : friendData.getFriends()) + { + friendNames.add(status.Name); + } + + // Load PlayerStatus' for friends + Collection statuses = _repository.getElements(friendNames); + + // Load player statuses into a mapping + Map playerStatuses = new HashMap(); + for(PlayerStatus status : statuses) + { + playerStatuses.put(status.getName(), status); + } + + // Load status information into friend data. + for (FriendStatus friend : friendData.getFriends()) + { + PlayerStatus status = playerStatuses.get(friend.Name); + friend.Online = (status != null); + friend.ServerName = (friend.Online) ? status.getServer() : null; + } + } + + /** + * @param playerName - the name of the player whose current server status is being fetched + * @return the {@link MinecraftServer} name that the player matching {@code playerName} + * is currently online on, if they are online, null otherwise. + */ + public String fetchPlayerServer(String playerName) + { + PlayerStatus status = _repository.getElement(playerName); + + return (status == null) ? null : status.getServer(); + } } diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Region.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Region.java index dda067632..5bc846b37 100644 --- a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Region.java +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/Region.java @@ -1,5 +1,7 @@ package mineplex.serverdata; +import java.io.File; + /** * Region enumerates the various geographical regions where Mineplex servers are * hosted. @@ -11,4 +13,12 @@ public enum Region US, EU, ALL; + + /** + * @return the geographical {@link Region} of the current running process. + */ + public static Region currentRegion() + { + return !new File("eu.dat").exists() ? Region.US : Region.EU; + } } diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/data/DataRepository.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/data/DataRepository.java index b7e71aa7c..fb9f9e7c4 100644 --- a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/data/DataRepository.java +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/data/DataRepository.java @@ -15,6 +15,8 @@ public interface DataRepository public Collection getElements(); public T getElement(String dataId); + + public Collection getElements(Collection dataIds); public void addElement(T element, int timeout); diff --git a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/RedisDataRepository.java b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/RedisDataRepository.java index f4b0fda9a..a49de5b64 100644 --- a/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/RedisDataRepository.java +++ b/Plugins/Mineplex.ServerData/src/mineplex/serverdata/redis/RedisDataRepository.java @@ -85,6 +85,12 @@ public class RedisDataRepository implements DataRepository @Override public Collection getElements() + { + return getElements(getActiveElements()); + } + + @Override + public Collection getElements(Collection dataIds) { Collection elements = new HashSet(); Jedis jedis = _readPool.getResource(); @@ -94,11 +100,12 @@ public class RedisDataRepository implements DataRepository Pipeline pipeline = jedis.pipelined(); List> responses = new ArrayList>(); - for (String dataId : getActiveElements()) + for (String dataId : dataIds) { responses.add(pipeline.get(generateKey(dataId))); } + // Block until all requests have received pipelined responses pipeline.sync(); for (Response response : responses) @@ -128,7 +135,7 @@ public class RedisDataRepository implements DataRepository return elements; } - + @Override public T getElement(String dataId) {