Add new Mineplex.ServerData library for interfacing with the ServerRepository, and modify Mineplex.ServerMonitor, Mineplex.Bungee.Mineplexer and Mineplex.Core to integrate changes.

This commit is contained in:
Ty 2014-08-01 17:56:29 -04:00
parent d7037f1619
commit 6a9255e97b
44 changed files with 1381 additions and 1449 deletions

View File

@ -17,10 +17,12 @@
<fileset dir="../Mineplex.Minecraft.Game.Core/bin"> <fileset dir="../Mineplex.Minecraft.Game.Core/bin">
<include name="**/*.class"/> <include name="**/*.class"/>
</fileset> </fileset>
<fileset dir="../Nautilus.Game.Arcade"> <fileset dir="../Nautilus.Game.Arcade">
<include name="*.yml"/> <include name="*.yml"/>
</fileset> </fileset>
<fileset dir="../Mineplex.ServerData/bin">
<include name="**/*.class"/>
</fileset>
<zipfileset src="../Libraries/httpclient-4.2.jar" /> <zipfileset src="../Libraries/httpclient-4.2.jar" />
<zipfileset src="../Libraries/httpcore-4.2.jar" /> <zipfileset src="../Libraries/httpcore-4.2.jar" />
@ -29,6 +31,8 @@
<zipfileset src="../Libraries/gson-2.2.1.jar" /> <zipfileset src="../Libraries/gson-2.2.1.jar" />
<zipfileset src="../Libraries/commons-logging-1.1.1.jar" /> <zipfileset src="../Libraries/commons-logging-1.1.1.jar" />
<zipfileset src="../Libraries/commons-codec-1.6.jar" /> <zipfileset src="../Libraries/commons-codec-1.6.jar" />
<zipfileset src="../Libraries/jedis-2.4.2.jar" />
<zipfileset src="../Libraries/commons-pool2-2.2.jar" />
</jar> </jar>
<copy file="../bin/Arcade.jar" todir="../../Testing/Arcade/plugins"/> <copy file="../bin/Arcade.jar" todir="../../Testing/Arcade/plugins"/>
</target> </target>
@ -52,6 +56,9 @@
<fileset dir="../Mineplex.Hub"> <fileset dir="../Mineplex.Hub">
<include name="*.yml"/> <include name="*.yml"/>
</fileset> </fileset>
<fileset dir="../Mineplex.ServerData/bin">
<include name="**/*.class"/>
</fileset>
<zipfileset src="../Libraries/httpclient-4.2.jar" /> <zipfileset src="../Libraries/httpclient-4.2.jar" />
<zipfileset src="../Libraries/httpcore-4.2.jar" /> <zipfileset src="../Libraries/httpcore-4.2.jar" />
@ -61,6 +68,8 @@
<zipfileset src="../Libraries/commons-logging-1.1.1.jar" /> <zipfileset src="../Libraries/commons-logging-1.1.1.jar" />
<zipfileset src="../Libraries/commons-io-2.4.jar" /> <zipfileset src="../Libraries/commons-io-2.4.jar" />
<zipfileset src="../Libraries/commons-codec-1.6.jar" /> <zipfileset src="../Libraries/commons-codec-1.6.jar" />
<zipfileset src="../Libraries/jedis-2.4.2.jar" />
<zipfileset src="../Libraries/commons-pool2-2.2.jar" />
</jar> </jar>
<copy file="../bin/Hub.jar" todir="../../Testing/Hub/plugins"/> <copy file="../bin/Hub.jar" todir="../../Testing/Hub/plugins"/>
</target> </target>

Binary file not shown.

Binary file not shown.

View File

@ -5,5 +5,6 @@
<classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/BungeeCord.jar"/> <classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/BungeeCord.jar"/>
<classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/commons-codec-1.6.jar"/> <classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/commons-codec-1.6.jar"/>
<classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/commons-io-2.4.jar"/> <classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/commons-io-2.4.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/Mineplex.ServerData"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@ -3,10 +3,15 @@ package mineplex.bungee.lobbyBalancer;
import java.io.File; import java.io.File;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import mineplex.serverdata.MinecraftServer;
import mineplex.serverdata.Region;
import mineplex.serverdata.ServerManager;
import mineplex.serverdata.ServerRepository;
import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
@ -15,9 +20,9 @@ import net.md_5.bungee.event.EventHandler;
public class LobbyBalancer implements Listener, Runnable public class LobbyBalancer implements Listener, Runnable
{ {
private Plugin _plugin; private Plugin _plugin;
private LobbyBalancerRepository _repository; private ServerRepository _repository;
private List<ServerStatusData> _sortedLobbies = new ArrayList<ServerStatusData>(); private List<MinecraftServer> _sortedLobbies = new ArrayList<MinecraftServer>();
private static Object _serverLock = new Object(); private static Object _serverLock = new Object();
private int _bestServerIndex = 0; private int _bestServerIndex = 0;
@ -27,11 +32,9 @@ public class LobbyBalancer implements Listener, Runnable
public LobbyBalancer(Plugin plugin) public LobbyBalancer(Plugin plugin)
{ {
_plugin = plugin; _plugin = plugin;
_repository = new LobbyBalancerRepository();
boolean us = !new File("eu.dat").exists(); Region region = !new File("eu.dat").exists() ? Region.US : Region.EU;
_repository = ServerManager.getServerRepository(region);
_repository.initialize(us);
loadLobbyServers(); loadLobbyServers();
@ -56,7 +59,7 @@ public class LobbyBalancer implements Listener, Runnable
while (_bestServerIndex < _sortedLobbies.size()) while (_bestServerIndex < _sortedLobbies.size())
{ {
_bestServerIndex++; _bestServerIndex++;
_maxPlayersToSendToBestServer = (_sortedLobbies.get(_bestServerIndex).MaxPlayers - _sortedLobbies.get(_bestServerIndex).Players) / 10; _maxPlayersToSendToBestServer = (_sortedLobbies.get(_bestServerIndex).getMaxPlayerCount() - _sortedLobbies.get(_bestServerIndex).getPlayerCount()) / 10;
if (_maxPlayersToSendToBestServer > 0) if (_maxPlayersToSendToBestServer > 0)
break; break;
@ -68,14 +71,14 @@ public class LobbyBalancer implements Listener, Runnable
_maxPlayersToSendToBestServer = 1; _maxPlayersToSendToBestServer = 1;
// Since we had to enter our dangerzone, update local data so if we have to enter it again we don't pick the same server over and over // Since we had to enter our dangerzone, update local data so if we have to enter it again we don't pick the same server over and over
_sortedLobbies.get(_bestServerIndex).Players += 5; _sortedLobbies.get(_bestServerIndex).incrementPlayerCount(5);
sort = true; sort = true;
} }
} }
if (_bestServerIndex < _sortedLobbies.size()) if (_bestServerIndex < _sortedLobbies.size())
event.setTarget(_plugin.getProxy().getServerInfo(_sortedLobbies.get(_bestServerIndex).Name)); event.setTarget(_plugin.getProxy().getServerInfo(_sortedLobbies.get(_bestServerIndex).getName()));
_playersSentToBestServer++; _playersSentToBestServer++;
@ -92,25 +95,25 @@ public class LobbyBalancer implements Listener, Runnable
public void loadLobbyServers() public void loadLobbyServers()
{ {
List<ServerStatusData> serverStatusDataList = _repository.retrieveServerStatuses(); Collection<MinecraftServer> servers = _repository.getServerStatuses();
synchronized (_serverLock) synchronized (_serverLock)
{ {
_sortedLobbies.clear(); _sortedLobbies.clear();
for (ServerStatusData serverStatusData : serverStatusDataList) for (MinecraftServer server : servers)
{ {
if (serverStatusData.Name == null) if (server.getName() == null)
continue; continue;
InetSocketAddress socketAddress = new InetSocketAddress(serverStatusData.Address, serverStatusData.Port); InetSocketAddress socketAddress = new InetSocketAddress(server.getPublicAddress(), server.getPort());
_plugin.getProxy().getServers().put(serverStatusData.Name, _plugin.getProxy().constructServerInfo(serverStatusData.Name, socketAddress, "LobbyBalancer", false)); _plugin.getProxy().getServers().put(server.getName(), _plugin.getProxy().constructServerInfo(server.getName(), socketAddress, "LobbyBalancer", false));
if (serverStatusData.Name.toUpperCase().contains("LOBBY")) if (server.getName().toUpperCase().contains("LOBBY"))
{ {
if (serverStatusData.Motd == null || !serverStatusData.Motd.contains("Restarting")) if (server.getMotd() == null || !server.getMotd().contains("Restarting"))
{ {
_sortedLobbies.add(serverStatusData); _sortedLobbies.add(server);
} }
} }
} }
@ -121,7 +124,7 @@ public class LobbyBalancer implements Listener, Runnable
_bestServerIndex = 0; _bestServerIndex = 0;
if (_sortedLobbies.size() > 0) if (_sortedLobbies.size() > 0)
_maxPlayersToSendToBestServer = (_sortedLobbies.get(_bestServerIndex).MaxPlayers - _sortedLobbies.get(_bestServerIndex).Players) / 10; _maxPlayersToSendToBestServer = (_sortedLobbies.get(_bestServerIndex).getMaxPlayerCount() - _sortedLobbies.get(_bestServerIndex).getPlayerCount()) / 10;
} }
} }
} }

View File

