Convert friend system over to redis-based PlayerStatus data tracking from old SQL storage.

This commit is contained in:
Ty Sayers 2015-03-14 17:41:16 -04:00
parent c1c284002d
commit 7811279b26
7 changed files with 103 additions and 46 deletions

View File

@ -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;
}
}

View File

@ -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;

View File

@ -409,7 +409,7 @@ public class FriendManager extends MiniDbClientPlugin<FriendData>
@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 + "';";
}
}

View File

@ -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<PlayerStatus> _repository;
public FriendRepository(JavaPlugin plugin)
{
super(plugin, DBPool.ACCOUNT);
_repository = new RedisDataRepository<PlayerStatus>(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<FriendData> friendDatas = new HashSet<FriendData>();
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<String> friendNames = new HashSet<String>();
for(FriendStatus status : friendData.getFriends())
{
friendNames.add(status.Name);
}
// Load PlayerStatus' for friends
Collection<PlayerStatus> statuses = _repository.getElements(friendNames);
// Load player statuses into a mapping
Map<String, PlayerStatus> playerStatuses = new HashMap<String, PlayerStatus>();
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();
}
}

View File

@ -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;
}
}

View File

@ -15,6 +15,8 @@ public interface DataRepository<T extends Data>
public Collection<T> getElements();
public T getElement(String dataId);
public Collection<T> getElements(Collection<String> dataIds);
public void addElement(T element, int timeout);

View File

@ -85,6 +85,12 @@ public class RedisDataRepository<T extends Data> implements DataRepository<T>
@Override
public Collection<T> getElements()
{
return getElements(getActiveElements());
}
@Override
public Collection<T> getElements(Collection<String> dataIds)
{
Collection<T> elements = new HashSet<T>();
Jedis jedis = _readPool.getResource();
@ -94,11 +100,12 @@ public class RedisDataRepository<T extends Data> implements DataRepository<T>
Pipeline pipeline = jedis.pipelined();
List<Response<String>> responses = new ArrayList<Response<String>>();
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<String> response : responses)
@ -128,7 +135,7 @@ public class RedisDataRepository<T extends Data> implements DataRepository<T>
return elements;
}
@Override
public T getElement(String dataId)
{