package games.strategy.engine.framework.headlessGameServer;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Date;
import java.util.Set;
import games.strategy.debug.ClientLogger;
import games.strategy.debug.DebugUtils;
import games.strategy.engine.ClientContext;
import games.strategy.engine.chat.Chat;
import games.strategy.engine.chat.HeadlessChat;
import games.strategy.engine.chat.IChatPanel;
import games.strategy.engine.framework.ServerGame;
import games.strategy.engine.framework.startup.ui.ISetupPanel;
import games.strategy.engine.framework.startup.ui.ServerSetupPanel;
import games.strategy.engine.framework.ui.SaveGameFileChooser;
import games.strategy.net.INode;
import games.strategy.net.IServerMessenger;
public class HeadlessConsoleController {
private final HeadlessGameServer server;
private final PrintStream out;
private final BufferedReader in;
private boolean m_chatMode = false;
public HeadlessConsoleController(final HeadlessGameServer server, final InputStream in, final PrintStream out) {
this.out = checkNotNull(out);
this.in = new BufferedReader(new InputStreamReader(checkNotNull(in)));
this.server = checkNotNull(server);
}
protected void process(final String command) {
if (command.equals("")) {
return;
}
final String noun = command.split("\\s")[0];
if (noun.equalsIgnoreCase("help")) {
showHelp();
} else if (noun.equalsIgnoreCase("status")) {
showStatus();
} else if (noun.equalsIgnoreCase("save")) {
save(command);
} else if (noun.equalsIgnoreCase("stop")) {
stop();
} else if (noun.equalsIgnoreCase("quit")) {
quit();
} else if (noun.equalsIgnoreCase("connections")) {
showConnections();
} else if (noun.equalsIgnoreCase("send")) {
send(command);
} else if (noun.equalsIgnoreCase("chatlog")) {
chatlog();
} else if (noun.equalsIgnoreCase("chatmode")) {
chatmode();
} else if (noun.equalsIgnoreCase("mute")) {
mute(command);
} else if (noun.equalsIgnoreCase("boot")) {
boot(command);
} else if (noun.equalsIgnoreCase("ban")) {
ban(command);
} else if (noun.equalsIgnoreCase("memory")) {
memory();
} else if (noun.equalsIgnoreCase("threads")) {
threads();
} else if (noun.equalsIgnoreCase("dump")) {
printThreadDumpsAndStatus();
} else {
out.println("Unrecognized command:" + command);
showHelp();
}
}
private void send(final String command) {
if (command == null) {
return;
}
final Chat chat = server.getChat();
if (chat == null) {
return;
}
try {
final String message;
if (command.length() > 5) {
message = command.substring(5, command.length());
} else {
out.println("Input chat message: ");
message = in.readLine();
}
chat.sendMessage(message, false);
} catch (final IOException e) {
ClientLogger.logQuietly(e);
}
}
private void chatlog() {
if (server == null) {
return;
}
final IChatPanel chat = server.getServerModel().getChatPanel();
if (chat == null) {
return;
}
out.println();
out.println(chat.getAllText());
out.println();
}
private void chatmode() {
if (server == null) {
return;
}
final IChatPanel chat = server.getServerModel().getChatPanel();
if (chat == null || !(chat instanceof HeadlessChat)) {
return;
}
m_chatMode = !m_chatMode;
out.println("chatmode is now " + (m_chatMode ? "on" : "off"));
final HeadlessChat headlessChat = (HeadlessChat) chat;
headlessChat.setPrintStream(m_chatMode ? out : null);
}
private void printThreadDumpsAndStatus() {
final StringBuilder sb = new StringBuilder();
sb.append("Dump to Log:");
sb.append("\n\nStatus:\n");
sb.append(getStatus());
sb.append("\n\nServer:\n");
sb.append(server == null ? "null" : server.getServerModel());
sb.append("\n\n");
sb.append(DebugUtils.getThreadDumps());
sb.append("\n\n");
sb.append(DebugUtils.getMemory());
sb.append("\n\nDump finished.\n");
HeadlessGameServer.log(sb.toString());
}
private void threads() {
out.println(DebugUtils.getThreadDumps());
}
private void memory() {
out.println(DebugUtils.getMemory());
}
private void mute(final String command) {
if (server.getServerModel() == null) {
return;
}
final IServerMessenger messenger = server.getServerModel().getMessenger();
if (messenger == null) {
return;
}
final Set<INode> nodes = server.getServerModel().getMessenger().getNodes();
if (nodes == null) {
return;
}
try {
final String name;
if (command.length() > 4 && command.split(" ").length > 1) {
name = command.split(" ")[1];
} else {
out.println("Input player name to mute: ");
name = in.readLine();
}
if (name == null || name.length() < 1) {
out.println("Invalid name");
return;
}
final String minutes;
if (command.length() > 4 && command.split(" ").length > 2) {
minutes = command.split(" ")[2];
} else {
out.println("Input minutes to mute: ");
minutes = in.readLine();
}
final long min;
try {
min = Math.max(0, Math.min(60 * 24 * 2, Long.parseLong(minutes))); // max out at 48 hours
} catch (final NumberFormatException nfe) {
out.println("Invalid minutes");
return;
}
final long expire = System.currentTimeMillis() + (min * 1000 * 60); // milliseconds
for (final INode node : nodes) {
final String realName = node.getName().split(" ")[0];
final String ip = node.getAddress().getHostAddress();
final String mac = messenger.getPlayerMac(node.getName());
if (realName.equals(name)) {
messenger.NotifyUsernameMutingOfPlayer(realName, new Date(expire));
messenger.NotifyIPMutingOfPlayer(ip, new Date(expire));
messenger.NotifyMacMutingOfPlayer(mac, new Date(expire));
return;
}
}
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
private void boot(final String command) {
if (server.getServerModel() == null) {
return;
}
final IServerMessenger messenger = server.getServerModel().getMessenger();
if (messenger == null) {
return;
}
final Set<INode> nodes = server.getServerModel().getMessenger().getNodes();
if (nodes == null) {
return;
}
try {
final String name;
if (command.length() > 4 && command.split(" ").length > 1) {
name = command.split(" ")[1];
} else {
out.println("Input player name to boot: ");
name = in.readLine();
}
if (name == null || name.length() < 1) {
out.println("Invalid name");
return;
}
for (final INode node : nodes) {
final String realName = node.getName().split(" ")[0];
if (realName.equals(name)) {
messenger.removeConnection(node);
}
}
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
private void ban(final String command) {
if (server.getServerModel() == null) {
return;
}
final IServerMessenger messenger = server.getServerModel().getMessenger();
if (messenger == null) {
return;
}
final Set<INode> nodes = server.getServerModel().getMessenger().getNodes();
if (nodes == null) {
return;
}
try {
final String name;
if (command.length() > 4 && command.split(" ").length > 1) {
name = command.split(" ")[1];
} else {
out.println("Input player name to ban: ");
name = in.readLine();
}
if (name == null || name.length() < 1) {
out.println("Invalid name");
return;
}
final String hours;
if (command.length() > 4 && command.split(" ").length > 2) {
hours = command.split(" ")[2];
} else {
out.println("Input hours to ban: ");
hours = in.readLine();
}
final long hrs;
try {
hrs = Math.max(0, Math.min(24 * 30, Long.parseLong(hours))); // max out at 30 days
} catch (final NumberFormatException nfe) {
out.println("Invalid minutes");
return;
}
final long expire = System.currentTimeMillis() + (hrs * 1000 * 60 * 60); // milliseconds
for (final INode node : nodes) {
final String realName = node.getName().split(" ")[0];
final String ip = node.getAddress().getHostAddress();
final String mac = messenger.getPlayerMac(node.getName());
if (realName.equals(name)) {
try {
messenger.NotifyUsernameMiniBanningOfPlayer(realName, new Date(expire));
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
try {
messenger.NotifyIPMiniBanningOfPlayer(ip, new Date(expire));
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
try {
messenger.NotifyMacMiniBanningOfPlayer(mac, new Date(expire));
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
messenger.removeConnection(node);
}
}
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
private void save(final String command) {
final ServerGame game = server.getIGame();
if (game == null) {
out.println("No Game Currently Running");
} else {
try {
String saveName;
if (command.length() > 5) {
saveName = command.substring(5, command.length());
} else {
out.println("Input savegame filename: ");
saveName = in.readLine();
}
if (saveName == null || saveName.length() < 2) {
out.println("Invalid save name");
return;
}
if (!saveName.endsWith(".tsvg")) {
saveName += ".tsvg";
}
SaveGameFileChooser.ensureMapsFolderExists();
final File f = new File(ClientContext.folderSettings().getSaveGamePath(), saveName);
try {
game.saveGame(f);
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
} catch (final IOException e) {
ClientLogger.logQuietly(e);
}
}
}
private void stop() {
final ServerGame game = server.getIGame();
if (game == null) {
out.println("No Game Currently Running");
return;
}
out.println("Are you sure? (y/n)");
try {
final String readin = in.readLine();
if (readin == null) {
return;
}
final boolean stop = readin.toLowerCase().startsWith("y");
if (stop) {
SaveGameFileChooser.ensureMapsFolderExists();
final File f1 =
new File(ClientContext.folderSettings().getSaveGamePath(), SaveGameFileChooser.getAutoSaveFileName());
final File f2 =
new File(ClientContext.folderSettings().getSaveGamePath(), SaveGameFileChooser.getAutoSave2FileName());
final File f;
if (f1.lastModified() > f2.lastModified()) {
f = f2;
} else {
f = f1;
}
try {
game.saveGame(f);
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
game.stopGame();
}
} catch (final IOException e) {
ClientLogger.logQuietly(e);
}
}
private void quit() {
out.println("Are you sure? (y/n)");
try {
final String readin = in.readLine();
if (readin != null && readin.toLowerCase().startsWith("y")) {
server.shutdown();
if (server.getSetupPanelModel() != null) {
final ISetupPanel setup = server.getSetupPanelModel().getPanel();
if (setup != null && setup instanceof ServerSetupPanel) {
// this is causing a deadlock when in a shutdown hook, due to swing/awt. so we will shut it down here
// instead.
setup.shutDown();
}
}
System.exit(0);
}
} catch (final IOException e) {
ClientLogger.logQuietly(e);
}
}
private void showConnections() {
out.println(getConnections());
}
private String getConnections() {
final StringBuilder sb = new StringBuilder();
if (server.getServerModel() != null && server.getServerModel().getMessenger() != null) {
sb.append("Connected: ").append(server.getServerModel().getMessenger().isConnected()).append("\n")
.append("Nodes: \n");
final Set<INode> nodes = server.getServerModel().getMessenger().getNodes();
if (nodes == null) {
sb.append(" null\n");
} else {
for (final INode node : nodes) {
sb.append(" ").append(node).append("\n");
}
}
} else {
sb.append("Not Connected to Anything");
}
return sb.toString();
}
private void showStatus() {
out.println(getStatus());
}
private String getStatus() {
return server.getStatus();
}
private void showHelp() {
out.println("Available commands:\n"
+ " help - show this message\n"
+ " status - show status information\n"
+ " dump - prints threads, memory, status, connections, to the log file\n"
+ " connections - show all connected players\n"
+ " mute - mute player\n"
+ " boot - boot player\n"
+ " ban - ban player\n"
+ " send - sends a chat message\n"
+ " chatmode - toggles the showing of chat messages as they come in\n"
+ " chatlog - shows the chat log\n"
+ " memory - show memory usage\n"
+ " threads - get thread dumps\n"
+ " save - saves game to filename\n"
+ " stop - saves then stops current game and goes back to waiting\n"
+ " quit - quit\n");
}
}