@ -1,140 +0,0 @@
package mineplex.bungee.lobbyBalancer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
public class LobbyBalancerRepository
{
private Connection _connection = null;
private String _connectionString = "jdbc:mysql://db.mineplex.com:3306/ServerStatus?autoReconnect=true&failOverReadOnly=false&maxReconnects=10";
private String _userName = "root";
private String _password = "tAbechAk3wR7tuTh";
private boolean _us;
private static String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS ServerStatus (id INT NOT NULL AUTO_INCREMENT, serverName VARCHAR(256), serverGroup VARCHAR(256), address VARCHAR(256), port VARCHAR(11), updated LONG, motd VARCHAR(256), players INT, maxPlayers INT, tps INT, ram INT, maxRam INT, PRIMARY KEY (id));";
private static String RETRIEVE_SERVER_STATUSES = "SELECT ServerStatus.serverName, ServerStatus.address, ServerStatus.port, motd, players, maxPlayers, now(), updated FROM ServerStatus INNER JOIN DynamicServers ON ServerStatus.address = DynamicServers.privateAddress WHERE DynamicServers.US = ?;";
public void initialize(boolean us)
{
_us = us;
PreparedStatement preparedStatement = null;
try
{
if (_connection == null || _connection.isClosed())
_connection = DriverManager.getConnection(_connectionString, _userName, _password);
// Create table
preparedStatement = _connection.prepareStatement(CREATE_TABLE);
preparedStatement.execute();
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
System.out.println("Initialized LobbyBalancer.");
}
public List<ServerStatusData> retrieveServerStatuses()
{
ResultSet resultSet = null;
PreparedStatement preparedStatement = null;
List<ServerStatusData> serverData = new ArrayList<ServerStatusData>();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try
{
if (_connection == null || _connection.isClosed())
_connection = DriverManager.getConnection(_connectionString, _userName, _password);
preparedStatement = _connection.prepareStatement(RETRIEVE_SERVER_STATUSES);
preparedStatement.setBoolean(1, _us);
resultSet = preparedStatement.executeQuery();
while (resultSet.next())
{
ServerStatusData serverStatusData = new ServerStatusData();
serverStatusData.Name = resultSet.getString(1);
serverStatusData.Address = resultSet.getString(2);
serverStatusData.Port = Integer.parseInt(resultSet.getString(3));
serverStatusData.Motd = resultSet.getString(4);
serverStatusData.Players = resultSet.getInt(5);
serverStatusData.MaxPlayers = resultSet.getInt(6);
long current = dateFormat.parse(resultSet.getString(7)).getTime();
long updated = dateFormat.parse(resultSet.getString(8)).getTime();
if (current - updated < 10000)
serverData.add(serverStatusData);
}
}
catch (Exception exception)
{
exception.printStackTrace();
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return retrieveServerStatuses();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (resultSet != null)
{
try
{
resultSet.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
return serverData;
}
}

View File

@ -2,43 +2,45 @@ package mineplex.bungee.lobbyBalancer;
import java.util.Comparator; import java.util.Comparator;
public class LobbySorter implements Comparator<ServerStatusData> import mineplex.serverdata.MinecraftServer;
public class LobbySorter implements Comparator<MinecraftServer>
{ {
@Override @Override
public int compare(ServerStatusData first, ServerStatusData second) public int compare(MinecraftServer first, MinecraftServer second)
{ {
if (second.Players == 999) if (second.getPlayerCount() == 999)
return -1; return -1;
if (first.Players == 999) if (first.getPlayerCount() == 999)
return 1; return 1;
if (first.Players < (first.MaxPlayers / 2) && second.Players >= (second.MaxPlayers / 2)) if (first.getPlayerCount() < (first.getMaxPlayerCount() / 2) && second.getPlayerCount() >= (second.getMaxPlayerCount() / 2))
return -1; return -1;
if (second.Players < (second.MaxPlayers / 2) && first.Players >= (first.MaxPlayers / 2)) if (second.getPlayerCount() < (second.getMaxPlayerCount() / 2) && first.getPlayerCount() >= (first.getMaxPlayerCount() / 2))
return 1; return 1;
if (first.Players < (first.MaxPlayers / 2)) if (first.getPlayerCount() < (first.getMaxPlayerCount() / 2))
{ {
if (first.Players > second.Players) if (first.getPlayerCount() > second.getPlayerCount())
return -1; return -1;
if (second.Players > first.Players) if (second.getPlayerCount() > first.getPlayerCount())
return 1; return 1;
} }
else else
{ {
if (first.Players < second.Players) if (first.getPlayerCount() < second.getPlayerCount())
return -1; return -1;
if (second.Players < first.Players) if (second.getPlayerCount() < first.getPlayerCount())
return 1; return 1;
} }
if (Integer.parseInt(first.Name.split("-")[1]) < Integer.parseInt(second.Name.split("-")[1])) if (Integer.parseInt(first.getName().split("-")[1]) < Integer.parseInt(second.getName().split("-")[1]))
return -1; return -1;
else if (Integer.parseInt(second.Name.split("-")[1]) < Integer.parseInt(first.Name.split("-")[1])) else if (Integer.parseInt(second.getName().split("-")[1]) < Integer.parseInt(first.getName().split("-")[1]))
return 1; return 1;
return 0; return 0;

View File

@ -1,11 +0,0 @@
package mineplex.bungee.lobbyBalancer;
public class ServerStatusData
{
public String Name;
public String Motd;
public int Players;
public int MaxPlayers;
public String Address;
public int Port;
}

View File

@ -8,5 +8,6 @@
<classpathentry combineaccessrules="false" kind="src" path="/Nautilus.Core.CraftBukkit"/> <classpathentry combineaccessrules="false" kind="src" path="/Nautilus.Core.CraftBukkit"/>
<classpathentry kind="var" path="REPO_DIR/Plugins/bin/craftbukkit.jar"/> <classpathentry kind="var" path="REPO_DIR/Plugins/bin/craftbukkit.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/Mineplex.Core.Common"/> <classpathentry combineaccessrules="false" kind="src" path="/Mineplex.Core.Common"/>
<classpathentry combineaccessrules="false" kind="src" path="/Mineplex.ServerData"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@ -5,18 +5,14 @@ import java.sql.DriverManager;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import mineplex.core.common.util.NautHashMap; import mineplex.core.common.util.NautHashMap;
import mineplex.core.status.ServerStatusData; import mineplex.serverdata.Region;
import mineplex.serverdata.ServerManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.mysql.jdbc.exceptions.jdbc4.CommunicationsException;
public class PortalRepository public class PortalRepository
{ {
private static Object _connectionLock = new Object(); private static Object _connectionLock = new Object();
@ -32,10 +28,8 @@ public class PortalRepository
private static String RETRIEVE_TRANSFER_RECORDS = "SELECT playerName, serverName FROM playerServerTransfer WHERE playerName IN "; private static String RETRIEVE_TRANSFER_RECORDS = "SELECT playerName, serverName FROM playerServerTransfer WHERE playerName IN ";
private static String DELETE_TRANSFER_RECORDS = "DELETE FROM playerServerTransfer WHERE playerName = ?;"; private static String DELETE_TRANSFER_RECORDS = "DELETE FROM playerServerTransfer WHERE playerName = ?;";
private static String ADD_TRANSFER_RECORD = "INSERT INTO playerServerTransfer (playerName,serverName) VALUES(?,?);"; private static String ADD_TRANSFER_RECORD = "INSERT INTO playerServerTransfer (playerName,serverName) VALUES(?,?);";
private static String RETRIEVE_SERVER_STATUSES = "SELECT ServerStatus.serverName, motd, players, maxPlayers, now(), updated FROM ServerStatus INNER JOIN DynamicServers ON ServerStatus.address = DynamicServers.privateAddress WHERE DynamicServers.US = ? AND ServerStatus.serverName = ?;";
private Connection _connection = null; private Connection _connection = null;
private Connection _altConnection = null;
public void initialize(boolean us, String altConnectString) public void initialize(boolean us, String altConnectString)
{ {
@ -226,74 +220,8 @@ public class PortalRepository
public boolean doesServerExist(String serverName) public boolean doesServerExist(String serverName)
{ {
ResultSet resultSet = null; Region region = _us ? Region.US : Region.EU;
PreparedStatement preparedStatement = null; return ServerManager.getServerRepository(region).serverExists(serverName);
List<ServerStatusData> serverData = new ArrayList<ServerStatusData>();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try
{
if (_altConnection == null || _altConnection.isClosed())
{
_altConnection = DriverManager.getConnection(_altConnectString, _userName, _password);
}
preparedStatement = _altConnection.prepareStatement(RETRIEVE_SERVER_STATUSES);
preparedStatement.setBoolean(1, _us);
preparedStatement.setString(2, serverName);
resultSet = preparedStatement.executeQuery();
while (resultSet.next())
{
ServerStatusData serverStatusData = new ServerStatusData();
serverStatusData.Name = resultSet.getString(1);
serverStatusData.Motd = resultSet.getString(2);
serverStatusData.Players = resultSet.getInt(3);
serverStatusData.MaxPlayers = resultSet.getInt(4);
long current = dateFormat.parse(resultSet.getString(5)).getTime();
long updated = dateFormat.parse(resultSet.getString(6)).getTime();
if (current - updated < 15000)
serverData.add(serverStatusData);
}
}
catch (CommunicationsException exception)
{
return doesServerExist(serverName);
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (resultSet != null)
{
try
{
resultSet.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
return !serverData.isEmpty();
} }
} }

View File

@ -1,9 +0,0 @@
package mineplex.core.status;
public class ServerStatusData
{
public String Name;
public String Motd;
public int Players;
public int MaxPlayers;
}

View File

@ -1,6 +1,7 @@
package mineplex.core.status; package mineplex.core.status;
import java.io.File; import java.io.File;
import java.util.Collection;
import java.util.List; import java.util.List;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -13,10 +14,17 @@ import mineplex.core.common.util.Callback;
import mineplex.core.monitor.LagMeter; import mineplex.core.monitor.LagMeter;
import mineplex.core.updater.UpdateType; import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent; import mineplex.core.updater.event.UpdateEvent;
import mineplex.serverdata.MinecraftServer;
import mineplex.serverdata.Region;
import mineplex.serverdata.ServerManager;
import mineplex.serverdata.ServerRepository;
public class ServerStatusManager extends MiniPlugin public class ServerStatusManager extends MiniPlugin
{ {
private ServerStatusRepository _repository; // The default timeout (in milliseconds) before the ServerStatus expires.
public final int DEFAULT_SERVER_TIMEOUT = 15000;
private ServerRepository _repository;
private LagMeter _lagMeter; private LagMeter _lagMeter;
private String _name; private String _name;
@ -45,27 +53,8 @@ public class ServerStatusManager extends MiniPlugin
_name = plugin.getConfig().getString("serverstatus.name"); _name = plugin.getConfig().getString("serverstatus.name");
_us = plugin.getConfig().getBoolean("serverstatus.us"); _us = plugin.getConfig().getBoolean("serverstatus.us");
try Region region = _us ? Region.US : Region.EU;
{ _repository = ServerManager.getServerRepository(region);
_repository = new ServerStatusRepository(
plugin.getConfig().getString("serverstatus.connectionurl"),
plugin.getConfig().getString("serverstatus.username"),
plugin.getConfig().getString("serverstatus.password"),
_us,
_name,
plugin.getConfig().getString("serverstatus.group"),
address,
_plugin.getServer().getPort() + "",
event.getMaxPlayers()
);
if (_enabled)
_repository.initialize();
}
catch (Exception ex)
{
ex.printStackTrace();
}
} }
private void setupConfigValues() private void setupConfigValues()
@ -98,7 +87,7 @@ public class ServerStatusManager extends MiniPlugin
} }
} }
public void retrieveServerStatuses(final Callback<List<ServerStatusData>> callback) public void retrieveServerStatuses(final Callback<Collection<MinecraftServer>> callback)
{ {
if (!_enabled) if (!_enabled)
return; return;
@ -109,7 +98,7 @@ public class ServerStatusManager extends MiniPlugin
{ {
if (callback != null) if (callback != null)
{ {
callback.run(_repository.retrieveServerStatuses()); callback.run(_repository.getServerStatuses());
} }
} }
}); });
@ -128,19 +117,48 @@ public class ServerStatusManager extends MiniPlugin
if (!_alternateSeconds) if (!_alternateSeconds)
return; return;
final ServerListPingEvent listPingEvent = new ServerListPingEvent(null, GetPlugin().getServer().getMotd(), GetPlugin().getServer().getOnlinePlayers().length, GetPlugin().getServer().getMaxPlayers()); saveServerStatus();
}
GetPluginManager().callEvent(listPingEvent);
/**
* Save the current {@link MinecraftServer} snapshot of this server to
* the {@link ServerRepository}.
*/
private void saveServerStatus()
{
final MinecraftServer serverSnapshot = generateServerSnapshot();
GetPlugin().getServer().getScheduler().runTaskAsynchronously(GetPlugin(), new Runnable() GetPlugin().getServer().getScheduler().runTaskAsynchronously(GetPlugin(), new Runnable()
{ {
public void run() public void run()
{ {
_repository.updatePlayerCountInDatabase(listPingEvent.getMotd(), Bukkit.getOnlinePlayers().length, listPingEvent.getMaxPlayers(), (int)_lagMeter.getTicksPerSecond()); _repository.updataServerStatus(serverSnapshot, 15000);
} }
}); });
} }
/**
* @return a newly instanced {@link MinecraftServer} snapshot that represents the
* current internal state of this minecraft server.
*/
private MinecraftServer generateServerSnapshot()
{
ServerListPingEvent event = new ServerListPingEvent(null, GetPlugin().getServer().getMotd(), GetPlugin().getServer().getOnlinePlayers().length, GetPlugin().getServer().getMaxPlayers());
GetPluginManager().callEvent(event);
String motd = event.getMotd();
int playerCount = Bukkit.getOnlinePlayers().length;
int maxPlayerCount = event.getMaxPlayers();
int tps = (int) _lagMeter.getTicksPerSecond();
String address = Bukkit.getServer().getIp().isEmpty() ? "localhost" : Bukkit.getServer().getIp();
int port = _plugin.getServer().getPort();
String group = _plugin.getConfig().getString("serverstatus.group");
int ram = (int) ((Runtime.getRuntime().maxMemory() - Runtime.getRuntime().freeMemory()) / 1048576);
int maxRam = (int) (Runtime.getRuntime().maxMemory() / 1048576);
return new MinecraftServer(_name, group, motd, address, port, playerCount,
maxPlayerCount, tps, ram, maxRam);
}
public String getCurrentServerName() public String getCurrentServerName()
{ {

View File

@ -1,286 +0,0 @@
package mineplex.core.status;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
public class ServerStatusRepository
{
private String _connectionString;
private String _userName;
private String _password;
private static String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS ServerStatus (id INT NOT NULL AUTO_INCREMENT, serverName VARCHAR(256), serverGroup VARCHAR(256), address VARCHAR(256), updated LONG, lastTimeWithPlayers LONG, motd VARCHAR(256), players INT, maxPlayers INT, tps INT, ram INT, maxRam INT, PRIMARY KEY (id));";
private static String INSERT_PLAYER_COUNT = "INSERT INTO ServerStatus (serverName, serverGroup, address, port, updated, motd, players, maxPlayers, tps, ram, maxRam) values(?, ?, ?, ?, now(), 'Configuring server.', ?, ?, 0, ?, ?);";
private static String UPDATE_PLAYER_COUNT_WITH_PLAYERS = "UPDATE ServerStatus SET updated = now(), serverName = ?, serverGroup = ?, motd = ?, players = ?, maxPlayers = ?, tps = ?, ram = ?, maxRam = ?, lastTimeWithPlayers = now() WHERE id = ?;";
private static String UPDATE_PLAYER_COUNT_WITHOUT_PLAYERS = "UPDATE ServerStatus SET updated = now(), serverName = ?, serverGroup = ?, motd = ?, players = ?, maxPlayers = ?, tps = ?, ram = ?, maxRam = ? WHERE id = ?;";
private static String RETRIEVE_ID = "SELECT id FROM ServerStatus WHERE address = ? AND port = ?;";
private static String RETRIEVE_SERVER_STATUSES = "SELECT ServerStatus.serverName, motd, players, maxPlayers, now(), updated FROM ServerStatus INNER JOIN DynamicServers ON ServerStatus.address = DynamicServers.privateAddress WHERE DynamicServers.US = ?";
private int _id = -1;
private boolean _us;
private String _serverName;
private String _serverGroup;
private String _address;
private String _port;
private int _maxPlayers = 0;
Connection _connection = null;
public ServerStatusRepository(String connectionUrl, String username, String password, boolean us, String serverName, String serverGroup, String address, String port, int maxPlayers)
{
_connectionString = connectionUrl;
_userName = username;
_password = password;
_us = us;
_serverName = serverName;
_serverGroup = serverGroup;
_address = address;
_port = port;
_maxPlayers = maxPlayers;
}
public void initialize()
{
ResultSet resultSet = null;
PreparedStatement preparedStatement = null;
PreparedStatement preparedStatementRetrieve = null;
PreparedStatement preparedStatementInsert = null;
try
{
_connection = DriverManager.getConnection(_connectionString, _userName, _password);
// Create table
preparedStatement = _connection.prepareStatement(CREATE_TABLE);
preparedStatement.execute();
// Retrieve id
preparedStatementRetrieve = _connection.prepareStatement(RETRIEVE_ID);
preparedStatementRetrieve.setString(1, _address);
preparedStatementRetrieve.setString(2, _port);
resultSet = preparedStatementRetrieve.executeQuery();
while (resultSet.next())
{
_id = resultSet.getInt("id");
}
// Insert if not there
if (_id == -1)
{
preparedStatementInsert = _connection.prepareStatement(INSERT_PLAYER_COUNT, Statement.RETURN_GENERATED_KEYS);
preparedStatementInsert.setString(1, _serverName);
preparedStatementInsert.setString(2, _serverGroup);
preparedStatementInsert.setString(3, _address);
preparedStatementInsert.setString(4, _port);
preparedStatementInsert.setInt(5, 0);
preparedStatementInsert.setInt(6, _maxPlayers);
preparedStatementInsert.setInt(7, (int) ((Runtime.getRuntime().maxMemory() - Runtime.getRuntime().freeMemory()) / 1048576));
preparedStatementInsert.setInt(8, (int) (Runtime.getRuntime().maxMemory() / 1048576));
int affectedRows = preparedStatementInsert.executeUpdate();
if (affectedRows == 0)
{
throw new SQLException("Creating server status failed, no rows affected.");
}
resultSet.close();
resultSet = preparedStatementInsert.getGeneratedKeys();
if (resultSet.next())
{
_id = resultSet.getInt(1);
}
}
// Update stoof
updatePlayerCountInDatabase("Configuring server.", 0, _maxPlayers, 20);
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (preparedStatementRetrieve != null)
{
try
{
preparedStatementRetrieve.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (preparedStatementInsert != null)
{
try
{
preparedStatementInsert.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (resultSet != null)
{
try
{
resultSet.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
}
public boolean updatePlayerCountInDatabase(String motd, int players, int maxPlayers, int tps)
{
PreparedStatement preparedStatement = null;
try
{
if (_connection.isClosed())
{
_connection = DriverManager.getConnection(_connectionString, _userName, _password);
}
preparedStatement = _connection.prepareStatement(players != 0 ? UPDATE_PLAYER_COUNT_WITH_PLAYERS : UPDATE_PLAYER_COUNT_WITHOUT_PLAYERS, Statement.RETURN_GENERATED_KEYS);
preparedStatement.setString(1, _serverName);
preparedStatement.setString(2, _serverGroup);
preparedStatement.setString(3, motd);
preparedStatement.setInt(4, players);
preparedStatement.setInt(5, maxPlayers);
preparedStatement.setInt(6, tps);
preparedStatement.setInt(7, (int) ((Runtime.getRuntime().maxMemory() - Runtime.getRuntime().freeMemory()) / 1048576));
preparedStatement.setInt(8, (int) (Runtime.getRuntime().maxMemory() / 1048576));
preparedStatement.setInt(9, _id);
int affectedRows = preparedStatement.executeUpdate();
if (affectedRows == 0)
{
throw new SQLException("Updating server status failed, no rows affected.");
}
return true;
}
catch (Exception exception)
{
exception.printStackTrace();
return false;
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
}
public List<ServerStatusData> retrieveServerStatuses()
{
ResultSet resultSet = null;
PreparedStatement preparedStatement = null;
List<ServerStatusData> serverData = new ArrayList<ServerStatusData>();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try
{
if (_connection.isClosed())
{
_connection = DriverManager.getConnection(_connectionString, _userName, _password);
}
preparedStatement = _connection.prepareStatement(RETRIEVE_SERVER_STATUSES);
preparedStatement.setBoolean(1, _us);
resultSet = preparedStatement.executeQuery();
while (resultSet.next())
{
ServerStatusData serverStatusData = new ServerStatusData();
serverStatusData.Name = resultSet.getString(1);
serverStatusData.Motd = resultSet.getString(2);
serverStatusData.Players = resultSet.getInt(3);
serverStatusData.MaxPlayers = resultSet.getInt(4);
long current = dateFormat.parse(resultSet.getString(5)).getTime();
long updated = dateFormat.parse(resultSet.getString(6)).getTime();
if (current - updated < 10000)
serverData.add(serverStatusData);
}
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (resultSet != null)
{
try
{
resultSet.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
return serverData;
}
}

View File

@ -10,5 +10,5 @@
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${BUILD_FILES}/EnjinTranslator.xml"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${BUILD_FILES}/EnjinTranslator.xml"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/> <booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/EnjinTranslator}"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${${build_files}:/EnjinTranslator}"/>
</launchConfiguration> </launchConfiguration>

View File

@ -10,5 +10,6 @@
<classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/commons-codec-1.6.jar"/> <classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/commons-codec-1.6.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/Mineplex.Core.Common"/> <classpathentry combineaccessrules="false" kind="src" path="/Mineplex.Core.Common"/>
<classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/commons-io-2.4.jar"/> <classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/commons-io-2.4.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/Mineplex.ServerData"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@ -62,7 +62,7 @@ public class Hub extends JavaPlugin implements IRelation
getConfig().addDefault(WEB_CONFIG, "http://accounts.mineplex.com/"); getConfig().addDefault(WEB_CONFIG, "http://accounts.mineplex.com/");
getConfig().set(WEB_CONFIG, getConfig().getString(WEB_CONFIG)); getConfig().set(WEB_CONFIG, getConfig().getString(WEB_CONFIG));
saveConfig(); saveConfig();
String webServerAddress = getConfig().getString(WEB_CONFIG); String webServerAddress = getConfig().getString(WEB_CONFIG);
Logger.initialize(this); Logger.initialize(this);
@ -87,7 +87,7 @@ public class Hub extends JavaPlugin implements IRelation
NpcManager npcManager = new NpcManager(this, creature); NpcManager npcManager = new NpcManager(this, creature);
PetManager petManager = new PetManager(this, clientManager, donationManager, creature, webServerAddress); PetManager petManager = new PetManager(this, clientManager, donationManager, creature, webServerAddress);
new AntiStack(this); new AntiStack(this);
//Main Modules //Main Modules
ServerStatusManager serverStatusManager = new ServerStatusManager(this, new LagMeter(this, clientManager)); ServerStatusManager serverStatusManager = new ServerStatusManager(this, new LagMeter(this, clientManager));
PacketHandler packetHandler = new PacketHandler(this); PacketHandler packetHandler = new PacketHandler(this);
@ -97,9 +97,9 @@ public class Hub extends JavaPlugin implements IRelation
AntiHack.Initialize(this, punish, portal); AntiHack.Initialize(this, punish, portal);
HubManager hubManager = new HubManager(this, new BlockRestore(this), clientManager, donationManager, new ConditionManager(this), new DisguiseManager(this, packetHandler), new TaskManager(this, webServerAddress), portal, partyManager, preferenceManager, petManager); HubManager hubManager = new HubManager(this, new BlockRestore(this), clientManager, donationManager, new ConditionManager(this), new DisguiseManager(this, packetHandler), new TaskManager(this, webServerAddress), portal, partyManager, preferenceManager, petManager);
new PlayerTracker(this, serverStatusManager.getCurrentServerName(), serverStatusManager.getUs()); new PlayerTracker(this, serverStatusManager.getCurrentServerName(), serverStatusManager.getUs());
QueueManager queueManager = new QueueManager(this, clientManager, donationManager, new EloManager(this), partyManager); QueueManager queueManager = new QueueManager(this, clientManager, donationManager, new EloManager(this), partyManager);
new ServerManager(this, clientManager, donationManager, portal, partyManager, serverStatusManager, hubManager, new StackerManager(hubManager), queueManager); new ServerManager(this, clientManager, donationManager, portal, partyManager, serverStatusManager, hubManager, new StackerManager(hubManager), queueManager);
new Chat(this, clientManager, preferenceManager, serverStatusManager.getCurrentServerName()); new Chat(this, clientManager, preferenceManager, serverStatusManager.getCurrentServerName());
new MemoryFix(this); new MemoryFix(this);

View File

@ -10,7 +10,7 @@ public class HubClient
public String PurchaseString = " Purchase Ultra Rank at mineplex.com to unlock all game benefits!"; public String PurchaseString = " Purchase Ultra Rank at mineplex.com to unlock all game benefits!";
public int PurchaseIndex = 0; public int PurchaseIndex = 0;
public String UltraString = " Thank you for your support!"; public String UltraString = " Thank you for your support!";
public int UltraIndex = 0; public int UltraIndex = 0;

View File

@ -11,8 +11,6 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import mineplex.core.common.util.NautHashMap; import mineplex.core.common.util.NautHashMap;
import mineplex.core.status.ServerStatusData;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;

View File

@ -46,7 +46,6 @@ import mineplex.core.logger.Logger;
import mineplex.core.portal.Portal; import mineplex.core.portal.Portal;
import mineplex.core.recharge.Recharge; import mineplex.core.recharge.Recharge;
import mineplex.core.shop.ShopBase; import mineplex.core.shop.ShopBase;
import mineplex.core.status.ServerStatusData;
import mineplex.core.status.ServerStatusManager; import mineplex.core.status.ServerStatusManager;
import mineplex.core.updater.UpdateType; import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent; import mineplex.core.updater.event.UpdateEvent;
@ -59,6 +58,7 @@ import mineplex.hub.queue.ui.QueueShop;
import mineplex.hub.server.ui.LobbyShop; import mineplex.hub.server.ui.LobbyShop;
import mineplex.hub.server.ui.QuickShop; import mineplex.hub.server.ui.QuickShop;
import mineplex.hub.server.ui.ServerNpcShop; import mineplex.hub.server.ui.ServerNpcShop;
import mineplex.serverdata.MinecraftServer;
public class ServerManager extends MiniPlugin public class ServerManager extends MiniPlugin
{ {
@ -326,26 +326,26 @@ public class ServerManager extends MiniPlugin
_retrieving = true; _retrieving = true;
_statusManager.retrieveServerStatuses(new Callback<List<ServerStatusData>>() _statusManager.retrieveServerStatuses(new Callback<Collection<MinecraftServer>>()
{ {
public void run(List<ServerStatusData> serverStatusList) public void run(Collection<MinecraftServer> serverStatusList)
{ {
for (ServerStatusData serverStatus : serverStatusList) for (MinecraftServer serverStatus : serverStatusList)
{ {
if (!_serverInfoMap.containsKey(serverStatus.Name)) if (!_serverInfoMap.containsKey(serverStatus.getName()))
{ {
ServerInfo newServerInfo = new ServerInfo(); ServerInfo newServerInfo = new ServerInfo();
newServerInfo.Name = serverStatus.Name; newServerInfo.Name = serverStatus.getName();
_serverInfoMap.put(serverStatus.Name, newServerInfo); _serverInfoMap.put(serverStatus.getName(), newServerInfo);
} }
String[] args = serverStatus.Motd.split("\\|"); String[] args = serverStatus.getMotd().split("\\|");
String tag = (serverStatus.Name != null && serverStatus.Name.contains("-")) ? serverStatus.Name.split("-")[0] : "N/A"; String tag = (serverStatus.getName() != null && serverStatus.getName().contains("-")) ? serverStatus.getName().split("-")[0] : "N/A";
ServerInfo serverInfo = _serverInfoMap.get(serverStatus.Name); ServerInfo serverInfo = _serverInfoMap.get(serverStatus.getName());
serverInfo.MOTD = args.length > 0 ? args[0] : serverStatus.Motd; serverInfo.MOTD = args.length > 0 ? args[0] : serverStatus.getMotd();
serverInfo.CurrentPlayers = serverStatus.Players; serverInfo.CurrentPlayers = serverStatus.getPlayerCount();
serverInfo.MaxPlayers = serverStatus.MaxPlayers; serverInfo.MaxPlayers = serverStatus.getMaxPlayerCount();
if (args.length > 1) if (args.length > 1)
serverInfo.ServerType = args[1]; serverInfo.ServerType = args[1];
@ -356,7 +356,7 @@ public class ServerManager extends MiniPlugin
if (args.length > 3) if (args.length > 3)
serverInfo.Map = args[3]; serverInfo.Map = args[3];
_serverUpdate.put(serverStatus.Name, System.currentTimeMillis()); _serverUpdate.put(serverStatus.getName(), System.currentTimeMillis());
if (_serverKeyTagMap.containsKey(tag)) if (_serverKeyTagMap.containsKey(tag))
{ {

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jre7"/>
<classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/jedis-2.4.2.jar"/>
<classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/commons-pool2-2.2.jar"/>
<classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/gson-2.2.1.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AFTER_CLEAN_TARGETS" value="ServerMonitor,"/>
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AUTO_TARGETS" value="ServerMonitor,"/>
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_MANUAL_TARGETS" value="ServerMonitor,"/>
<booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/>
<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${project}"/>
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value=""/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${BUILD_FILES}/common.xml"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Mineplex.ServerMonitor}"/>
</launchConfiguration>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AFTER_CLEAN_TARGETS" value="ServerData,"/>
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AUTO_TARGETS" value="ServerData,"/>
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_MANUAL_TARGETS" value="ServerData,"/>
<booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/>
<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${resource}"/>
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value=""/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${BUILD_FILES}/common.xml"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Mineplex.ServerData}"/>
</launchConfiguration>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Mineplex.ServerData</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>auto,full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/ServerData.launch</value>
</dictionary>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="EclipseModuleManager">
<varelement var="file://$REPO_DIR$/Plugins/Plugins/Libraries/gson-2.2.1.jar" value="REPO_DIR/Plugins/Libraries/gson-2.2.1.jar" />
<varelement var="file://$REPO_DIR$/Plugins/Plugins/Libraries/httpclient-4.2.jar" value="REPO_DIR/Plugins/Libraries/httpclient-4.2.jar" />
<varelement var="file://$REPO_DIR$/Plugins/Plugins/Libraries/httpcore-4.2.jar" value="REPO_DIR/Plugins/Libraries/httpcore-4.2.jar" />
<src_description expected_position="0">
<src_folder value="file://$MODULE_DIR$/src" expected_position="0" />
</src_description>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/bin" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="jdk" jdkName="1.7" jdkType="JavaSDK" />
<orderEntry type="module-library">
<library name="gson-2.2.1.jar">
<CLASSES>
<root url="file://$REPO_DIR$/Plugins/Plugins/Libraries/gson-2.2.1.jar" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module" module-name="Mineplex.Core.Common" />
<orderEntry type="module-library">
<library name="httpclient-4.2.jar">
<CLASSES>
<root url="file://$REPO_DIR$/Plugins/Plugins/Libraries/httpclient-4.2.jar" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library">
<library name="httpcore-4.2.jar">
<CLASSES>
<root url="file://$REPO_DIR$/Plugins/Plugins/Libraries/httpcore-4.2.jar" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component>
</module>

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- WARNING: Eclipse auto-generated file.
Any modifications will be overwritten.
To include a user specific buildfile here, simply create one in the same
directory with the processing instruction <?eclipse.ant.import?>
as the first entry and export the buildfile again. --><project basedir="." default="build" name="Mineplex.ServerData">
<property environment="env"/>
<property name="REPO_DIR" value="../../"/>
<property name="Mineplex.Bungee.Mineplexer.location" value="../Mineplex.Bungee.Mineplexer"/>
<property name="Mineplex.Core.location" value="../Mineplex.Core"/>
<property name="Mineplex.ServerMonitor.location" value="../Mineplex.ServerMonitor"/>
<property name="ECLIPSE_HOME" value="../../../eclipse/"/>
<property name="debuglevel" value="source,lines,vars"/>
<property name="target" value="1.7"/>
<property name="source" value="1.7"/>
<path id="Mineplex.ServerData.classpath">
<pathelement location="bin"/>
<pathelement location="${REPO_DIR}/Plugins/Libraries/jedis-2.4.2.jar"/>
<pathelement location="${REPO_DIR}/Plugins/Libraries/commons-pool2-2.2.jar"/>
<pathelement location="${REPO_DIR}/Plugins/Libraries/gson-2.2.1.jar"/>
</path>
<target name="init">
<mkdir dir="bin"/>
<copy includeemptydirs="false" todir="bin">
<fileset dir="src">
<exclude name="**/*.java"/>
</fileset>
</copy>
</target>
<target name="clean">
<delete dir="bin"/>
</target>
<target depends="clean" name="cleanall"/>
<target depends="build-subprojects,build-project" name="build"/>
<target name="build-subprojects"/>
<target depends="init" name="build-project">
<echo message="${ant.project.name}: ${ant.file}"/>
<javac debug="true" debuglevel="${debuglevel}" destdir="bin" includeantruntime="false" source="${source}" target="${target}">
<src path="src"/>
<classpath refid="Mineplex.ServerData.classpath"/>
</javac>
</target>
<target description="Build all projects which reference this project. Useful to propagate changes." name="build-refprojects">
<ant antfile="build.xml" dir="${Mineplex.Bungee.Mineplexer.location}" inheritAll="false" target="clean"/>
<ant antfile="build.xml" dir="${Mineplex.Bungee.Mineplexer.location}" inheritAll="false" target="build">
<propertyset>
<propertyref name="build.compiler"/>
</propertyset>
</ant>
<ant antfile="build.xml" dir="${Mineplex.Core.location}" inheritAll="false" target="clean"/>
<ant antfile="build.xml" dir="${Mineplex.Core.location}" inheritAll="false" target="build">
<propertyset>
<propertyref name="build.compiler"/>
</propertyset>
</ant>
<ant antfile="build.xml" dir="${Mineplex.ServerMonitor.location}" inheritAll="false" target="clean"/>
<ant antfile="build.xml" dir="${Mineplex.ServerMonitor.location}" inheritAll="false" target="build">
<propertyset>
<propertyref name="build.compiler"/>
</propertyset>
</ant>
</target>
<target description="copy Eclipse compiler jars to ant lib directory" name="init-eclipse-compiler">
<copy todir="${ant.library.dir}">
<fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/>
</copy>
<unzip dest="${ant.library.dir}">
<patternset includes="jdtCompilerAdapter.jar"/>
<fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/>
</unzip>
</target>
<target description="compile project with Eclipse compiler" name="build-eclipse-compiler">
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
<antcall target="build"/>
</target>
</project>

View File

@ -0,0 +1,99 @@
package mineplex.serverdata;
import java.util.HashMap;
import java.util.Map;
public class DedicatedServer
{
// The default amount of available CPU usage.
public static final int DEFAULT_CPU = 32;
// The default amount of available ram usage.
public static final int DEFAULT_RAM = 14000;
// The unique name representing this server
private String _name;
public String getName() { return _name; }
// The public I.P address used to connect to this server
private String _publicAddress;
public String getPublicAddress() { return _publicAddress; }
// The private I.P address of this server
private String _privateAddress;
public String getPrivateAddress() { return _privateAddress; }
// The geographical region that this dedicated server is located in
private Region _region;
public Region getRegion() { return _region; }
public boolean isUsRegion() { return _region == Region.US; }
// The amount of available CPU usage on this server box.
private int _availableCpu;
public int getAvailableCpu() { return _availableCpu; }
// The amount of available ram usage on this server box.
private int _availableRam;
public int getAvailableRam() { return _availableRam; }
// A mapping of server group names (Key) to the number of server instances (Value)
private Map<String, Integer> _serverCounts;
/**
* Class constructor
* @param data - the set of serialized data values representing
* the internal state of this DedicatedServer.
*/
public DedicatedServer(Map<String, String> data)
{
this._name = data.get("name");
this._publicAddress = data.get("publicAddress");
this._privateAddress = data.get("privateAddress");
this._region = Region.valueOf(data.get("region").toUpperCase());
this._availableCpu = Integer.valueOf(data.get("cpu"));
this._availableRam = Integer.valueOf(data.get("ram"));
this._serverCounts = new HashMap<String, Integer>();
}
/**
* Set the number of {@link MinecraftServer} instances on this server
* for a specific {@link ServerGroup} type.
* @param serverGroup - the {@link ServerGroup} whose server instance count is being set.
* @param serverCount - the number of {@link MinecraftServer} instances active on this server.
*/
public void setServerCount(ServerGroup serverGroup, int serverCount)
{
if (_serverCounts.containsKey(serverGroup.getName()))
{
int currentAmount = _serverCounts.get(serverGroup.getName());
this._availableCpu += serverGroup.getRequiredCpu() * currentAmount;
this._availableRam += serverGroup.getRequiredRam() * currentAmount;
}
_serverCounts.put(serverGroup.getName(), serverCount);
this._availableCpu -= serverGroup.getRequiredCpu() * serverCount;
this._availableRam -= serverGroup.getRequiredRam() * serverCount;
}
/**
* @param serverGroup - the server group whose server count on this dedicated server is being fetched.
* @return the number of active {@link MinecraftServer}s on this dedicated server
* that belong to {@code serverGroup}.
*/
public int getServerCount(ServerGroup serverGroup)
{
String groupName = serverGroup.getName();
return _serverCounts.containsKey(groupName) ? _serverCounts.get(groupName) : 0;
}
/**
* Increment the number of {@link MinecraftServer} instances on this server
* for a specific {@link ServerGroup} type by 1.
* @param serverGroup - the {@link ServerGroup} whose server instance count is being incremented
*/
public void incrementServerCount(ServerGroup serverGroup)
{
setServerCount(serverGroup, getServerCount(serverGroup) + 1);
}
}

View File

@ -0,0 +1,18 @@
package mineplex.serverdata;
import java.util.Comparator;
public class DedicatedServerSorter implements Comparator<DedicatedServer>
{
@Override
public int compare(DedicatedServer first, DedicatedServer second)
{
if (second.getAvailableRam() <= 1024) return -1;
else if (first.getAvailableRam() <= 1024) return 1;
else if (first.getAvailableRam() > second.getAvailableRam()) return -1;
else if (second.getAvailableRam() > first.getAvailableRam()) return 1;
else if (first.getAvailableCpu() > second.getAvailableCpu()) return -1;
else if (second.getAvailableCpu() > first.getAvailableCpu()) return 1;
else return 0;
}
}

View File

@ -0,0 +1,105 @@
package mineplex.serverdata;
/**
* A MinecraftServer represents a snapshot of the internal
* state of an active Minecraft host server.
* @author Ty
*
*/
public class MinecraftServer
{
// The name of this server.
private String _name;
public String getName() { return _name; }
// The ServerGroup that this MinecraftServer belongs to.
private String _group;
public String getGroup() { return _group; }
// The current message of the day (MOTD) of the server.
private String _motd;
public String getMotd() { return _motd; }
// The number of players currently online.
private int _playerCount;
public int getPlayerCount() { return _playerCount; }
public void incrementPlayerCount(int amount) { this._playerCount += amount; }
// The maximum number of players allowed on the server.
private int _maxPlayerCount;
public int getMaxPlayerCount() { return _maxPlayerCount; }
// The ticks per second (TPS) of the server.
private int _tps;
public int getTps() { return _tps; }
// The current amount of RAM allocated to the server.
private int _ram;
public int getRam() { return _ram; }
// The maximum amount of available RAM that can be allocated to the server.
private int _maxRam;
public int getMaxRam() { return _maxRam; }
// The public I.P address used by players to connect to the server.
private String _publicAddress;
public String getPublicAddress() { return _publicAddress; }
// The port the server is currently running/listening on.
private int _port;
public int getPort() { return _port; }
/**
* Class constructor
* @param name
* @param group
* @param motd
* @param publicAddress
* @param port
* @param playerCount
* @param maxPlayerCount
* @param tps
* @param ram
* @param maxRam
*/
public MinecraftServer(String name, String group, String motd, String publicAddress, int port,
int playerCount, int maxPlayerCount, int tps, int ram, int maxRam)
{
this._name = name;
this._group = group;
this._motd = motd;
this._playerCount = playerCount;
this._maxPlayerCount = maxPlayerCount;
this._tps = tps;
this._ram = ram;
this._maxRam = maxRam;
this._publicAddress = publicAddress;
this._port = port;
}
/**
* @return true, if {@value _playerCount} equals 0, false otherwise.
*/
public boolean isEmpty()
{
return _playerCount == 0;
}
/**
* @return true, if this server is currently joinable by players, false otherwise.
*/
public boolean isJoinable()
{
if (_motd != null && (_motd.contains("Starting") || _motd.contains("Recruiting")
|| _motd.contains("Waiting") || _motd.contains("Cup") || _motd.isEmpty()))
{
if (_playerCount < _maxPlayerCount)
{
int availableSlots = _maxPlayerCount - _playerCount;
return _motd.isEmpty() ? (availableSlots > 20) : true;
}
}
return false;
}
}

View File

@ -0,0 +1,314 @@
package mineplex.serverdata;
import java.util.ArrayList;
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 redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* RedisServerRepository offers a Redis-based implementation of {@link ServerRepository}
* using a mixture of hash and JSON encoded storage.
* @author Ty
*
*/
public class RedisServerRepository implements ServerRepository
{
// The delimiter character used for redis key paths
public final char KEY_DELIMITER = '.';
// The pool used to retrieve jedis instances.
private JedisPool _jedisPool;
// The geographical region of the servers stored by this ServerRepository
private Region _region;
/**
* Class constructor
* @param host
* @param port
*/
public RedisServerRepository(String host, int port, Region region)
{
this._jedisPool = new JedisPool(new JedisPoolConfig(), host, port);
this._region = region;
}
@Override
public Collection<MinecraftServer> getServerStatuses()
{
Collection<MinecraftServer> servers = new HashSet<MinecraftServer>();
Jedis jedis = _jedisPool.getResource();
try
{
String setKey = concatenate("serverstatus", "minecraft", _region.toString());
Pipeline pipeline = jedis.pipelined();
List<Response<String>> responses = new ArrayList<Response<String>>();
for (String serverName : getActiveNames(setKey))
{
String dataKey = concatenate(setKey, serverName);
responses.add(pipeline.get(dataKey));
}
pipeline.sync();
for (Response<String> response : responses)
{
String serializedData = response.get();
servers.add(Utility.deserialize(serializedData, MinecraftServer.class));
}
}
finally
{
_jedisPool.returnResource(jedis);
}
return servers;
}
@Override
public MinecraftServer getServerStatus(String serverName)
{
MinecraftServer server = null;
Jedis jedis = _jedisPool.getResource();
try
{
String setKey = concatenate("serverstatus", "minecraft", _region.toString());
String dataKey = concatenate(setKey, serverName);
String serializedData = jedis.get(dataKey);
server = Utility.deserialize(serializedData, MinecraftServer.class);
}
finally
{
_jedisPool.returnResource(jedis);
}
return server;
}
@Override
public void updataServerStatus(MinecraftServer serverData, int timeout)
{
Jedis jedis = _jedisPool.getResource();
try
{
String serializedData = Utility.serialize(serverData);
String serverName = serverData.getName();
String setKey = concatenate("serverstatus", "minecraft", _region.toString());
String dataKey = concatenate(setKey, serverName);
long expiry = System.currentTimeMillis() + timeout;
Transaction transaction = jedis.multi();
transaction.set(dataKey, serializedData);
transaction.zadd(setKey, expiry, serverName);
transaction.exec();
}
finally
{
_jedisPool.returnResource(jedis);
}
}
@Override
public void removeServerStatus(MinecraftServer serverData)
{
Jedis jedis = _jedisPool.getResource();
try
{
String serverName = serverData.getName();
String setKey = concatenate("serverstatus", "minecraft", _region.toString());
String dataKey = concatenate(setKey, serverName);
Transaction transaction = jedis.multi();
transaction.set(dataKey, null);
transaction.zrem(setKey, serverName);
transaction.exec();
}
finally
{
_jedisPool.returnResource(jedis);
}
}
@Override
public boolean serverExists(String serverName)
{
return getServerStatus(serverName) != null;
}
@Override
public Collection<DedicatedServer> getDedicatedServers()
{
Collection<DedicatedServer> servers = new HashSet<DedicatedServer>();
Jedis jedis = _jedisPool.getResource();
try
{
String key = concatenate("serverstatus", "dedicated");
Set<String> serverNames = jedis.smembers(key);
Set<Response<Map<String, String>>> serverDatas = new HashSet<Response<Map<String, String>>>();
Pipeline pipeline = jedis.pipelined();
for (String serverName : serverNames)
{
String dataKey = concatenate(key, serverName);
serverDatas.add(pipeline.hgetAll(dataKey));
}
pipeline.sync();
for (Response<Map<String, String>> response : serverDatas)
{
Map<String, String> data = response.get();
DedicatedServer server = new DedicatedServer(data);
if (server.getRegion() == _region)
{
servers.add(server);
}
}
}
finally
{
_jedisPool.returnResource(jedis);
}
Map<String, ServerGroup> serverGroups = new HashMap<String, ServerGroup>();
for (ServerGroup serverGroup : getServerGroups())
{
serverGroups.put(serverGroup.getName(), serverGroup);
}
// TODO: Find cleaner way to prep dedicated server group counts?
for (DedicatedServer server : servers)
{
for (MinecraftServer minecraftServer : getServerStatuses())
{
if (serverGroups.containsKey(minecraftServer.getGroup()))
{
ServerGroup serverGroup = serverGroups.get(minecraftServer.getGroup());
server.incrementServerCount(serverGroup);
}
}
}
return servers;
}
@Override
public Collection<ServerGroup> getServerGroups()
{
Collection<ServerGroup> servers = new HashSet<ServerGroup>();
Jedis jedis = _jedisPool.getResource();
try
{
String key = "servergroups";
Set<String> names = jedis.smembers(key);
for (String groupName : names)
{
String dataKey = concatenate(key, groupName);
Map<String, String> data = jedis.hgetAll(dataKey);
servers.add(new ServerGroup(data, _region));
}
}
finally
{
_jedisPool.returnResource(jedis);
}
return servers;
}
@Override
public int clean()
{
// TODO: Clean out expired/dead MinecraftServers.
return 0;
}
/**
* @param key - the key where the sorted set of server sessions is stored
* @return the {@link Set} of active server names stored at {@code key} for non-expired
* servers.
*/
protected Set<String> getActiveNames(String key)
{
Set<String> names = new HashSet<String>();
Jedis jedis = _jedisPool.getResource();
try
{
String min = "(" + System.currentTimeMillis();
String max = "+inf";
names = jedis.zrangeByScore(key, min, max);
}
finally
{
_jedisPool.returnResource(jedis);
}
return names;
}
/**
* @param elements - the elements to concatenate together
* @return the concatenated form of all {@code elements}
* separated by the delimiter {@value KEY_DELIMITER}.
*/
protected String concatenate(String... elements)
{
return Utility.concatenate(KEY_DELIMITER, elements);
}
/*
* <region> = "US" or "EU"
* serverstatus.minecraft.<region>.<name> stores the JSON encoded information of an active MinecraftServer instance.
* serverstatus.minecraft.<region> stores a sorted set with the set of name's for MinecraftServers
* with a value of their expiry date (in ms)
*
* -----------------------
*
* serverstatus.dedicated.<name> stores the hash containing information of an active dedicated server instance
* serverstatus.dedicated stores the set of active dedicated server names.
* serverstatus.dedicated uses a hash with the following keys:
* name, publicAddress, privateAddress, region, cpu, ram
*
* Example commands for adding/creating a new dedicated server:
* 1. HMSET serverstatus.dedicated.<name> name <?> publicAddress <?> privateAddress <?> region <?> cpu <?> ram <?>
* 2. SADD serverstatus.dedicated <name>
*
* ------------------------
*
* servergroups.<name> stores the hash-set containing information for the server group type.
* servergroups stores the set of active server group names.
* servergroups.<name> stores a hash of the following key name/values
* name, prefix, scriptName, ram, cpu, totalServers, joinableServers
*
* Example commands for adding/creating a new server group:
*
* 1. HMSET servergroups.<name> name <?> prefix <?> scriptName <?> ram <?> cpu <?> totalServers <?> joinableServers <?>
* 2. SADD servergroups <name>
*/
}

View File

@ -0,0 +1,13 @@
package mineplex.serverdata;
/**
* Region enumerates the various geographical regions where Mineplex servers are
* hosted.
* @author Ty
*
*/
public enum Region
{
US,
EU;
}

View File

@ -0,0 +1,207 @@
package mineplex.serverdata;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* A ServerGroup represents a set of associated requirements for a type of {@link MinecraftServer}.
* @author Ty
*
*/
public class ServerGroup
{
// The unique name identifying this ServerGroup.
private String _name;
public String getName() { return _name; }
// The prefix used to desginate this type of ServerGroup.
private String _prefix;
public String getPrefix() { return _prefix; }
// The name of the shell script used to start the minecraft server instance.
private String _scriptName;
public String getScriptName() { return _scriptName; }
// The amount of ram required for a server instance of this group type
private int _requiredRam;
public int getRequiredRam() { return _requiredRam; }
// The amount of cpu required for a server instance of this group type
private int _requiredCpu;
public int getRequiredCpu() { return _requiredCpu; }
// The total amount of servers required to be active of this group type
private int _requiredTotalServers;
public int getRequiredTotalServers() { return _requiredTotalServers; }
// The amount of joinable (non-full) servers required to be active for this group
private int _requiredJoinableServers;
public int getRequiredJoinableServers() { return _requiredJoinableServers; }
// The set of active MinecraftServers that belong to this server group
private Set<MinecraftServer> servers;
/**
* Class constructor
* @param data - the set of serialized data values representing
* the internal state of this ServerGroup.
* @param region - the region from which to fetch active {@link MinecraftServer}s.
*/
public ServerGroup(Map<String, String> data, Region region)
{
this._name = data.get("name");
this._prefix = data.get("prefix");
this._scriptName = data.get("scriptName");
this._requiredRam = Integer.valueOf(data.get("ram"));
this._requiredCpu = Integer.valueOf(data.get("cpu"));
this._requiredTotalServers = Integer.valueOf(data.get("totalServers"));
this._requiredJoinableServers = Integer.valueOf(data.get("joinableServers"));
fetchServers(region);
}
/**
* @return the total number of currently active {@link MinecraftServer}s belonging
* to this server group.
*/
public int getServerCount()
{
return servers.size();
}
/**
* @return the total number of currently joinable (non-full) {@link MinecraftServer}s
* belonging to this server group.
*/
public int getJoinableCount()
{
int joinable = 0;
for (MinecraftServer server : servers)
{
if (server.isJoinable())
{
joinable++;
}
}
return joinable;
}
/**
* @return the total player count across all {@link MinecraftServer}s
* belonging to this server group.
*/
public int getPlayerCount()
{
int playerCount = 0;
for (MinecraftServer server : servers)
{
playerCount += server.getPlayerCount();
}
return playerCount;
}
/**
* @return the total maximum player count across all {@link MinecraftServer}s
* belonging to this server group.
*/
public int getMaxPlayerCount()
{
int maxPlayerCount = 0;
for (MinecraftServer server : servers)
{
maxPlayerCount += server.getMaxPlayerCount();
}
return maxPlayerCount;
}
/**
* @return a {@link Collection} of active but empty {@link MinecraftServer}s that belong
* to this server group.
*/
public Collection<MinecraftServer> getEmptyServers()
{
Collection<MinecraftServer> emptyServers = new HashSet<MinecraftServer>();
for (MinecraftServer server : servers)
{
if (server.isEmpty())
{
emptyServers.add(server);
}
}
return emptyServers;
}
/**
* Update & fetch all {@link MinecraftServer}s that belong to this server group and
* store them in {@code servers} field.
*/
private void fetchServers(Region region)
{
this.servers = new HashSet<MinecraftServer>();
ServerRepository repository = ServerManager.getServerRepository(region);
for (MinecraftServer server : repository.getServerStatuses())
{
if (_name.equals(server.getGroup()))
{
servers.add(server);
}
}
}
/**
* @return a unique server name suffix id, unique to any servers in this ServerGroup.
*/
public int generateUniqueId()
{
int id = 0;
while (true)
{
boolean uniqueId = true;
for (MinecraftServer server : servers)
{
String serverName = server.getName();
try
{
int serverNum = Integer.parseInt(serverName.split("-")[1]);
if (serverNum == id)
{
uniqueId = false;
break;
}
}
catch (Exception exception)
{
exception.printStackTrace();
}
}
if (uniqueId)
{
return id;
}
else
{
id++;
}
}
}
}

View File

@ -0,0 +1,49 @@
package mineplex.serverdata;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* ServerManager handles the creation/management of {@link ServerRepository}s for use.
* @author Ty
*
*/
public class ServerManager
{
// The host of the default redis database used for server repository
private static String DEFAULT_REDIS_HOST = "10.33.53.16";
// The default port used by redis databases
private static int DEFAULT_REDIS_PORT = 6379;
// The cached repository instances
private static Map<Region, ServerRepository> repositories = new HashMap<Region, ServerRepository>();
/**
* @param host - the host url used to connect to the database
* @param port - the port to connect to the repository
* @param region - the geographical region of the {@link ServerRepository}.
* @return a newly instanced (or cached) {@link ServerRepository} for the specified {@code region}.
*/
public static ServerRepository getServerRepository(String host, int port, Region region)
{
if (repositories.containsKey(region)) return repositories.get(region);
ServerRepository repository = new RedisServerRepository(host, port, region);
repositories.put(region, repository);
return repository;
}
/**
* {@code host} defaults to {@value DEFAULT_REDIS_HOST} and
* {@code port} defaults to {@value DEFAULT_REDIS_PORT}.
*
* @see #getServerRepository(String, int, Region)
*/
public static ServerRepository getServerRepository(Region region)
{
return getServerRepository(DEFAULT_REDIS_HOST, DEFAULT_REDIS_PORT, region);
}
}

View File

@ -0,0 +1,71 @@
package mineplex.serverdata;
import java.util.Collection;
/**
* The ServerRepository is used for storing/retrieving active sessions
* for {@link MinecraftServer}s, {@link DedicatedServer}s, and {@link ServerGroup}s
* from a persistent database/repoistory.
* @author Ty
*
*/
public interface ServerRepository
{
/**
* @return a newly instanced snapshot {@link Collection} of all currently active
* {@link MinecraftServer}s in the repository.
*/
public Collection<MinecraftServer> getServerStatuses();
/**
* @param serverName - the name of the {@link MinecraftServer} to be fetched.
* @return the currently active {@link MinecraftServer} with a matching {@code serverName},
* if an active one exists, null otherwise.
*/
public MinecraftServer getServerStatus(String serverName);
/**
* Update (or add, if it doesn't already exist) a {@link MinecraftServer}s data
* in the repository.
*
* A {@link MinecraftServer} must be updated within {@code timeout} milliseconds before
* it expires and is removed from the repository.
* @param serverData - the {@link MinecraftServer} to add/update in the repository.
* @param timeout - the timeout (in milliseconds) before the {@link MinecraftServer} session expires.
*/
public void updataServerStatus(MinecraftServer serverData, int timeout);
/**
* Remove an active {@link MinecraftServer} from the repository.
* @param serverData - the {@link MinecraftServer} to be removed.
*/
public void removeServerStatus(MinecraftServer serverData);
/**
* @param serverName - the name of the server whose existence is being checked.
* @return true, if there exists an active {@link MinecraftServer} session with a
* matching {@code serverName}, false otherwise.
*/
public boolean serverExists(String serverName);
/**
* @return a newly instanced snapshot {@link Collection} of all the
* currently active {@link DedicatedServer}s in the repository.
*/
public Collection<DedicatedServer> getDedicatedServers();
/**
* @return a newly instanced snapshot {@link Collection} of all the
* currently active {@link ServerGroup}s in the repository.
*/
public Collection<ServerGroup> getServerGroups();
/**
* Clean the repository by removing all expired server statuses that have
* passed their timeout period.
* @return the number of expired server statuses removed/cleared.
*/
public int clean();
}

View File

@ -0,0 +1,54 @@
package mineplex.serverdata;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/**
* Utility offers various necessary utility-based methods for use in Mineplex.ServerData.
* @author Ty
*
*/
public class Utility
{
// The Gson instance used to serialize/deserialize objects in JSON form.
private static Gson _gson = new GsonBuilder().create();
public static Gson getGson() { return _gson; }
/**
* @param object - the (non-null) object to serialize
* @return the serialized form of {@code object}.
*/
public static String serialize(Object object)
{
return _gson.toJson(object);
}
/**
* @param serializedData - the serialized data to be deserialized
* @param type - the resulting class type of the object to be deserialized
* @return the deserialized form of {@code serializedData} for class {@code type}.
*/
public static <T> T deserialize(String serializedData, Class<T> type)
{
return _gson.fromJson(serializedData, type);
}
/**
* @param delimiter - the delimiter character used to separate the concatenated elements
* @param elements - the set of string elements to be concatenated and returned.
* @return the concatenated string of all {@code elements} separated by the {@code delimiter}.
*/
public static String concatenate(char delimiter, String... elements)
{
int length = elements.length;
String result = length > 0 ? elements[0] : new String();
for (int i = 1; i < length; i++)
{
result += delimiter + elements[i];
}
return result;
}
}

View File

@ -6,5 +6,6 @@
<classpathentry combineaccessrules="false" kind="src" path="/Mineplex.Core.Common"/> <classpathentry combineaccessrules="false" kind="src" path="/Mineplex.Core.Common"/>
<classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/httpclient-4.2.jar"/> <classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/httpclient-4.2.jar"/>
<classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/httpcore-4.2.jar"/> <classpathentry kind="var" path="REPO_DIR/Plugins/Libraries/httpcore-4.2.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/Mineplex.ServerData"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@ -1,33 +0,0 @@
package mineplex.servermonitor;
import java.util.HashMap;
public class DynamicServerData
{
public String Name;
public String Address;
public int AvailableCPU = 32;
public int AvailableRAM = 14000;
public HashMap<String, Integer> ServerGroupCount = new HashMap<String, Integer>();
public boolean US;
public String PrivateAddress;
public void setServerGroupCount(ServerGroupData groupData, int count)
{
if (ServerGroupCount.containsKey(groupData.Name))
{
AvailableCPU += groupData.RequiredCPU * ServerGroupCount.get(groupData.Name);
AvailableRAM += groupData.RequiredRAM * ServerGroupCount.get(groupData.Name);
}
ServerGroupCount.put(groupData.Name, count);
AvailableCPU -= groupData.RequiredCPU * count;
AvailableRAM -= groupData.RequiredRAM * count;
}
public void printInfo()
{
System.out.println("DynamicServerData - Name:" + Name + " Address:" + Address + " RAM:" + AvailableRAM + " CPU:" + AvailableCPU);
}
}

View File

@ -1,30 +0,0 @@
package mineplex.servermonitor;
import java.util.Comparator;
public class DynamicServerSorter implements Comparator<DynamicServerData>
{
@Override
public int compare(DynamicServerData first, DynamicServerData second)
{
if (second.AvailableRAM <= 1024)
return -1;
if (first.AvailableRAM <= 1024)
return 1;
if (first.AvailableRAM > second.AvailableRAM)
return -1;
if (second.AvailableRAM > first.AvailableRAM)
return 1;
if (first.AvailableCPU > second.AvailableCPU)
return -1;
if (second.AvailableCPU > first.AvailableCPU)
return 1;
return 0;
}
}

View File

@ -1,115 +0,0 @@
package mineplex.servermonitor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class GroupStatusData
{
private int _serverNum = 0;
private int _totalCount = 0;
private int _joinableCount = 0;
public int Players;
public int MaxPlayers;
public int MaxServerNumber;
public List<ServerStatusData> EmptyServers = new ArrayList<ServerStatusData>();
public List<ServerStatusData> KillServers = new ArrayList<ServerStatusData>();
public HashMap<Integer, ServerStatusData> Servers = new HashMap<Integer, ServerStatusData>();
public void addServer(ServerStatusData serverStatusData)
{
if (Servers.containsKey(Integer.parseInt(serverStatusData.Name.split("-")[1])))
{
ServerStatusData existingServer = Servers.get(Integer.parseInt(serverStatusData.Name.split("-")[1]));
int existingCount = existingServer.Players;
int newCount = serverStatusData.Players;
if (newCount == 0 || newCount < existingCount)
{
KillServers.add(serverStatusData);
return;
}
else if (existingCount == 0 || newCount > existingCount)
{
KillServers.add(existingServer);
Players -= existingServer.Players;
MaxPlayers -= existingServer.MaxPlayers;
if (existingServer.Motd != null && (existingServer.Motd.contains("Starting") || existingServer.Motd.contains("Recruiting") || existingServer.Motd.contains("Waiting") || existingServer.Motd.contains("Cup") || existingServer.Motd.isEmpty() || existingServer.Motd.equals("")))
{
if (existingServer.Players < existingServer.MaxPlayers)
{
// Lobby joinable checking
if (existingServer.Motd.isEmpty() || existingServer.Motd.equals(""))
{
if (serverStatusData.MaxPlayers - serverStatusData.Players > 20)
_joinableCount--;
}
else
{
_joinableCount--;
}
}
}
}
}
Players += serverStatusData.Players;
MaxPlayers += serverStatusData.MaxPlayers;
if (serverStatusData.Motd != null && (serverStatusData.Motd.contains("Starting") || serverStatusData.Motd.contains("Recruiting") || serverStatusData.Motd.contains("Waiting") || serverStatusData.Motd.contains("Cup") || serverStatusData.Motd.isEmpty() || serverStatusData.Motd.equals("")))
{
if (serverStatusData.Players < serverStatusData.MaxPlayers)
{
// Lobby joinable checking
if (serverStatusData.Motd.isEmpty() || serverStatusData.Motd.equals(""))
{
if (serverStatusData.MaxPlayers - serverStatusData.Players > 20)
{
_joinableCount++;
}
}
else
{
_joinableCount++;
}
}
}
_totalCount++;
if (serverStatusData.Empty)
{
EmptyServers.add(serverStatusData);
}
Servers.put(Integer.parseInt(serverStatusData.Name.split("-")[1]), serverStatusData);
}
public int getTotalServers()
{
return _totalCount;
}
public int getJoinableCount()
{
return _joinableCount;
}
public int getNextServerNumber()
{
_serverNum++;
while (true)
{
if (!Servers.containsKey(_serverNum))
{
return _serverNum;
}
_serverNum++;
}
}
}

View File

@ -1,437 +0,0 @@
package mineplex.servermonitor;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
public class Repository
{
private String _connectionString = "jdbc:mysql://db.mineplex.com:3306/ServerStatus?autoReconnect=true&failOverReadOnly=false&maxReconnects=10";
private String _userName = "root";
private String _password = "tAbechAk3wR7tuTh";
private boolean _us = true;
private static String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS ServerStatus (id INT NOT NULL AUTO_INCREMENT, serverName VARCHAR(256), serverGroup VARCHAR(256), address VARCHAR(256), port VARCHAR(11), updated LONG, lastTimeWithPlayers LONG, motd VARCHAR(256), players INT, maxPlayers INT, tps INT, ram INT, maxRam INT, PRIMARY KEY (id));";
private static String RETRIEVE_OLD_SERVER_STATUSES = "SELECT ServerStatus.serverName, DynamicServers.address, ServerStatus.address, ServerStatus.port, motd, players, maxPlayers, now(), updated FROM ServerStatus INNER JOIN DynamicServers ON ServerStatus.address = DynamicServers.privateAddress WHERE DynamicServers.US = ?;";
private static String CREATE_DYNAMIC_TABLE = "CREATE TABLE IF NOT EXISTS DynamicServers (id INT NOT NULL AUTO_INCREMENT, serverName VARCHAR(256), address VARCHAR(256), privateAddress VARCHAR(256), US BOOLEAN NOT NULL DEFAULT 'true', PRIMARY KEY (id));";
private static String RETRIEVE_AVAILABLE_SERVERS = "SELECT DynamicServers.serverName, DynamicServers.address, DynamicServers.privateAddress, DynamicServers.US, DynamicServers.availableCpu, DynamicServers.availableRam, ServerStatus.serverGroup, COUNT(*) As serverCount FROM DynamicServers LEFT JOIN ServerStatus ON ServerStatus.address = DynamicServers.privateAddress WHERE DynamicServers.US = ? GROUP BY DynamicServers.address, ServerStatus.serverGroup;";
private static String RETRIEVE_SERVERGROUP_STATUSES = "SELECT ServerStatus.serverName, serverGroup, motd, DynamicServers.address, ServerStatus.address, ServerStatus.port, players, maxPlayers, case when TIME_TO_SEC(TIMEDIFF(now(), ServerStatus.lastTimeWithPlayers)) > 300 then 1 else 0 end as empty, now(), updated FROM ServerStatus INNER JOIN DynamicServers ON ServerStatus.address = DynamicServers.privateAddress WHERE DynamicServers.US = ?";
private static String RETRIEVE_SERVER_GROUP_DATA = "SELECT groupName, prefix, scriptName, requiredRam, cpuRequired, requiredTotal, requiredJoinable FROM ServerGroups;";
private static String DELETE_SERVER_STATUS = "DELETE FROM ServerStatus WHERE address = ? AND port = ? AND serverName = ?;";
public static Connection connection;
public void initialize(boolean us)
{
_us = us;
PreparedStatement preparedStatement = null;
try
{
Class.forName("com.mysql.jdbc.Driver");
if (connection == null || connection.isClosed())
connection = DriverManager.getConnection(_connectionString, _userName, _password);
// Create table
preparedStatement = connection.prepareStatement(CREATE_TABLE);
preparedStatement.execute();
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
preparedStatement = null;
try
{
Class.forName("com.mysql.jdbc.Driver");
// Create table
preparedStatement = connection.prepareStatement(CREATE_DYNAMIC_TABLE);
preparedStatement.execute();
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
}
public List<ServerStatusData> retrieveOldServerStatuses()
{
ResultSet resultSet = null;
PreparedStatement preparedStatement = null;
List<ServerStatusData> serverData = new ArrayList<ServerStatusData>();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try
{
if (connection == null || connection.isClosed())
connection = DriverManager.getConnection(_connectionString, _userName, _password);
preparedStatement = connection.prepareStatement(RETRIEVE_OLD_SERVER_STATUSES);
preparedStatement.setBoolean(1, _us);
resultSet = preparedStatement.executeQuery();
while (resultSet.next())
{
ServerStatusData serverStatusData = new ServerStatusData();
serverStatusData.Name = resultSet.getString(1);
serverStatusData.Address = resultSet.getString(2);
serverStatusData.PrivateAddress = resultSet.getString(3);
serverStatusData.Port = Integer.parseInt(resultSet.getString(4));
serverStatusData.Motd = resultSet.getString(5);
serverStatusData.Players = resultSet.getInt(6);
serverStatusData.MaxPlayers = resultSet.getInt(7);
long current = dateFormat.parse(resultSet.getString(8)).getTime();
long updated = dateFormat.parse(resultSet.getString(9)).getTime();
if (current - updated > 15000)
serverData.add(serverStatusData);
}
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (resultSet != null)
{
try
{
resultSet.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
return serverData;
}
public HashMap<String, GroupStatusData> retrieveGroupStatusData()
{
ResultSet resultSet = null;
PreparedStatement preparedStatement = null;
HashMap<String, GroupStatusData> groupData = new HashMap<String, GroupStatusData>();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try
{
if (connection == null || connection.isClosed())
connection = DriverManager.getConnection(_connectionString, _userName, _password);
preparedStatement = connection.prepareStatement(RETRIEVE_SERVERGROUP_STATUSES);
preparedStatement.setBoolean(1, _us);
resultSet = preparedStatement.executeQuery();
while (resultSet.next())
{
ServerStatusData serverStatusData = new ServerStatusData();
serverStatusData.Name = resultSet.getString(1);
String serverGroup = resultSet.getString(2);
serverStatusData.Motd = resultSet.getString(3);
serverStatusData.Address = resultSet.getString(4);
serverStatusData.PrivateAddress = resultSet.getString(5);
serverStatusData.Port = Integer.parseInt(resultSet.getString(6));
serverStatusData.Players = resultSet.getInt(7);
serverStatusData.MaxPlayers = resultSet.getInt(8);
serverStatusData.Empty = resultSet.getBoolean(9);
if (!groupData.containsKey(serverGroup))
{
groupData.put(serverGroup, new GroupStatusData());
}
long current = dateFormat.parse(resultSet.getString(10)).getTime();
long updated = dateFormat.parse(resultSet.getString(11)).getTime();
if (current - updated < 15000)
groupData.get(serverGroup).addServer(serverStatusData);
}
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (resultSet != null)
{
try
{
resultSet.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
return groupData;
}
public Collection<DynamicServerData> retrieveDynamicServers()
{
ResultSet resultSet = null;
PreparedStatement preparedStatement = null;
HashMap<String, DynamicServerData> serverMap = new HashMap<String, DynamicServerData>();
HashMap<String, ServerGroupData> serverGroupMap = new HashMap<String, ServerGroupData>();
try
{
if (connection == null || connection.isClosed())
connection = DriverManager.getConnection(_connectionString, _userName, _password);
preparedStatement = connection.prepareStatement(RETRIEVE_SERVER_GROUP_DATA);
resultSet = preparedStatement.executeQuery();
while (resultSet.next())
{
ServerGroupData serverGroupData = new ServerGroupData();
serverGroupData.Name = resultSet.getString(1);
serverGroupData.Prefix = resultSet.getString(2);
serverGroupData.ScriptName = resultSet.getString(3);
serverGroupData.RequiredRAM = resultSet.getInt(4);
serverGroupData.RequiredCPU = resultSet.getInt(5);
serverGroupData.RequiredTotalServers = resultSet.getInt(6);
serverGroupData.RequiredJoinableServers = resultSet.getInt(7);
if (!serverGroupMap.containsKey(serverGroupData.Name))
serverGroupMap.put(serverGroupData.Name, serverGroupData);
}
preparedStatement.close();
resultSet.close();
preparedStatement = connection.prepareStatement(RETRIEVE_AVAILABLE_SERVERS);
preparedStatement.setBoolean(1, _us);
resultSet = preparedStatement.executeQuery();
while (resultSet.next())
{
DynamicServerData dynamicServer = new DynamicServerData();
dynamicServer.Name = resultSet.getString(1);
dynamicServer.Address = resultSet.getString(2);
dynamicServer.PrivateAddress = resultSet.getString(3);
dynamicServer.US = resultSet.getBoolean(4);
dynamicServer.AvailableCPU = resultSet.getInt(5);
dynamicServer.AvailableRAM = resultSet.getInt(6);
if (!serverMap.containsKey(dynamicServer.Name))
serverMap.put(dynamicServer.Name, dynamicServer);
String serverGroupName = resultSet.getString(7);
if (serverGroupMap.containsKey(serverGroupName))
serverMap.get(dynamicServer.Name).setServerGroupCount(serverGroupMap.get(serverGroupName), resultSet.getInt(8));
}
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (resultSet != null)
{
try
{
resultSet.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
return serverMap.values();
}
public Collection<ServerGroupData> retrieveServerGroups()
{
ResultSet resultSet = null;
PreparedStatement preparedStatement = null;
HashMap<String, ServerGroupData> serverGroupMap = new HashMap<String, ServerGroupData>();
try
{
if (connection == null || connection.isClosed())
connection = DriverManager.getConnection(_connectionString, _userName, _password);
preparedStatement = connection.prepareStatement(RETRIEVE_SERVER_GROUP_DATA);
resultSet = preparedStatement.executeQuery();
while (resultSet.next())
{
ServerGroupData serverGroupData = new ServerGroupData();
serverGroupData.Name = resultSet.getString(1);
serverGroupData.Prefix = resultSet.getString(2);
serverGroupData.ScriptName = resultSet.getString(3);
serverGroupData.RequiredRAM = resultSet.getInt(4);
serverGroupData.RequiredCPU = resultSet.getInt(5);
serverGroupData.RequiredTotalServers = resultSet.getInt(6);
serverGroupData.RequiredJoinableServers = resultSet.getInt(7);
if (!serverGroupMap.containsKey(serverGroupData.Name))
serverGroupMap.put(serverGroupData.Name, serverGroupData);
}
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (resultSet != null)
{
try
{
resultSet.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
return serverGroupMap.values();
}
public void removeServerRecord(ServerStatusData serverToKill)
{
PreparedStatement preparedStatement = null;
try
{
if (connection == null || connection.isClosed())
connection = DriverManager.getConnection(_connectionString, _userName, _password);
preparedStatement = connection.prepareStatement(DELETE_SERVER_STATUS);
preparedStatement.setString(1, serverToKill.PrivateAddress);
preparedStatement.setString(2, serverToKill.Port + "");
preparedStatement.setString(3, serverToKill.Name);
preparedStatement.execute();
}
catch (Exception exception)
{
exception.printStackTrace();
}
finally
{
if (preparedStatement != null)
{
try
{
preparedStatement.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
}
}

View File

@ -1,17 +0,0 @@
package mineplex.servermonitor;
public class ServerGroupData
{
public String Name;
public String Prefix;
public String ScriptName;
public int RequiredRAM;
public int RequiredCPU;
public int RequiredTotalServers;
public int RequiredJoinableServers;
public void printInfo()
{
System.out.println("ServerGroupData - Name:" + Name + " Prefix:" + Prefix + " ScriptName:" + ScriptName + " RAM:" + RequiredRAM + " CPU:" + RequiredCPU + " ReqTotal:" + RequiredTotalServers + " ReqJoin:" + RequiredJoinableServers);
}
}

View File

@ -13,172 +13,141 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import mineplex.serverdata.DedicatedServer;
import mineplex.serverdata.DedicatedServerSorter;
import mineplex.serverdata.MinecraftServer;
import mineplex.serverdata.Region;
import mineplex.serverdata.ServerGroup;
import mineplex.serverdata.ServerManager;
import mineplex.serverdata.ServerRepository;
public class ServerMonitor public class ServerMonitor
{ {
private static boolean _us = true;
private static Repository _repository = new Repository(); private static ServerRepository _repository = null;
private static int _count = 0; private static int _count = 0;
private static HashSet<ProcessRunner> _processes = new HashSet<ProcessRunner>(); private static HashSet<ProcessRunner> _processes = new HashSet<ProcessRunner>();
private static HashMap<String, Boolean> _badServers = new HashMap<String, Boolean>(); private static HashMap<String, Boolean> _badServers = new HashMap<String, Boolean>();
public static void main (String args[]) public static void main (String args[])
{ {
_us = !new File("eu.dat").exists(); Region region = !new File("eu.dat").exists() ? Region.US : Region.EU;
_repository = ServerManager.getServerRepository(region); // Fetches and connects to server repo
_repository.initialize(_us);
HashMap<String, Entry<String, Long>> serverTracker = new HashMap<String, Entry<String, Long>>(); HashMap<String, Entry<String, Long>> serverTracker = new HashMap<String, Entry<String, Long>>();
while (true) while (true)
{ {
Collection<ServerGroupData> serverGroups = _repository.retrieveServerGroups(); Collection<ServerGroup> serverGroups = _repository.getServerGroups();
HashMap<String, GroupStatusData> groupStatusList = _repository.retrieveGroupStatusData(); _repository.clean(); // Clean out old expired server entries
for (ServerStatusData statusData : _repository.retrieveOldServerStatuses()) List<DedicatedServer> dedicatedServers = new ArrayList<DedicatedServer>(_repository.getDedicatedServers());
{
/* if (_count % 15 == 0)
if (us) {
{ _badServers.clear();
if (!serverTracker.containsKey(statusData.Name))
for (DedicatedServer serverData : dedicatedServers)
{
if (isServerOffline(serverData))
{ {
restartServer(statusData); System.out.println("------=[OFFLINE]=------=[" + serverData.getName() + ":" + serverData.getPublicAddress() + "]=------=[OFFLINE]=------");
serverTracker.put(statusData.Name, new AbstractMap.SimpleEntry<String, Long>(statusData.Address, System.currentTimeMillis())); _badServers.put(serverData.getName(), true);
}
else if (System.currentTimeMillis() - serverTracker.get(statusData.Name).getValue() > 15000)
{
serverTracker.remove(statusData.Name);
System.out.println("-=[SERVER RESTART TOO SLOW]=- " + statusData.Name + " (Putting back in restart queue)");
} }
} }
else
*/
killServer(statusData); System.out.println(_badServers.size() + " bad servers.");
} }
/* for (Iterator<DedicatedServer> iterator = dedicatedServers.iterator(); iterator.hasNext();)
if (us)
{ {
// Remove successfully restarted US servers DedicatedServer serverData = iterator.next();
for (GroupStatusData groupStatus : groupStatusList.values())
if (_badServers.containsKey(serverData.getName()))
iterator.remove();
}
// TODO: Check with Jonathan to see if we still need this duplication server code
/*for (GroupStatusData groupStatus : groupStatusList.values())
{
for (ServerStatusData serverToKill : groupStatus.KillServers)
{ {
for (ServerStatusData serverToKill : groupStatus.Servers.values()) System.out.println("----DUPLICATE SERVER----> " + serverToKill.Address + ", " + serverToKill.Name);
{ killServer(serverToKill);
if (serverTracker.containsKey(serverToKill.Name)) }
serverTracker.remove(serverToKill.Name);
} for (ServerStatusData serverToKill : groupStatus.Servers.values())
{
if (serverTracker.containsKey(serverToKill.Name))
serverTracker.remove(serverToKill.Name);
}
}*/
for (Iterator<Entry<String, Entry<String, Long>>> iterator = serverTracker.entrySet().iterator(); iterator.hasNext();)
{
Entry<String, Entry<String, Long>> entry = iterator.next();
if (System.currentTimeMillis() - entry.getValue().getValue() > 15000)
{
System.out.println("-=[SERVER STARTUP TOO SLOW]=- " + entry.getKey());
String serverName = entry.getKey();
String serverAddress = entry.getValue().getKey();
killServer(serverName, serverAddress, true);
iterator.remove();
} }
} }
else
for (ServerGroup serverGroup : serverGroups)
{ {
*/ int serverNum = serverGroup.generateUniqueId();
List<DynamicServerData> dynamicServers = new ArrayList<DynamicServerData>(_repository.retrieveDynamicServers()); //GroupStatusData groupStatus = groupStatusList.get(serverGroup.Name);
int requiredTotal = serverGroup.getRequiredTotalServers();
if (_count % 15 == 0) int requiredJoinable = serverGroup.getRequiredJoinableServers();
{ int joinableServers = serverGroup.getJoinableCount();
_badServers.clear(); int totalServers = serverGroup.getServerCount();
int serversToAdd = Math.max(requiredTotal - totalServers, requiredJoinable - joinableServers);
for (DynamicServerData serverData : dynamicServers) int serversToKill = (totalServers > requiredTotal && joinableServers > requiredJoinable) ? Math.min(joinableServers - requiredJoinable, serverGroup.getEmptyServers().size()) : 0;
{
if (isServerOffline(serverData)) // Minimum 1500 slot bufferzone
{ if (serverGroup.getName().equalsIgnoreCase("Lobby"))
System.out.println("------=[OFFLINE]=------=[" + serverData.Name + ":" + serverData.Address + "]=------=[OFFLINE]=------");
_badServers.put(serverData.Name, true);
}
}
System.out.println(_badServers.size() + " bad servers.");
}
for (Iterator<DynamicServerData> iterator = dynamicServers.iterator(); iterator.hasNext();)
{ {
DynamicServerData serverData = iterator.next(); if (serverGroup.getMaxPlayerCount() - serverGroup.getPlayerCount() < 1500)
serversToAdd = requiredJoinable;
if (_badServers.containsKey(serverData.Name))
iterator.remove();
}
for (GroupStatusData groupStatus : groupStatusList.values())
{
for (ServerStatusData serverToKill : groupStatus.KillServers)
{
System.out.println("----DUPLICATE SERVER----> " + serverToKill.Address + ", " + serverToKill.Name);
killServer(serverToKill);
}
for (ServerStatusData serverToKill : groupStatus.Servers.values())
{
if (serverTracker.containsKey(serverToKill.Name))
serverTracker.remove(serverToKill.Name);
}
} }
for (Iterator<Entry<String, Entry<String, Long>>> iterator = serverTracker.entrySet().iterator(); iterator.hasNext();) while (serversToAdd > 0)
{ {
Entry<String, Entry<String, Long>> entry = iterator.next(); Collections.sort(dedicatedServers, new DedicatedServerSorter());
DedicatedServer bestServer = getBestDedicatedServer(dedicatedServers, serverGroup);
if (System.currentTimeMillis() - entry.getValue().getValue() > 15000) if (bestServer == null)
{ {
System.out.println("-=[SERVER STARTUP TOO SLOW]=- " + entry.getKey()); System.out.println("No best dynamic server available for group " + serverGroup.getName());
break;
ServerStatusData serverToKill = new ServerStatusData();
serverToKill.Name = entry.getKey();
serverToKill.Address = entry.getValue().getKey();
killServer(serverToKill);
iterator.remove();
} }
if (serverTracker.containsKey(serverGroup.getPrefix() + "-" + serverNum))
System.out.println("[WAITING] On " + serverGroup.getPrefix() + "-" + serverNum + " to finish starting...");
else
{
startServer(bestServer, serverGroup, serverNum);
serverTracker.put(serverGroup.getPrefix() + "-" + serverNum, new AbstractMap.SimpleEntry<String, Long>(bestServer.getPublicAddress(), System.currentTimeMillis()));
}
serversToAdd--;
} }
for (ServerGroupData serverGroup : serverGroups) while (serversToKill > 0)
{ {
if (!groupStatusList.containsKey(serverGroup.Name)) List<MinecraftServer> emptyServers = new ArrayList<MinecraftServer>(serverGroup.getEmptyServers());
{ MinecraftServer emptyServer = emptyServers.get(0);
groupStatusList.put(serverGroup.Name, new GroupStatusData()); System.out.println("[" + emptyServer.getName() + ":" + emptyServer.getPublicAddress() + "] Killing " + serverGroup.getName() + " Req Total: " + serverGroup.getRequiredTotalServers() + " Req Joinable: " + serverGroup.getRequiredJoinableServers() + " | Actual Total: " + serverGroup.getServerCount() + " Actual Joinable: " + serverGroup.getJoinableCount());
} killServer(emptyServer);
serversToKill--;
GroupStatusData groupStatus = groupStatusList.get(serverGroup.Name);
int serversToAdd = Math.max(serverGroup.RequiredTotalServers - groupStatus.getTotalServers(), serverGroup.RequiredJoinableServers - groupStatus.getJoinableCount());
int serversToKill = (groupStatus.getTotalServers() > serverGroup.RequiredTotalServers && groupStatus.getJoinableCount() > serverGroup.RequiredJoinableServers) ? Math.min(groupStatus.getJoinableCount() - serverGroup.RequiredJoinableServers, groupStatus.EmptyServers.size()) : 0;
// Minimum 1500 slot bufferzone
if (serverGroup.Name.equalsIgnoreCase("Lobby"))
{
if (groupStatus.MaxPlayers - groupStatus.Players < 1500)
serversToAdd = serverGroup.RequiredJoinableServers;
}
while (serversToAdd > 0)
{
int serverNum = groupStatus.getNextServerNumber();
Collections.sort(dynamicServers, new DynamicServerSorter());
DynamicServerData bestServer = getBestDynamicServer(dynamicServers, serverGroup);
if (bestServer == null)
{
System.out.println("No best dynamic server available for group " + serverGroup.Name);
break;
}
if (serverTracker.containsKey(serverGroup.Prefix + "-" + serverNum))
System.out.println("[WAITING] On " + serverGroup.Prefix + "-" + serverNum + " to finish starting...");
else
{
startServer(bestServer, serverGroup, serverNum);
serverTracker.put(serverGroup.Prefix + "-" + serverNum, new AbstractMap.SimpleEntry<String, Long>(bestServer.Address, System.currentTimeMillis()));
}
serversToAdd--;
}
while (serversToKill > 0)
{
System.out.println("[" + groupStatus.EmptyServers.get(0).Name + ":" + groupStatus.EmptyServers.get(0).Address + "] Killing " + serverGroup.Name + " Req Total: " + serverGroup.RequiredTotalServers + " Req Joinable: " + serverGroup.RequiredJoinableServers + " | Actual Total: " + groupStatus.getTotalServers() + " Actual Joinable: " + groupStatus.getJoinableCount());
killServer(groupStatus.EmptyServers.remove(0));
serversToKill--;
}
} }
//} }
int processWaits = 0; int processWaits = 0;
@ -244,24 +213,31 @@ public class ServerMonitor
} }
} }
private static void killServer(final ServerStatusData serverToKill, final boolean announce) private static void killServer(final String serverName, final String serverAddress, final boolean announce)
{ {
String cmd = "/home/mineplex/easyRemoteKillServer.sh"; String cmd = "/home/mineplex/easyRemoteKillServer.sh";
ProcessRunner pr = new ProcessRunner(new String[] {"/bin/sh", cmd, serverToKill.Address, serverToKill.Name}); ProcessRunner pr = new ProcessRunner(new String[] {"/bin/sh", cmd, serverAddress, serverName});
pr.start(new GenericRunnable<Boolean>() pr.start(new GenericRunnable<Boolean>()
{ {
public void run(Boolean error) public void run(Boolean error)
{ {
if (!error) if (!error)
_repository.removeServerRecord(serverToKill); {
MinecraftServer server = _repository.getServerStatus(serverName);
if (server != null)
{
_repository.removeServerStatus(server);
}
}
if (announce) if (announce)
{ {
if (error) if (error)
System.out.println("[" + serverToKill.Name + ":" + serverToKill.Address + "] Kill errored."); System.out.println("[" + serverName + ":" + serverAddress + "] Kill errored.");
else else
System.out.println("Sent kill command to " + serverToKill.Address + " for " + serverToKill.Name + " completed"); System.out.println("Sent kill command to " + serverAddress + " for " + serverName + " completed");
} }
} }
}); });
@ -280,14 +256,14 @@ public class ServerMonitor
_processes.add(pr); _processes.add(pr);
} }
private static boolean isServerOffline(DynamicServerData serverData) private static boolean isServerOffline(DedicatedServer serverData)
{ {
boolean success = false; boolean success = false;
Process process = null; Process process = null;
String cmd = "/home/mineplex/isServerOnline.sh"; String cmd = "/home/mineplex/isServerOnline.sh";
ProcessBuilder processBuilder = new ProcessBuilder(new String[] {"/bin/sh", cmd, serverData.Address}); ProcessBuilder processBuilder = new ProcessBuilder(new String[] {"/bin/sh", cmd, serverData.getPublicAddress()});
try try
{ {
@ -316,79 +292,47 @@ public class ServerMonitor
return !success; return !success;
} }
private static DynamicServerData getBestDynamicServer(Collection<DynamicServerData> dynamicServers, ServerGroupData serverGroup) private static DedicatedServer getBestDedicatedServer(Collection<DedicatedServer> dedicatedServers, ServerGroup serverGroup)
{ {
DynamicServerData bestServer = null; DedicatedServer bestServer = null;
for (DynamicServerData serverData : dynamicServers) for (DedicatedServer serverData : dedicatedServers)
{ {
if (serverData.AvailableRAM > serverGroup.RequiredRAM && serverData.AvailableCPU > serverGroup.RequiredCPU) if (serverData.getAvailableRam() > serverGroup.getRequiredRam()
&& serverData.getAvailableCpu() > serverGroup.getRequiredCpu())
{ {
if (bestServer == null) if (bestServer == null
|| serverData.getServerCount(serverGroup) < bestServer.getServerCount(serverGroup))
{ {
bestServer = serverData; bestServer = serverData;
if (!serverData.ServerGroupCount.containsKey(serverGroup.Name))
break;
}
else if (serverData.ServerGroupCount.containsKey(serverGroup.Name))
{
if (serverData.ServerGroupCount.get(serverGroup.Name) < bestServer.ServerGroupCount.get(serverGroup.Name))
bestServer = serverData;
} }
} }
} }
return bestServer; return bestServer;
} }
private static void restartServer(final ServerStatusData serverToKill) private static void killServer(final MinecraftServer serverToKill)
{ {
String cmd = "/home/mineplex/restartServer.sh"; killServer(serverToKill.getName(), serverToKill.getPublicAddress(), true);
ProcessRunner pr = new ProcessRunner(new String[] {"/bin/sh", cmd, serverToKill.Address, serverToKill.Name});
pr.start(new GenericRunnable<Boolean>()
{
public void run(Boolean error)
{
if (error)
System.out.println("Restart command to " + serverToKill.Address + " for " + serverToKill.Name + " failed");
else
System.out.println("Restart command to " + serverToKill.Address + " for " + serverToKill.Name + " completed");
}
});
try
{
pr.join(500);
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
if (!pr.isDone())
_processes.add(pr);
} }
private static void killServer(final ServerStatusData serverToKill) private static void startServer(final DedicatedServer serverSpace, final ServerGroup serverGroup, final int serverNum)
{
killServer(serverToKill, true);
}
private static void startServer(final DynamicServerData serverSpace, final ServerGroupData serverGroup, final int serverNum)
{ {
String cmd = "/home/mineplex/easyRemoteStartServer.sh"; String cmd = "/home/mineplex/easyRemoteStartServer.sh";
final String groupPrefix = serverGroup.getPrefix();
final String serverName = serverSpace.getName();
final String serverAddress = serverSpace.getPublicAddress();
ProcessRunner pr = new ProcessRunner(new String[] {"/bin/sh", cmd, serverSpace.Address, serverSpace.PrivateAddress, serverGroup.ScriptName, serverGroup.Prefix + "-" + serverNum, "1", serverSpace.US ? "us" : "eu"}); ProcessRunner pr = new ProcessRunner(new String[] {"/bin/sh", cmd, serverSpace.getPublicAddress(), serverSpace.getPrivateAddress(), serverGroup.getScriptName(), groupPrefix + "-" + serverNum, "1", serverSpace.isUsRegion() ? "us" : "eu"});
pr.start(new GenericRunnable<Boolean>() pr.start(new GenericRunnable<Boolean>()
{ {
public void run(Boolean error) public void run(Boolean error)
{ {
if (error) if (error)
System.out.println("[" + serverSpace.Name + ":" + serverSpace.Address + "] Errored " + serverGroup.Name + "(" + serverGroup.Prefix + "-" + serverNum + ")"); System.out.println("[" + serverName + ":" + serverAddress + "] Errored " + serverName + "(" + groupPrefix+ "-" + serverNum + ")");
else else
System.out.println("[" + serverSpace.Name + ":" + serverSpace.Address + "] Added " + serverGroup.Name + "(" + serverGroup.Prefix + "-" + serverNum + ")"); System.out.println("[" + serverName + ":" + serverAddress + "] Added " + serverName + "(" + groupPrefix+ "-" + serverNum + ")");
} }
}); });
@ -401,7 +345,7 @@ public class ServerMonitor
e1.printStackTrace(); e1.printStackTrace();
} }
serverSpace.setServerGroupCount(serverGroup, serverSpace.ServerGroupCount.containsKey(serverGroup.Name) ? (serverSpace.ServerGroupCount.get(serverGroup.Name) + 1) : 1); serverSpace.incrementServerCount(serverGroup);
if (!pr.isDone()) if (!pr.isDone())
_processes.add(pr); _processes.add(pr);

View File

@ -1,13 +0,0 @@
package mineplex.servermonitor;
public class ServerStatusData
{
public String Name;
public String Motd;
public int Players;
public int MaxPlayers;
public String Address;
public String PrivateAddress;
public int Port;
public boolean Empty = false;
}

View File

@ -1,8 +0,0 @@
package mineplex.servermonitor;
public class ServerTargetData
{
public DynamicServerData DedicatedServer;
public int ServerNumber;
public String ServerGroup;
}

View File

@ -10,7 +10,7 @@
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/> <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/> <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value=""/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value=""/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${BUILD_FILES}/common.xml"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${build_files}${BUILD_FILES}/common.xml"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/> <booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Nautilus.Core.CraftBukkit}"/> <stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Nautilus.Core.CraftBukkit}"/>