From 4824afc412741434005b3b891045e0e98d670865 Mon Sep 17 00:00:00 2001 From: Dries007 Date: Sun, 16 Jul 2017 18:18:30 +0200 Subject: [PATCH] Partial commit. Changes include: - Removed world manager (to be replaced) - Added support for '*' in the CLI. - Reworked restart timer to actually work. - Changed some internals for (hopefully) better performance. - Removed out of date java8 options, since we require java8 anyway. - Removed permgen (java8 again). - Cleaned up some code. --- README.md | 17 +- build.gradle | 2 +- src/main/java/freemarker_implicit.ftl | 1 + .../java/net/doubledoordev/backend/Main.java | 16 +- .../backend/commands/Bindings.java | 12 +- .../backend/commands/CommandHandler.java | 3 +- .../backend/server/BackupTask.java | 2 +- .../doubledoordev/backend/server/JvmData.java | 18 +- .../backend/server/RestartingInfo.java | 199 ++++++++---- .../doubledoordev/backend/server/Server.java | 71 ++--- .../backend/server/WorldManager.java | 10 +- .../net/doubledoordev/backend/util/Cache.java | 291 +++++++++--------- .../doubledoordev/backend/util/Constants.java | 63 +--- .../doubledoordev/backend/util/Helper.java | 29 +- .../backend/util/IUpdateFromJson.java | 29 ++ .../doubledoordev/backend/util/PortRange.java | 7 +- .../doubledoordev/backend/util/Settings.java | 7 - .../util/exceptions/OutOfPortsException.java | 4 +- .../backend/util/winreg/JavaFinder.java | 5 +- .../backend/util/winreg/JavaInfo.java | 1 - .../backend/web/http/FreemarkerHandler.java | 4 +- .../backend/web/http/PostHandler.java | 13 +- .../AdvancedSettingsSocketApplication.java | 92 ++---- .../web/socket/ConsoleSocketApplication.java | 4 +- .../socket/FileManagerSocketApplication.java | 40 +-- .../socket/FileMonitorSocketApplication.java | 25 +- .../ServerControlSocketApplication.java | 25 +- .../ServerMonitorSocketApplication.java | 6 +- .../ServerPropertiesSocketApplication.java | 2 +- .../socket/ServerWebSocketApplication.java | 5 + .../ServerconsoleSocketApplication.java | 2 +- .../web/socket/UsersSocketApplication.java | 28 +- .../socket/WorldManagerSocketApplication.java | 27 +- src/main/resources/licenseTemplate.html | 24 +- .../resources/templates/advancedsettings.ftl | 34 +- src/main/resources/templates/header.ftl | 24 +- src/main/resources/templates/index.ftl | 17 +- src/main/resources/templates/login.ftl | 10 + src/main/resources/templates/newserver.ftl | 20 +- src/main/resources/templates/register.ftl | 47 ++- src/main/resources/templates/server.ftl | 2 +- .../resources/templates/serverconsole.ftl | 25 +- src/main/resources/templates/worldmanager.ftl | 11 +- 43 files changed, 616 insertions(+), 658 deletions(-) create mode 100644 src/main/java/net/doubledoordev/backend/util/IUpdateFromJson.java diff --git a/README.md b/README.md index 650ee12..71c982c 100644 --- a/README.md +++ b/README.md @@ -21,24 +21,13 @@ Typos? [Go here.](https://github.com/DoubleDoorDevelopment/D3Backend/issues/10) 1. Tell us what you clicked exactly (if applicable) 1. If we ask you for more information and you don't replay within 14 days, the issue will be considerer inactive. -ToDo ----- - -- [ ] Implement email system -- [ ] Implement a server wrapper - - [ ] Shut the actual server down if empty, restart if someone connects. - - [ ] Keep clients connected during server restart -- [ ] Multi 'node' support -- [ ] Add a 'look and feel' config (change name, add bootstrap theme, ...) -- [ ] In release: Use minified js and css - -HttpS ------ +Http**S** +--------- Step 1: Make a jks file.
Option 1: [Self signed certificate](https://www.sslshopper.com/article-how-to-create-a-self-signed-certificate-using-java-keytool.html) Please use this for internal network or testing only.
Option 2: [Proper, CA signed certificate](https://docs.oracle.com/cd/E19798-01/821-1751/ghlgv/index.html)
-**Protip:** [CA signed certificates don't have to be expensive...](https://www.startssl.com/)
+**ProTip:** Have a look at LetsEncrypt for a free signed SSL cert. There is no support for it in our backend, but you can run the tool externally. Step 2: Put the path (relative to run dir or absolute) and password in the config file. diff --git a/build.gradle b/build.gradle index 4aed0a2..1f884f6 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ apply plugin: "idea-utils" archivesBaseName = "D3Backend" group = "net.doubledoordev.backend" -version = "0.10.2" +version = "0.11.0" if (System.getenv().BUILD_NUMBER != null) version += "." + System.getenv().BUILD_NUMBER def vendor = "DoubleDoorDevelopment" diff --git a/src/main/java/freemarker_implicit.ftl b/src/main/java/freemarker_implicit.ftl index e05d860..f60b4a4 100644 --- a/src/main/java/freemarker_implicit.ftl +++ b/src/main/java/freemarker_implicit.ftl @@ -3,5 +3,6 @@ [#-- @ftlvariable name="fm" type="net.doubledoordev.backend.server.FileManager" --] [#-- @ftlvariable name="user" type="net.doubledoordev.backend.permissions.User" --] [#-- @ftlvariable name="server" type="net.doubledoordev.backend.server.Server" --] +[#-- @ftlvariable name="wm" type="net.doubledoordev.backend.server.WorldManager" --] [#-- @ftlvariable name="Helper" type="net.doubledoordev.backend.util.Helper" --] [#-- @ftlvariable name="Settings" type="net.doubledoordev.backend.util.Settings" --] diff --git a/src/main/java/net/doubledoordev/backend/Main.java b/src/main/java/net/doubledoordev/backend/Main.java index 82195f1..ba8d5a7 100644 --- a/src/main/java/net/doubledoordev/backend/Main.java +++ b/src/main/java/net/doubledoordev/backend/Main.java @@ -118,7 +118,6 @@ public static void main(String[] args) throws Exception if (debug) LOGGER.info("DEBUG MODE"); if (safe) LOGGER.info("SAFE MODE"); - // todo: get JDK and classload tools.jar + native library; if not jdk: disable warmroast LOGGER.info("\n\n D3Backend Copyright (C) 2015 - 2016 Dries007 & Double Door Development\n" + " This program comes with ABSOLUTELY NO WARRANTY;\n" + " This is free software, and you are welcome to redistribute it under certain conditions;\n" + @@ -129,7 +128,10 @@ public static void main(String[] args) throws Exception for (Object key : properties.keySet()) LOGGER.info("- {} = {}", key, properties.get(key)); LOGGER.info("Making necessary folders..."); - mkdirs(); + //noinspection ResultOfMethodCallIgnored + Constants.SERVERS.mkdir(); + //noinspection ResultOfMethodCallIgnored + Constants.BACKUPS.mkdir(); LOGGER.info("Starting webserver..."); final HttpServer webserver = new HttpServer(); @@ -182,7 +184,7 @@ public static void main(String[] args) throws Exception adminKey = UUID.randomUUID().toString(); LOGGER.warn("Your userlist is empty."); LOGGER.warn("Make a new account and use the special admin token in the '2 + 2 = ?' field."); - LOGGER.warn("You can only use this key once. It will be regenerated if the userlist is empty when the backend starts."); + LOGGER.warn("You can only use this key once. It will be regenerated if the user list is empty when the backend starts."); LOGGER.warn("Admin token: " + adminKey); } @@ -204,17 +206,11 @@ public static void main(String[] args) throws Exception } } - @SuppressWarnings("ResultOfMethodCallIgnored") - private static void mkdirs() - { - Constants.SERVERS.mkdir(); - } - public static synchronized void shutdown() { running = false; + Cache.stop(); Settings.save(); - Cache.init(); LOGGER.info("Attempting graceful shutdown of all servers..."); for (final Server server : SETTINGS.servers.values()) { diff --git a/src/main/java/net/doubledoordev/backend/commands/Bindings.java b/src/main/java/net/doubledoordev/backend/commands/Bindings.java index bf4857c..6848b3f 100644 --- a/src/main/java/net/doubledoordev/backend/commands/Bindings.java +++ b/src/main/java/net/doubledoordev/backend/commands/Bindings.java @@ -45,7 +45,11 @@ public Server getServer(ArgumentStack context) throws ParameterException @BindingMatch(type = Server[].class, behavior = BindingBehavior.CONSUMES) public Server[] getServers(ArgumentStack context) throws ParameterException { - Pattern pattern = Pattern.compile(context.next()); + String selector = context.next(); + if (Settings.getServerByName(selector) != null) return new Server[]{Settings.getServerByName(selector)}; + if (selector.equals("*")) return Settings.SETTINGS.servers.values().toArray(new Server[0]); + + Pattern pattern = Pattern.compile(selector); List servers = new ArrayList<>(); for (Server server : Settings.SETTINGS.servers.values()) if (pattern.matcher(server.getID()).matches()) servers.add(server); return servers.toArray(new Server[servers.size()]); @@ -60,7 +64,11 @@ public User getUser(ArgumentStack context) throws ParameterException @BindingMatch(type = User[].class, behavior = BindingBehavior.CONSUMES, consumedCount = 1) public User[] getUsers(ArgumentStack context) throws ParameterException { - Pattern pattern = Pattern.compile(context.next()); + String selector = context.next(); + if (Settings.getUserByName(selector) != null) return new User[]{Settings.getUserByName(selector)}; + if (selector.equals("*")) return Settings.SETTINGS.users.values().toArray(new User[0]); + + Pattern pattern = Pattern.compile(selector); List users = new ArrayList<>(); for (User server : Settings.SETTINGS.users.values()) if (pattern.matcher(server.getUsername()).matches()) users.add(server); return users.toArray(new User[users.size()]); diff --git a/src/main/java/net/doubledoordev/backend/commands/CommandHandler.java b/src/main/java/net/doubledoordev/backend/commands/CommandHandler.java index 09a305a..5251839 100644 --- a/src/main/java/net/doubledoordev/backend/commands/CommandHandler.java +++ b/src/main/java/net/doubledoordev/backend/commands/CommandHandler.java @@ -153,8 +153,7 @@ public void run() return; } - //todo: open gui - JOptionPane.showMessageDialog(null, "You opened D3Backend without a console. Since we don't have a gui yet, and we need input for commands, this is not supported.\nUse a commandline enviroment to open the jar for now."); + JOptionPane.showMessageDialog(null, "You opened D3Backend without a console. Use a commandline environment to open the jar for now."); System.exit(1); } diff --git a/src/main/java/net/doubledoordev/backend/server/BackupTask.java b/src/main/java/net/doubledoordev/backend/server/BackupTask.java index cc61332..8b56414 100644 --- a/src/main/java/net/doubledoordev/backend/server/BackupTask.java +++ b/src/main/java/net/doubledoordev/backend/server/BackupTask.java @@ -28,7 +28,7 @@ import java.util.TimerTask; /** - * todo: reimplement + * TODO: fix * @author Dries007 */ public class BackupTask extends TimerTask diff --git a/src/main/java/net/doubledoordev/backend/server/JvmData.java b/src/main/java/net/doubledoordev/backend/server/JvmData.java index da9328a..8421d19 100644 --- a/src/main/java/net/doubledoordev/backend/server/JvmData.java +++ b/src/main/java/net/doubledoordev/backend/server/JvmData.java @@ -18,23 +18,33 @@ package net.doubledoordev.backend.server; +import com.google.gson.JsonObject; import com.google.gson.annotations.Expose; +import net.doubledoordev.backend.util.IUpdateFromJson; /** * @author Dries007 */ -public class JvmData +public class JvmData implements IUpdateFromJson { @Expose - public int ramMin = 1024; + public int ramMin = 512; @Expose public int ramMax = 2048; @Expose - public int permGen = 128; - @Expose public String extraJavaParameters = ""; @Expose public String extraMCParameters = ""; @Expose public String jarName = "minecraft_server.jar"; + + @Override + public void updateFrom(JsonObject json) + { + if (json.has("ramMin")) ramMin = json.get("ramMin").getAsInt(); + if (json.has("ramMax")) ramMax = json.get("ramMax").getAsInt(); + if (json.has("extraJavaParameters")) extraJavaParameters = json.get("extraJavaParameters").getAsString(); + if (json.has("extraMCParameters")) extraMCParameters = json.get("extraMCParameters").getAsString(); + if (json.has("jarName")) jarName = json.get("jarName").getAsString(); + } } diff --git a/src/main/java/net/doubledoordev/backend/server/RestartingInfo.java b/src/main/java/net/doubledoordev/backend/server/RestartingInfo.java index 83b2012..c67e644 100644 --- a/src/main/java/net/doubledoordev/backend/server/RestartingInfo.java +++ b/src/main/java/net/doubledoordev/backend/server/RestartingInfo.java @@ -18,23 +18,30 @@ package net.doubledoordev.backend.server; +import com.google.gson.JsonObject; import com.google.gson.annotations.Expose; +import net.doubledoordev.backend.Main; +import net.doubledoordev.backend.util.IUpdateFromJson; import java.text.SimpleDateFormat; -import java.util.Calendar; +import java.time.ZonedDateTime; import java.util.Date; +import java.util.Timer; +import java.util.TimerTask; + +import static java.time.temporal.ChronoField.*; /** + * The auto-restart doesn't need to be on a repeated timer, because the shutdown and boot will stop and restart the timer. + * * @author Dries007 */ -public class RestartingInfo +public class RestartingInfo implements IUpdateFromJson { + private static final int[] COUNTDOWN = new int[] {15, 10, 5, 4, 3, 2, 1}; + @Expose public boolean autoStart = false; -// @Expose -// public int globalTimeout = 24; -// @Expose -// public int whenEmptyTimeout = -1; @Expose public boolean enableRestartSchedule = false; @Expose @@ -44,91 +51,151 @@ public class RestartingInfo @Expose public String restartScheduleMessage = "Server reboot in %time minutes!"; - private boolean restartNextRun = false; - private ScheduleStep runningSchedule = ScheduleStep.NONE; + @Override + public void updateFrom(JsonObject json) + { + if (json.has("autoStart")) autoStart = json.get("autoStart").getAsBoolean(); + + if (json.has("enableRestartSchedule")) enableRestartSchedule = json.get("enableRestartSchedule").getAsBoolean(); + if (json.has("restartScheduleHours")) restartScheduleHours = json.get("restartScheduleHours").getAsInt(); + if (json.has("restartScheduleMinutes")) restartScheduleMinutes = json.get("restartScheduleMinutes").getAsInt(); + + if (json.has("enableRestartSchedule") || json.has("restartScheduleHours") || json.has("restartScheduleMinutes")) + { + start(); + } + + if (json.has("restartScheduleMessage")) restartScheduleMessage = json.get("restartScheduleMessage").getAsString(); + } + + private Server server; + + public void init(Server server) + { + this.server = server; + } + + private Timer timer; private Date lastRestart; + private Date nextRestart; - public void run(Server server) + public void start() { - // To restart the server after it has been stopped by us. - try + if (timer != null) stop(); + if (!enableRestartSchedule) return; + timer = new Timer(); + + ZonedDateTime now = ZonedDateTime.now(); + ZonedDateTime restartTime = now.with(HOUR_OF_DAY, restartScheduleHours).with(MINUTE_OF_HOUR, restartScheduleMinutes).with(SECOND_OF_MINUTE, 0).with(MICRO_OF_SECOND, 0); + if (restartTime.minusMinutes(1).isBefore(now)) restartTime = restartTime.plusDays(1); + + nextRestart = Date.from(restartTime.toInstant()); + + for (int minuteOffset : COUNTDOWN) { - if (!server.getOnline() && !server.isDownloading() && restartNextRun) + ZonedDateTime warningTime = restartTime.minusMinutes(minuteOffset); + if (warningTime.isBefore(now)) continue; + timer.schedule(new TimerTask() { - server.startServer(); - restartNextRun = false; - } + @Override + public void run() + { + server.sendChat(restartScheduleMessage.replace("%time", Integer.toString(minuteOffset))); + } + }, Date.from(warningTime.toInstant())); } - catch (Exception e) + + timer.schedule(new TimerTask() { - e.printStackTrace(); - } + @Override + public void run() + { + lastRestart = new Date(); + server.printLine("[AutoRestart] Sending stop command..."); + server.stopServer("[AutoRestart] Restarting on schedule."); + waitForShutdown(150); + if (server.getOnline()) + { + server.printLine("[AutoRestart] Force-stopping server..."); + try + { + server.forceStopServer(); + waitForShutdown(30); + } + catch (Exception ignored) + { - if (!server.getOnline()) return; -// if (lastRestart != null && System.currentTimeMillis() - lastRestart.getTime() < globalTimeout * 3600000) return; + } + if (server.getOnline()) + { + server.printLine("[AutoRestart] Murdering server..."); + try + { + server.murderServer(); + waitForShutdown(30); + } + catch (Exception ignored) + { - // Restart Schedule - if (enableRestartSchedule) - { - Calendar calendar = Calendar.getInstance(); - switch (runningSchedule) + } + if (server.getOnline()) + { + server.printLine("[AutoRestart] Failed to make server stop. Can't restart it."); + Main.LOGGER.error("[AutoRestart] Failed to restart {}. It wouldn't stop.", server); + return; + } + } + } + + try + { + server.printLine("[AutoRestart] Restarting the server..."); + Thread.sleep(1000); + server.startServer(); + } + catch (Exception e) + { + server.printLine("[AutoRestart] Failed to start the server. " + e.getClass().getSimpleName() + ": " + e.getMessage()); + } + } + + private void waitForShutdown(int maxDelay) { - case NONE: - calendar.add(Calendar.MINUTE, 15); - if (calendar.get(Calendar.HOUR_OF_DAY) == restartScheduleHours && calendar.get(Calendar.MINUTE) == restartScheduleMinutes) + while (server.getOnline() && maxDelay > 0) + { + server.printLine("[AutoRestart] Waiting for shutdown. (" + maxDelay + "s of patience left.)"); + maxDelay--; + try { - runningSchedule = ScheduleStep.M15; + Thread.sleep(1000); } - break; - default: - calendar.add(Calendar.MINUTE, runningSchedule.timeLeft); - if (calendar.get(Calendar.HOUR_OF_DAY) == restartScheduleHours && calendar.get(Calendar.MINUTE) == restartScheduleMinutes) + catch (InterruptedException ignored) { - server.sendChat(restartScheduleMessage.replace("%time", Integer.toString(runningSchedule.timeLeft))); - runningSchedule = runningSchedule.nextStep; + } - break; - case NOW: - runningSchedule = ScheduleStep.NONE; - initReboot(server, "Restarting on schedule."); + } } - } - // Empty check -// if (server.getPlayerList().size() == 0 && whenEmptyTimeout != -1) -// { -// if (emptyDate == null) emptyDate = new Date(); -// else if (System.currentTimeMillis() - emptyDate.getTime() > whenEmptyTimeout * 60000) -// { -// initReboot(server, "Server restart because empty."); -// } -// } -// else emptyDate = null; + }, Date.from(restartTime.toInstant())); } - private void initReboot(Server server, String s) + public void stop() { - lastRestart = new Date(); - server.stopServer(s); - restartNextRun = true; + if (timer == null) return; + + timer.cancel(); + timer.purge(); + timer = null; + nextRestart = null; } public String getLastRestart(String format) { - return lastRestart == null ? "" : new SimpleDateFormat(format).format(lastRestart); + return lastRestart == null ? "None." : new SimpleDateFormat(format).format(lastRestart); } - public enum ScheduleStep + public String getNextRestart(String format) { - NONE(-1, null), NOW(0, NONE), M1(1, NOW), M2(2, M1), M3(3, M2), M4(4, M3), M5(5, M4), M10(10, M5), M15(15, M10); - - public final int timeLeft; - public final ScheduleStep nextStep; - - ScheduleStep(int timeLeft, ScheduleStep nextStep) - { - this.timeLeft = timeLeft; - this.nextStep = nextStep != null ? nextStep : this; - } + return nextRestart == null ? "None." : new SimpleDateFormat(format).format(nextRestart); } } diff --git a/src/main/java/net/doubledoordev/backend/server/Server.java b/src/main/java/net/doubledoordev/backend/server/Server.java index fbbc5fb..ef75155 100644 --- a/src/main/java/net/doubledoordev/backend/server/Server.java +++ b/src/main/java/net/doubledoordev/backend/server/Server.java @@ -65,16 +65,12 @@ public class Server public static final String QUERY_PORT = "query.port"; public static final String QUERY_ENABLE = "enable-query"; public static final String SERVER_IP = "server-ip"; - @Expose - private final Map dimensionMap = new HashMap<>(); /** * Diskspace var + timer to avoid long page load times. */ public int[] size = new int[3]; public QueryResponse cachedResponse; - /* - * START exposed Json data - */ + @Expose private String ID; @Expose @@ -87,15 +83,11 @@ public class Server private List admins = new ArrayList<>(); @Expose private List coOwners = new ArrayList<>(); - /* - * END exposed Json data - */ @Expose private RestartingInfo restartingInfo = new RestartingInfo(); @Expose private JvmData jvmData = new JvmData(); - //@Expose - //private RoastOptions roastOptions = new RoastOptions(); + /** * Used to reroute server output to our console. * NOT LOGGED TO FILE! @@ -147,6 +139,8 @@ public void init() if (!backupFolder.exists()) backupFolder.mkdirs(); if (!folder.exists()) folder.mkdir(); + getRestartingInfo().init(this); + try { SizeCounter sizeCounter = new SizeCounter(); @@ -219,7 +213,14 @@ public Properties getProperties() e.printStackTrace(); } } - normalizeProperties(); + try + { + normalizeProperties(); + } + catch (IOException e) + { + e.printStackTrace(); + } return properties; } @@ -256,16 +257,8 @@ public String getProperty(String key) */ public boolean getOnline() { - try - { - if (process == null) return false; - process.exitValue(); - return false; - } - catch (IllegalThreadStateException e) - { - return true; - } + if (process == null) return false; + return process.isAlive(); } /** @@ -398,11 +391,6 @@ public WorldManager getWorldManager() return worldManager; } - public Map getDimensionMap() - { - return dimensionMap; - } - public File getFolder() { return folder; @@ -471,6 +459,7 @@ public void setOwner(IMethodCaller methodCaller, String username) public void setServerPort(IMethodCaller caller, int serverPort) throws IOException { if (!isCoOwner(caller.getUser())) throw new AuthenticationException(); + if (!Settings.SETTINGS.portRange.isInRange(serverPort)) throw new IOException("Illegal port. Must be in range: " + Settings.SETTINGS.portRange); this.serverPort = serverPort; normalizeProperties(); } @@ -951,11 +940,11 @@ public void startServer() throws Exception if (user == null) throw new Exception("No owner set??"); if (user.getMaxRamLeft() != -1 && getJvmData().ramMax > user.getMaxRamLeft()) throw new Exception("Out of usable RAM. Lower your max RAM."); saveProperties(); - starting = true; final Server instance = this; for (String blocked : SERVER_START_ARGS_BLACKLIST_PATTERNS) if (getJvmData().extraJavaParameters.contains(blocked)) throw new Exception("JVM/MC options contain a blocked option: " + blocked); for (String blocked : SERVER_START_ARGS_BLACKLIST_PATTERNS) if (getJvmData().extraMCParameters.contains(blocked)) throw new Exception("JVM/MC options contain a blocked option: " + blocked); + starting = true; File eula = new File(getFolder(), "eula.txt"); try { @@ -975,20 +964,18 @@ public void startServer() throws Exception printLine("Starting server ................"); try { - /** - * Build arguments list. + /* + Build arguments list. */ List arguments = new ArrayList<>(); arguments.add(Constants.getJavaPath()); - arguments.add("-DServerOwner=\"" + owner + '"'); + arguments.add("-DServerID=\"" + ID + '"'); arguments.add("-server"); { int amount = getJvmData().ramMin; if (amount > 0) arguments.add(String.format("-Xms%dM", amount)); amount = getJvmData().ramMax; if (amount > 0) arguments.add(String.format("-Xmx%dM", amount)); - amount = getJvmData().permGen; - if (amount > 0) arguments.add(String.format("-XX:MaxPermSize=%dm", amount)); } if (Strings.isNotBlank(getJvmData().extraJavaParameters)) { @@ -1005,15 +992,19 @@ public void startServer() throws Exception // Debug printout printLine("Arguments: " + arguments.toString()); - /** - * Make ProcessBuilder, set rundir, and make sure the io gets redirected + /* + Make ProcessBuilder, set rundir, and make sure the io gets redirected */ ProcessBuilder pb = new ProcessBuilder(arguments); pb.directory(folder); pb.redirectErrorStream(true); - if (!new File(folder, getJvmData().jarName).exists()) return; // for reasons of WTF? + if (!new File(folder, getJvmData().jarName).exists()) + { + throw new FileNotFoundException("JarFile went missing in the 0.2 sec it takes for the server to start."); + } process = pb.start(); startTime = System.currentTimeMillis(); + getRestartingInfo().start(); new Thread(() -> { try @@ -1032,6 +1023,7 @@ public void startServer() throws Exception { error(e); } + getRestartingInfo().stop(); }, ID.concat("-streamEater")).start(); instance.update(); } @@ -1040,7 +1032,7 @@ public void startServer() throws Exception error(e); } starting = false; - }, "ServerStarter-" + getID()).start(); // <-- Very important call. + }, "ServerStarter-" + getID()).start(); } public void printLine(String line) @@ -1162,7 +1154,7 @@ public void sendCmd(String s) * PRIVATE METHODS */ - private void normalizeProperties() + private void normalizeProperties() throws IOException { if (!properties.containsKey(SERVER_IP)) properties.setProperty(SERVER_IP, ip); if (!properties.containsKey(SERVER_PORT)) properties.setProperty(SERVER_PORT, String.valueOf(serverPort)); @@ -1176,6 +1168,11 @@ private void normalizeProperties() else { serverPort = Integer.parseInt(properties.getProperty(SERVER_PORT, String.valueOf(serverPort))); + if (!Settings.SETTINGS.portRange.isInRange(serverPort)) + { + serverPort = Settings.SETTINGS.portRange.getNextAvailablePort(); + + } properties.setProperty(QUERY_PORT, String.valueOf(serverPort)); } diff --git a/src/main/java/net/doubledoordev/backend/server/WorldManager.java b/src/main/java/net/doubledoordev/backend/server/WorldManager.java index db305f9..0739d41 100644 --- a/src/main/java/net/doubledoordev/backend/server/WorldManager.java +++ b/src/main/java/net/doubledoordev/backend/server/WorldManager.java @@ -38,9 +38,10 @@ /** * Handles backups and dimension related stuff * + * TODO: fix + * * @author Dries007 */ -@SuppressWarnings("UnusedDeclaration") public class WorldManager { public final Server server; @@ -54,13 +55,6 @@ public WorldManager(Server server) public void update() { worldFolder = new File(server.getFolder(), getWorldName()); - if (!worldFolder.exists()) return; - if (worldFolder.list().length == 0) return; - if (!server.getDimensionMap().containsKey(OVERWORLD)) server.getDimensionMap().put(OVERWORLD, new Dimension(OVERWORLD)); - for (String file : worldFolder.list(DIM_ONLY_FILTER)) - { - if (!server.getDimensionMap().containsKey(file)) server.getDimensionMap().put(file, new Dimension(file)); - } } public String getWorldName() diff --git a/src/main/java/net/doubledoordev/backend/util/Cache.java b/src/main/java/net/doubledoordev/backend/util/Cache.java index 719b6e0..4f79f49 100644 --- a/src/main/java/net/doubledoordev/backend/util/Cache.java +++ b/src/main/java/net/doubledoordev/backend/util/Cache.java @@ -41,15 +41,27 @@ import static net.doubledoordev.backend.util.Constants.*; /** - * Contains static Runnables that are used often + * Contains static TimerTasks that are used often * * @author Dries007 */ -public class Cache extends TimerTask +public class Cache { + private static final long REALLY_LONG_CACHE_TIMEOUT = 1000 * 60 * 60 * 24; // 24 hours + private static final long LONG_CACHE_TIMEOUT = 1000 * 60 * 60; // 1 hour + private static final long MEDIUM_CACHE_TIMEOUT = 1000 * 60; // 1 minute + private static final long SHORT_CACHE_TIMEOUT = 1000 * 10; // 10 seconds + + private Cache() { throw new AssertionError(); } + + /** + * isDaemon = true, so cache won't keeps the JVM running, even if for some reason the stop function doesn't get called. + */ + private static final Timer TIMER = new Timer("Cache-Timer", true); + private static final int FORGE_MAP_CAPACITY = 2000; private static final LinkedHashMap FORGE_NAME_VERSION_MAP = new LinkedHashMap<>(FORGE_MAP_CAPACITY); - private static final Runnable FORGE_VERSIONS_DOWNLOADER = new Runnable() + private static final TimerTask FORGE_VERSIONS_DOWNLOADER = new TimerTask() { private boolean hasInstaller(JsonObject object) { @@ -168,112 +180,176 @@ public void run() } }; private static final Map CASHED_MC_VERSIONS = new LinkedHashMap<>(); - private static final Runnable MC_VERSIONS_DOWNLOADER = () -> + private static final TimerTask MC_VERSIONS_DOWNLOADER = new TimerTask() { - JsonObject versionList; - try - { - Reader sr = new InputStreamReader(new URL(Constants.MC_VERIONS_URL).openStream()); - versionList = Constants.JSONPARSER.parse(sr).getAsJsonObject(); - sr.close(); - } - catch (IOException e) + @Override + public void run() { - e.printStackTrace(); - return; + JsonObject versionList; + try + { + Reader sr = new InputStreamReader(new URL(Constants.MC_VERIONS_URL).openStream()); + versionList = Constants.JSONPARSER.parse(sr).getAsJsonObject(); + sr.close(); + } + catch (IOException e) + { + e.printStackTrace(); + return; + } + synchronized (CASHED_MC_VERSIONS) + { + CASHED_MC_VERSIONS.clear(); + for (JsonElement element : versionList.getAsJsonArray("versions")) + { + JsonObject o = element.getAsJsonObject(); + if (!o.get("type").getAsString().equals("release") && !o.get("type").getAsString().equals("snapshot")) + continue; + try + { + CASHED_MC_VERSIONS.put(o.get("id").getAsString(), new URL(o.get("url").getAsString())); + } + catch (MalformedURLException e) + { + e.printStackTrace(); + } + } + } } - synchronized (CASHED_MC_VERSIONS) + }; + private static final TimerTask SIZE_COUNTER = new TimerTask() + { + @Override + public void run() { - CASHED_MC_VERSIONS.clear(); - for (JsonElement element : versionList.getAsJsonArray("versions")) + for (Server server : Settings.SETTINGS.servers.values()) { - JsonObject o = element.getAsJsonObject(); - if (!o.get("type").getAsString().equals("release") && !o.get("type").getAsString().equals("snapshot")) continue; + if (server.getFolder() == null || server.getBackupFolder() == null) continue; try { - CASHED_MC_VERSIONS.put(o.get("id").getAsString(), new URL(o.get("url").getAsString())); + SizeCounter sizeCounter = new SizeCounter(); + if (server.getFolder().exists()) Files.walkFileTree(server.getFolder().toPath(), sizeCounter); + server.size[0] = sizeCounter.getSizeInMB(); + sizeCounter = new SizeCounter(); + if (server.getBackupFolder().exists()) + Files.walkFileTree(server.getBackupFolder().toPath(), sizeCounter); + server.size[1] = sizeCounter.getSizeInMB(); + server.size[2] = server.size[0] + server.size[1]; } - catch (MalformedURLException e) + catch (IOException e) { e.printStackTrace(); } } } }; - private static final Runnable SIZE_COUNTER = () -> + private static boolean hasUpdate = false; + private static String updatedVersion = ""; + private static final TimerTask UPDATE_CHECKER = new TimerTask() { - for (Server server : Settings.SETTINGS.servers.values()) + @Override + public void run() { - if (server.getFolder() == null || server.getBackupFolder() == null) continue; try { - SizeCounter sizeCounter = new SizeCounter(); - if (server.getFolder().exists()) Files.walkFileTree(server.getFolder().toPath(), sizeCounter); - server.size[0] = sizeCounter.getSizeInMB(); - sizeCounter = new SizeCounter(); - if (server.getBackupFolder().exists()) Files.walkFileTree(server.getBackupFolder().toPath(), sizeCounter); - server.size[1] = sizeCounter.getSizeInMB(); - server.size[2] = server.size[0] + server.size[1]; + InputStream inputStream = new URL(VERSION_CHECKER_URL).openStream(); + JsonObject object = JSONPARSER.parse(new InputStreamReader(inputStream)).getAsJsonObject().getAsJsonObject("lastStableBuild"); + + if (!object.get("number").getAsString().equalsIgnoreCase(Main.build)) + { + hasUpdate = true; + JsonArray artifacts = object.getAsJsonArray("artifacts"); + for (int i = 0; i < artifacts.size(); i++) + { + Matcher matcher = Constants.VERSION_PATTERN.matcher(artifacts.get(i).getAsJsonObject().get("fileName").getAsString()); + if (!matcher.find()) continue; + updatedVersion = matcher.group(); + Main.LOGGER.warn("Version out of date! New version: " + updatedVersion); + break; + } + } + + inputStream.close(); } - catch (IOException e) + catch (Exception e) { e.printStackTrace(); } } }; - /** - * Forge version related things - */ - private static long lastForgeVersions = 0L; - /** - * MC version related things - */ - private static long lastMCVersions = 0L; - /** - * Size counter related things - */ - private static long lastSize = 0L; - /** - * - */ - private static boolean hasUpdate = false; - private static String updatedVersion = ""; - private static final Runnable UPDATE_CHECKER = () -> + + private static final TimerTask SERVER_INFO_CHECKER = new TimerTask() { - try + @Override + public void run() { - InputStream inputStream = new URL(VERSION_CHECKER_URL).openStream(); - JsonObject object = JSONPARSER.parse(new InputStreamReader(inputStream)).getAsJsonObject().getAsJsonObject("lastStableBuild"); - - if (!object.get("number").getAsString().equalsIgnoreCase(Main.build)) + try { - hasUpdate = true; - JsonArray artifacts = object.getAsJsonArray("artifacts"); - for (int i = 0; i < artifacts.size(); i++) + for (Server server : Settings.SETTINGS.servers.values()) { - Matcher matcher = Constants.VERSION_PATTERN.matcher(artifacts.get(i).getAsJsonObject().get("fileName").getAsString()); - if (!matcher.find()) continue; - updatedVersion = matcher.group(); - Main.LOGGER.warn("Version out of date! New version: " + updatedVersion); - break; + if (!server.getOnline()) + { + server.cachedResponse = null; + } + else + { + try + { + server.renewQuery(); + } + catch (Exception e) + { + Main.LOGGER.error("Exception while doing queryRenew on server: " + server.getID(), e); + } + } } } - - inputStream.close(); + catch (Exception e) + { + e.printStackTrace(); + } } - catch (Exception e) + }; + + public static void init() + { + if (FORGE_FILE.exists()) { - e.printStackTrace(); + try + { + //noinspection unchecked + FORGE_NAME_VERSION_MAP.putAll(GSON.fromJson(FileUtils.readFileToString(FORGE_FILE), Map.class)); + } + catch (IOException e) + { + e.printStackTrace(); + } } - }; - /** - * Timer related things - */ - private static Cache instance; - private Cache() + TIMER.scheduleAtFixedRate(UPDATE_CHECKER, 1000 * Constants.RANDOM.nextInt(300), REALLY_LONG_CACHE_TIMEOUT); + TIMER.scheduleAtFixedRate(MC_VERSIONS_DOWNLOADER, 1000 * Constants.RANDOM.nextInt(300), REALLY_LONG_CACHE_TIMEOUT); + + TIMER.scheduleAtFixedRate(FORGE_VERSIONS_DOWNLOADER, 100 * Constants.RANDOM.nextInt(300), LONG_CACHE_TIMEOUT); + + TIMER.scheduleAtFixedRate(SIZE_COUNTER, 10 * Constants.RANDOM.nextInt(300), MEDIUM_CACHE_TIMEOUT); + + TIMER.scheduleAtFixedRate(SERVER_INFO_CHECKER, Constants.RANDOM.nextInt(300), SHORT_CACHE_TIMEOUT); + } + + public static void stop() + { + TIMER.cancel(); + TIMER.purge(); + } + + public static void forceUpdateForge() { + new Thread(FORGE_VERSIONS_DOWNLOADER, "forced-forgeVersionDownloader").start(); + } + public static void forceUpdateMC() + { + new Thread(MC_VERSIONS_DOWNLOADER, "forced-mcVersionDownloader").start(); } public static Collection getForgeNames() @@ -300,73 +376,4 @@ public static String getUpdateVersion() { return updatedVersion; } - - public static void init() - { - if (instance != null) return; - instance = new Cache(); - if (FORGE_FILE.exists()) - { - try - { - //noinspection unchecked - FORGE_NAME_VERSION_MAP.putAll(GSON.fromJson(FileUtils.readFileToString(FORGE_FILE), Map.class)); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - TIMER.scheduleAtFixedRate(instance, 0, SHORT_CACHE_TIMEOUT); - } - - @Override - public void run() - { - long now = System.currentTimeMillis(); - - if (now - lastMCVersions > REALLY_LONG_CACHE_TIMEOUT) - { - new Thread(MC_VERSIONS_DOWNLOADER, "cache-mcVersionDownloader").start(); - new Thread(UPDATE_CHECKER, "cache-updateChecking").start(); - lastMCVersions = now; - } - if (now - lastSize > MEDIUM_CACHE_TIMEOUT) - { - new Thread(SIZE_COUNTER, "cache-sizeCounter").start(); - lastSize = now; - } - if (now - lastForgeVersions > LONG_CACHE_TIMEOUT) - { - new Thread(FORGE_VERSIONS_DOWNLOADER, "cache-forgeVersionDownloader").start(); - lastForgeVersions = now; - } - - new Thread(() -> - { - for (Server server : Settings.SETTINGS.servers.values()) - { - server.getRestartingInfo().run(server); - if (!server.getOnline()) continue; - try - { - server.renewQuery(); - } - catch (Exception e) - { - Main.LOGGER.error("Exception while doing queryRenew on server: " + server.getID(), e); - } - } - }, "cache-rConAndQuery").start(); - } - - public static void forceUpdateForge() - { - new Thread(FORGE_VERSIONS_DOWNLOADER, "forced-forgeVersionDownloader").start(); - } - - public static void forceUpdateMC() - { - new Thread(MC_VERSIONS_DOWNLOADER, "forced-mcVersionDownloader").start(); - } } diff --git a/src/main/java/net/doubledoordev/backend/util/Constants.java b/src/main/java/net/doubledoordev/backend/util/Constants.java index 88eecaf..c26d05c 100644 --- a/src/main/java/net/doubledoordev/backend/util/Constants.java +++ b/src/main/java/net/doubledoordev/backend/util/Constants.java @@ -61,18 +61,10 @@ public class Constants public static final String DIM = "DIM"; public static final String OVERWORLD = "Overworld"; public static final String FORGE_USER_AGENT = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)"; - /* - * FilenameFilter constants - */ - public final static FilenameFilter NOT_DIM_FILTER = (dir, name) -> !name.startsWith(DIM); - public final static FilenameFilter DIM_ONLY_FILTER = (dir, name) -> name.startsWith(DIM); public static final String RESTARTING_INFO = "RestartingInfo"; public static final String JVM_DATA = "JvmData"; public static final String TEMPLATE_EXTENSION = ".ftl"; public static final String ERROR_TEMPLATE = "error.ftl"; - /* - * URL and PATH constants - */ public static final String SLASH_STR = "/"; public static final String STATIC_PATH = "/static/"; public static final String TEMPLATES_PATH = "/templates/"; @@ -90,9 +82,16 @@ public class Constants public static final String FORGE_VERIONS_URL = "http://files.minecraftforge.net/maven/net/minecraftforge/forge/json"; public static final String FORGE_INSTALLER_URL = "http://files.minecraftforge.net/maven/net/minecraftforge/forge/%ID%/forge-%ID%-installer.jar"; public static final String VERSION_CHECKER_URL = "https://jenkins.dries007.net/job/D3Backend/api/json?tree=lastStableBuild[number,artifacts[*]]"; - /* - * File constants - */ + + public final static FilenameFilter NOT_DIM_FILTER = (dir, name) -> !name.startsWith(DIM); + public final static FilenameFilter DIM_ONLY_FILTER = (dir, name) -> name.startsWith(DIM); + + public final static FilenameFilter ACCEPT_ALL_JAR_FILTER = (dir, name) -> FilenameUtils.getExtension(name).equals("jar"); + public final static FilenameFilter ACCEPT_ALL_FILTER = (dir, name) -> !name.equalsIgnoreCase("eula.txt"); + public final static FilenameFilter ACCEPT_NONE_FILTER = (dir, name) -> false; + public final static FilenameFilter ACCEPT_FORGE_FILTER = (dir, name) -> (name.startsWith("forge") || name.startsWith("FTBserver")) && ACCEPT_ALL_JAR_FILTER.accept(dir, name); + public final static FilenameFilter ACCEPT_MINECRAFT_SERVER_FILTER = (dir, name) -> name.startsWith("minecraft_server") && ACCEPT_ALL_JAR_FILTER.accept(dir, name); + public static final File ROOT = getRootFile(); public static final File CONFIG_FILE = new File(ROOT, "config.json"); public static final File SERVERS_FILE = new File(ROOT, "servers.json"); @@ -100,48 +99,20 @@ public class Constants public static final File FORGE_FILE = new File(ROOT, "forge.json"); public static final File SERVERS = new File(ROOT, "servers"); public static final File BACKUPS = new File(ROOT, "backups"); - /* - * Time constants - */ - public static final long SOCKET_PING_TIME = 1000 * 50; // 50 seconds - public static final long REALLY_LONG_CACHE_TIMEOUT = 1000 * 60 * 60 * 24; // 24 hours - public static final long LONG_CACHE_TIMEOUT = 1000 * 60 * 60; // 1 hour - public static final long MEDIUM_CACHE_TIMEOUT = 1000 * 60; // 1 minute - public static final long SHORT_CACHE_TIMEOUT = 1000 * 10; // 10 seconds - /* - * Pattern constants - */ - public static final Pattern USERNAME_PATTERN = Pattern.compile("^[\\w-]+$"); + + public static final Pattern USERNAME_PATTERN = Pattern.compile("^[0-9A-Za-z]+$"); + public static final Pattern SERVERNAME_PATTERN = Pattern.compile("^\\w+$"); public static final Pattern VERSION_PATTERN = Pattern.compile("\\d+(?:\\.\\d+)+"); + public static final String SERVER_START_ARGS_BLACKLIST_PATTERNS[] = {"-Xms", "-Xmx", "-XX:MaxPermSize"}; - public final static FilenameFilter ACCEPT_ALL_JAR_FILTER = (dir, name) -> FilenameUtils.getExtension(name).equals("jar"); - public final static FilenameFilter ACCEPT_ALL_FILTER = (dir, name) -> !name.equalsIgnoreCase("eula.txt"); - public final static FilenameFilter ACCEPT_NONE_FILTER = (dir, name) -> false; - public final static FilenameFilter ACCEPT_FORGE_FILTER = (dir, name) -> (name.startsWith("forge") || name.startsWith("FTBserver")) && ACCEPT_ALL_JAR_FILTER.accept(dir, name); - public final static FilenameFilter ACCEPT_MINECRAFT_SERVER_FILTER = (dir, name) -> name.startsWith("minecraft_server") && ACCEPT_ALL_JAR_FILTER.accept(dir, name); - /* - * JSON constants - */ public static final Gson GSON = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().disableHtmlEscaping().setPrettyPrinting().create(); public static final JsonParser JSONPARSER = new JsonParser(); - /* - * Joiner constants - */ public static final Joiner JOINER_COMMA_SPACE = Joiner.on(", "); - public static final Joiner JOINER_COMMA = Joiner.on(','); - public static final Joiner JOINER_SPACE = Joiner.on(' '); - /* - * Special constants - * Can be order sensitive! - */ - public static final Random RANDOM = new Random(); public static final SimpleDateFormat BACKUP_SDF = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); - public static final Timer TIMER = new Timer(); - public static String javaPath; + public static final Random RANDOM = new Random(); + + private static String javaPath; - /** - * Methods that only get called to init the Constants - */ private Constants() { } diff --git a/src/main/java/net/doubledoordev/backend/util/Helper.java b/src/main/java/net/doubledoordev/backend/util/Helper.java index 4eba2be..6d96dcf 100644 --- a/src/main/java/net/doubledoordev/backend/util/Helper.java +++ b/src/main/java/net/doubledoordev/backend/util/Helper.java @@ -22,6 +22,8 @@ import com.flowpowered.nbt.stream.NBTInputStream; import com.flowpowered.nbt.stream.NBTOutputStream; import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import net.doubledoordev.backend.Main; import net.doubledoordev.backend.server.Server; @@ -38,7 +40,6 @@ import java.util.*; import static net.doubledoordev.backend.util.Constants.JSONPARSER; -import static net.doubledoordev.backend.util.Constants.RANDOM; import static net.doubledoordev.backend.util.Settings.SETTINGS; /** @@ -50,7 +51,7 @@ @SuppressWarnings("UnusedDeclaration") public class Helper { - public static final Map UUID_USERNMAME_MAP = new HashMap<>(); + private static final Map UUID_USERNMAME_MAP = new HashMap<>(); private static final SimpleDateFormat BAN_SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.##"); @@ -103,7 +104,7 @@ public static char[] randomCharArray(int length) final char[] buf = new char[length]; - for (int idx = 0; idx < buf.length; ++idx) buf[idx] = symbols[RANDOM.nextInt(symbols.length)]; + for (int idx = 0; idx < buf.length; ++idx) buf[idx] = symbols[Constants.RANDOM.nextInt(symbols.length)]; return buf; } @@ -374,4 +375,26 @@ public static URL getFinalURL(String url) throws IOException } throw new IOException("Redirect limit (" + MAX_REDIRECTS + ") exceeded on url: " + url); } + + public static void doWebMethodCall(WebSocket socket, String text, Object o) + { + try + { + JsonObject object = JSONPARSER.parse(text).getAsJsonObject(); + String name = object.get("method").getAsString(); + ArrayList args = new ArrayList<>(); + if (object.has("args")) for (JsonElement arg : object.getAsJsonArray("args")) args.add(arg.getAsString()); + IMethodCaller methodCaller = Helper.invokeWithRefectionMagic(socket, o, name, args); + if (methodCaller == null) + { + WebSocketHelper.sendOk(socket); + socket.close(); + } + } + catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) + { + WebSocketHelper.sendError(socket, e); + socket.close(); + } + } } diff --git a/src/main/java/net/doubledoordev/backend/util/IUpdateFromJson.java b/src/main/java/net/doubledoordev/backend/util/IUpdateFromJson.java new file mode 100644 index 0000000..b212d9d --- /dev/null +++ b/src/main/java/net/doubledoordev/backend/util/IUpdateFromJson.java @@ -0,0 +1,29 @@ +/* + * D3Backend + * Copyright (C) 2015 - 2017 Dries007 & Double Door Development + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package net.doubledoordev.backend.util; + +import com.google.gson.JsonObject; + +/** + * @author Dries007 + */ +public interface IUpdateFromJson +{ + void updateFrom(JsonObject json); +} diff --git a/src/main/java/net/doubledoordev/backend/util/PortRange.java b/src/main/java/net/doubledoordev/backend/util/PortRange.java index 49d5605..130c821 100644 --- a/src/main/java/net/doubledoordev/backend/util/PortRange.java +++ b/src/main/java/net/doubledoordev/backend/util/PortRange.java @@ -40,7 +40,7 @@ public int getNextAvailablePort(int ignored) throws OutOfPortsException { usedPorts.add(server.getServerPort()); } - for (int port = min; port < max; port++) + for (int port = min; port <= max; port++) { if (!usedPorts.contains(port) && port != ignored) return port; } @@ -51,4 +51,9 @@ public int getNextAvailablePort() throws OutOfPortsException { return getNextAvailablePort(-1); } + + public boolean isInRange(int serverPort) + { + return serverPort >= min && serverPort <= max; + } } diff --git a/src/main/java/net/doubledoordev/backend/util/Settings.java b/src/main/java/net/doubledoordev/backend/util/Settings.java index 65ed6cd..9a1d51b 100644 --- a/src/main/java/net/doubledoordev/backend/util/Settings.java +++ b/src/main/java/net/doubledoordev/backend/util/Settings.java @@ -66,8 +66,6 @@ public class Settings @Expose public int portHTTPS = 443; @Expose - public boolean useJava8 = false; - @Expose public boolean fixedPorts = false; @Expose public boolean fixedIP = false; @@ -168,11 +166,6 @@ public String getHostname() return hostname; } - public boolean isUseJava8() - { - return useJava8; - } - public boolean isFixedPorts() { return fixedPorts; diff --git a/src/main/java/net/doubledoordev/backend/util/exceptions/OutOfPortsException.java b/src/main/java/net/doubledoordev/backend/util/exceptions/OutOfPortsException.java index 22ffda4..9b1362b 100644 --- a/src/main/java/net/doubledoordev/backend/util/exceptions/OutOfPortsException.java +++ b/src/main/java/net/doubledoordev/backend/util/exceptions/OutOfPortsException.java @@ -18,10 +18,12 @@ package net.doubledoordev.backend.util.exceptions; +import java.io.IOException; + /** * @author Dries007 */ -public class OutOfPortsException extends Exception +public class OutOfPortsException extends IOException { public OutOfPortsException() { diff --git a/src/main/java/net/doubledoordev/backend/util/winreg/JavaFinder.java b/src/main/java/net/doubledoordev/backend/util/winreg/JavaFinder.java index ddcb406..9226e73 100644 --- a/src/main/java/net/doubledoordev/backend/util/winreg/JavaFinder.java +++ b/src/main/java/net/doubledoordev/backend/util/winreg/JavaFinder.java @@ -28,7 +28,6 @@ import net.doubledoordev.backend.Main; import net.doubledoordev.backend.util.OSUtils; -import net.doubledoordev.backend.util.Settings; import java.io.File; import java.util.ArrayList; @@ -221,7 +220,6 @@ public static JavaInfo parseJavaVersion() { for (JavaInfo aJava64 : java64) { - if (aJava64.isJava8() && Settings.SETTINGS.useJava8) continue; if (!preferred.is64bits || aJava64.compareTo(preferred) == 1) preferred = aJava64; } } @@ -229,7 +227,6 @@ public static JavaInfo parseJavaVersion() { for (JavaInfo aJava32 : java32) { - if (aJava32.isJava8() && Settings.SETTINGS.useJava8) continue; if (!preferred.is64bits && aJava32.compareTo(preferred) == 1) preferred = aJava32; } } @@ -242,7 +239,7 @@ public static JavaInfo parseJavaVersion() } else { - Main.LOGGER.debug("No Java versions found!"); + Main.LOGGER.fatal("No Java versions found!"); return null; } } diff --git a/src/main/java/net/doubledoordev/backend/util/winreg/JavaInfo.java b/src/main/java/net/doubledoordev/backend/util/winreg/JavaInfo.java index 79ec09c..4a3dfe3 100644 --- a/src/main/java/net/doubledoordev/backend/util/winreg/JavaInfo.java +++ b/src/main/java/net/doubledoordev/backend/util/winreg/JavaInfo.java @@ -41,7 +41,6 @@ public class JavaInfo implements Comparable public String version; //! Version string. public String origVersion = ""; public boolean supportedVersion = false; - public boolean hasJava8; public boolean is64bits; //! true for 64-bit javas, false for 32 public int major, minor, revision, build; diff --git a/src/main/java/net/doubledoordev/backend/web/http/FreemarkerHandler.java b/src/main/java/net/doubledoordev/backend/web/http/FreemarkerHandler.java index 9437b8f..bfe7ff9 100644 --- a/src/main/java/net/doubledoordev/backend/web/http/FreemarkerHandler.java +++ b/src/main/java/net/doubledoordev/backend/web/http/FreemarkerHandler.java @@ -94,7 +94,7 @@ protected boolean handle(String uri, Request request, Response response) throws // Put all session data in map, take 1 data.putAll(request.getSession().attributes()); - /** + /* * Data processing */ if (request.getMethod() == Method.GET) @@ -117,7 +117,7 @@ else if (request.getMethod() == Method.POST) if (uri == null) return true; - /** + /* * fix up the url to match template */ if (uri.endsWith(SLASH_STR)) uri += INDEX; diff --git a/src/main/java/net/doubledoordev/backend/web/http/PostHandler.java b/src/main/java/net/doubledoordev/backend/web/http/PostHandler.java index 51e77d0..9d30b15 100644 --- a/src/main/java/net/doubledoordev/backend/web/http/PostHandler.java +++ b/src/main/java/net/doubledoordev/backend/web/http/PostHandler.java @@ -64,7 +64,6 @@ public class PostHandler private static final String ARE_YOU_HUMAN = "areyouhuman"; private static final String RAM_MIN = "RAMmin"; private static final String RAM_MAX = "RAMmax"; - private static final String PERMGEN = "PermGen"; private static final String EXTRA_JAVA_PARM = "extraJavaParameters"; private static final String EXTRA_MC_PARM = "extraMCParameters"; private static final String ADMINS = "admins"; @@ -188,7 +187,12 @@ private String doNewserver(HashMap data, String uri, Request req if (user.getMaxServers() != -1 && user.getServerCount() >= user.getMaxServers()) throw new PostException("Max server count reached."); String owner = user.getGroup() == Group.ADMIN && names.contains(OWNER) ? parameters.getParameter(OWNER) : user.getUsername(); - String ID = owner + "_" + parameters.getParameter(NAME); + + String ID = parameters.getParameter(NAME); + if (ID.length() > 16) throw new PostException("Name can only be 16 characters long."); + if (!SERVERNAME_PATTERN.matcher(ID).matches()) throw new PostException("Name contains illegal characters."); + + ID = owner + "_" + ID; if (Settings.getServerByName(ID) != null) throw new PostException("Duplicate server ID"); Server server = new Server(ID, owner); @@ -206,10 +210,6 @@ private String doNewserver(HashMap data, String uri, Request req server.getJvmData().ramMin = ramMin; server.getJvmData().ramMax = ramMax; - int permGen = Integer.parseInt(parameters.getParameter(PERMGEN)); - if (permGen < 2) throw new PostException("PermGen settings invalid."); - server.getJvmData().permGen = permGen; - if (parameters.getParameter(EXTRA_JAVA_PARM).trim().length() != 0) server.getJvmData().extraJavaParameters = parameters.getParameter(EXTRA_JAVA_PARM).trim(); if (parameters.getParameter(EXTRA_MC_PARM).trim().length() != 0) server.getJvmData().extraMCParameters = parameters.getParameter(EXTRA_MC_PARM).trim(); if (parameters.getParameter(ADMINS).trim().length() != 0) for (String name : Arrays.asList(parameters.getParameter(ADMINS).trim().split("\n"))) server.addAdmin(caller, name); @@ -257,6 +257,7 @@ private String doRegister(String uri, Request request, Response response) if (!admin && !parameters.getParameter(ARE_YOU_HUMAN).trim().equals("4")) throw new PostException("You failed the human test..."); User user = Settings.getUserByName(username); if (user != null) throw new PostException("Username taken."); + if (username.length() > 15) throw new PostException("Username too long"); if (!USERNAME_PATTERN.matcher(username).matches()) throw new PostException("Username contains invalid chars.
Only a-Z, 0-9, _ and - please."); try { diff --git a/src/main/java/net/doubledoordev/backend/web/socket/AdvancedSettingsSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/AdvancedSettingsSocketApplication.java index a5e376c..99bcf60 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/AdvancedSettingsSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/AdvancedSettingsSocketApplication.java @@ -18,25 +18,23 @@ package net.doubledoordev.backend.web.socket; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import net.doubledoordev.backend.Main; import net.doubledoordev.backend.permissions.User; import net.doubledoordev.backend.server.JvmData; import net.doubledoordev.backend.server.RestartingInfo; import net.doubledoordev.backend.server.Server; +import net.doubledoordev.backend.util.IUpdateFromJson; import net.doubledoordev.backend.util.Settings; -import net.doubledoordev.backend.util.TypeHellhole; import net.doubledoordev.backend.util.WebSocketHelper; import net.doubledoordev.backend.util.exceptions.AuthenticationException; import org.glassfish.grizzly.websockets.DefaultWebSocket; import org.glassfish.grizzly.websockets.WebSocket; import org.glassfish.grizzly.websockets.WebSocketEngine; -import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.TimerTask; +import java.util.function.Function; import static net.doubledoordev.backend.util.Constants.*; @@ -45,19 +43,22 @@ */ public class AdvancedSettingsSocketApplication extends ServerWebSocketApplication { - public static final HashMap DATA_TYPES = new HashMap<>(); + private static final Map DATA_TYPES = new HashMap<>(); static { - try - { - DATA_TYPES.put(RESTARTING_INFO, new Data(RestartingInfo.class, RESTARTING_INFO)); - DATA_TYPES.put(JVM_DATA, new Data(JvmData.class, JVM_DATA)); - } - catch (NoSuchMethodException e) - { - throw new RuntimeException(e); - } + DATA_TYPES.put(RESTARTING_INFO, new Data<>(AdvancedSettingsSocketApplication::getRestartingInfo)); + DATA_TYPES.put(JVM_DATA, new Data<>(AdvancedSettingsSocketApplication::getJvmData)); + } + + private static JvmData getJvmData(Server server) + { + return server.getJvmData(); + } + + private static RestartingInfo getRestartingInfo(Server server) + { + return server.getRestartingInfo(); } private static final AdvancedSettingsSocketApplication APPLICATION = new AdvancedSettingsSocketApplication(); @@ -65,7 +66,7 @@ public class AdvancedSettingsSocketApplication extends ServerWebSocketApplicatio private AdvancedSettingsSocketApplication() { - TIMER.scheduleAtFixedRate(new TimerTask() + TIMER_NETWORK.scheduleAtFixedRate(new TimerTask() { @Override public void run() @@ -107,24 +108,12 @@ public void onConnect(WebSocket socket) @Override public void onMessage(WebSocket socket, String text) { - Main.LOGGER.info(text); - Server server = (Server) ((DefaultWebSocket) socket).getUpgradeRequest().getAttribute(SERVER); JsonObject object = JSONPARSER.parse(text).getAsJsonObject(); - for (String key : DATA_TYPES.keySet()) - { - if (object.has(key)) - { - try - { - DATA_TYPES.get(key).setValues(server, object.getAsJsonObject(key)); - } - catch (Exception e) - { - WebSocketHelper.sendError(socket, e); - } - } - } + DATA_TYPES.forEach((key, data) -> { + if (!object.has(key)) return; + data.set(server, object.getAsJsonObject(key)); + }); doSendUpdateToAll(server); Settings.save(); } @@ -147,45 +136,30 @@ private void doSendUpdateToAll(Server server) } } - public JsonObject getData(Server server) throws Exception + private JsonObject getData(Server server) throws Exception { JsonObject object = new JsonObject(); - - for (String key : DATA_TYPES.keySet()) - { - object.add(key, GSON.toJsonTree(DATA_TYPES.get(key).getter.invoke(server))); - } - + DATA_TYPES.forEach((s, data) -> object.add(s, GSON.toJsonTree(data.get(server)))); return object; } - public static class Data + private static class Data { - public final Class clazz; - public final Method getter; + private final Function getter; - public Data(Class clazz, String getterName) throws NoSuchMethodException + private Data(Function getter) { - this.clazz = clazz; - Method m; - try - { - m = Server.class.getDeclaredMethod(getterName); - } - catch (NoSuchMethodException ignored) - { - m = Server.class.getDeclaredMethod("get" + getterName); - } - this.getter = m; + this.getter = getter; } - public void setValues(Server server, JsonObject data) throws Exception + private T get(Server s) { - Object object = getter.invoke(server); - for (Map.Entry entry : data.entrySet()) - { - TypeHellhole.set(clazz.getDeclaredField(entry.getKey()), object, entry.getValue()); - } + return getter.apply(s); + } + + public void set(Server s, JsonObject jsonObject) + { + get(s).updateFrom(jsonObject); } } } diff --git a/src/main/java/net/doubledoordev/backend/web/socket/ConsoleSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/ConsoleSocketApplication.java index 13547ff..4df23c3 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/ConsoleSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/ConsoleSocketApplication.java @@ -41,14 +41,14 @@ public class ConsoleSocketApplication extends WebSocketApplication private ConsoleSocketApplication() { - TIMER.scheduleAtFixedRate(new TimerTask() + ServerWebSocketApplication.TIMER_NETWORK.scheduleAtFixedRate(new TimerTask() { @Override public void run() { for (WebSocket socket : getWebSockets()) socket.sendPing("ping".getBytes()); } - }, SOCKET_PING_TIME, SOCKET_PING_TIME); + }, ServerWebSocketApplication.SOCKET_PING_TIME, ServerWebSocketApplication.SOCKET_PING_TIME); } public static void register() diff --git a/src/main/java/net/doubledoordev/backend/web/socket/FileManagerSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/FileManagerSocketApplication.java index ae8ee9d..fc23604 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/FileManagerSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/FileManagerSocketApplication.java @@ -18,19 +18,15 @@ package net.doubledoordev.backend.web.socket; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import net.doubledoordev.backend.permissions.User; import net.doubledoordev.backend.server.FileManager; import net.doubledoordev.backend.server.Server; import net.doubledoordev.backend.util.Helper; import net.doubledoordev.backend.util.WebSocketHelper; -import net.doubledoordev.backend.util.methodCaller.IMethodCaller; import org.glassfish.grizzly.websockets.DefaultWebSocket; import org.glassfish.grizzly.websockets.WebSocket; import org.glassfish.grizzly.websockets.WebSocketEngine; -import java.util.ArrayList; import java.util.TimerTask; import static net.doubledoordev.backend.util.Constants.*; @@ -45,7 +41,7 @@ public class FileManagerSocketApplication extends ServerWebSocketApplication private FileManagerSocketApplication() { - TIMER.scheduleAtFixedRate(new TimerTask() + TIMER_NETWORK.scheduleAtFixedRate(new TimerTask() { @Override public void run() @@ -81,21 +77,6 @@ public void onConnect(WebSocket socket) ((DefaultWebSocket) socket).getUpgradeRequest().setAttribute(FILE_MANAGER, fileManager); } -// @Override -// public void onMessage(WebSocket socket, byte[] bytes) -// { -// FileManager fileManager = (FileManager) ((DefaultWebSocket) socket).getUpgradeRequest().getAttribute(FILE_MANAGER); -// if (!fileManager.getServer().isCoOwner((User) ((DefaultWebSocket) socket).getUpgradeRequest().getAttribute(USER))) -// { -// WebSocketHelper.sendError(socket, "You have no rights to this server."); -// socket.close(); -// return; -// } -// -// Main.LOGGER.info("Binary data: "); -// Main.LOGGER.info(new String(bytes)); -// } - @Override public void onMessage(WebSocket socket, String text) { @@ -106,23 +87,6 @@ public void onMessage(WebSocket socket, String text) socket.close(); return; } - try - { - JsonObject object = JSONPARSER.parse(text).getAsJsonObject(); - String name = object.get("method").getAsString(); - ArrayList args = new ArrayList<>(); - if (object.has("args")) for (JsonElement arg : object.getAsJsonArray("args")) args.add(arg.getAsString()); - IMethodCaller methodCaller = Helper.invokeWithRefectionMagic(socket, fileManager, name, args); - if (methodCaller == null) - { - WebSocketHelper.sendOk(socket); - socket.close(); - } - } - catch (Exception e) - { - e.printStackTrace(); - WebSocketHelper.sendError(socket, e); - } + Helper.doWebMethodCall(socket, text, fileManager); } } diff --git a/src/main/java/net/doubledoordev/backend/web/socket/FileMonitorSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/FileMonitorSocketApplication.java index 60d561a..e7aac35 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/FileMonitorSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/FileMonitorSocketApplication.java @@ -19,20 +19,16 @@ package net.doubledoordev.backend.web.socket; import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import net.doubledoordev.backend.permissions.User; import net.doubledoordev.backend.server.FileManager; import net.doubledoordev.backend.server.Server; import net.doubledoordev.backend.util.Helper; import net.doubledoordev.backend.util.WebSocketHelper; -import net.doubledoordev.backend.util.methodCaller.IMethodCaller; import org.glassfish.grizzly.websockets.DefaultWebSocket; import org.glassfish.grizzly.websockets.WebSocket; import org.glassfish.grizzly.websockets.WebSocketEngine; import java.io.File; -import java.util.ArrayList; import java.util.TimerTask; import static net.doubledoordev.backend.util.Constants.*; @@ -47,7 +43,7 @@ public class FileMonitorSocketApplication extends ServerWebSocketApplication private FileMonitorSocketApplication() { - TIMER.scheduleAtFixedRate(new TimerTask() + TIMER_NETWORK.scheduleAtFixedRate(new TimerTask() { @Override public void run() @@ -94,23 +90,6 @@ public void onMessage(WebSocket socket, String text) socket.close(); return; } - try - { - JsonObject object = JSONPARSER.parse(text).getAsJsonObject(); - String name = object.get("method").getAsString(); - ArrayList args = new ArrayList<>(); - if (object.has("args")) for (JsonElement arg : object.getAsJsonArray("args")) args.add(arg.getAsString()); - IMethodCaller methodCaller = Helper.invokeWithRefectionMagic(socket, fileManager, name, args); - if (methodCaller == null) - { - WebSocketHelper.sendOk(socket); - socket.close(); - } - } - catch (Exception e) - { - e.printStackTrace(); - WebSocketHelper.sendError(socket, e); - } + Helper.doWebMethodCall(socket, text, fileManager); } } diff --git a/src/main/java/net/doubledoordev/backend/web/socket/ServerControlSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/ServerControlSocketApplication.java index 24eceb0..6899e2f 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/ServerControlSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/ServerControlSocketApplication.java @@ -18,20 +18,14 @@ package net.doubledoordev.backend.web.socket; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import net.doubledoordev.backend.permissions.User; import net.doubledoordev.backend.server.Server; import net.doubledoordev.backend.util.Helper; import net.doubledoordev.backend.util.WebSocketHelper; -import net.doubledoordev.backend.util.methodCaller.IMethodCaller; import org.glassfish.grizzly.websockets.DefaultWebSocket; import org.glassfish.grizzly.websockets.WebSocket; import org.glassfish.grizzly.websockets.WebSocketEngine; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; - import static net.doubledoordev.backend.util.Constants.*; /** @@ -64,23 +58,6 @@ public void onMessage(WebSocket socket, String text) socket.close(); return; } - try - { - JsonObject object = JSONPARSER.parse(text).getAsJsonObject(); - String name = object.get("method").getAsString(); - ArrayList args = new ArrayList<>(); - if (object.has("args")) for (JsonElement arg : object.getAsJsonArray("args")) args.add(arg.getAsString()); - IMethodCaller methodCaller = Helper.invokeWithRefectionMagic(socket, server, name, args); - if (methodCaller == null) - { - WebSocketHelper.sendOk(socket); - socket.close(); - } - } - catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) - { - WebSocketHelper.sendError(socket, e); - socket.close(); - } + Helper.doWebMethodCall(socket, text, server); } } diff --git a/src/main/java/net/doubledoordev/backend/web/socket/ServerMonitorSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/ServerMonitorSocketApplication.java index 903efde..41ee479 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/ServerMonitorSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/ServerMonitorSocketApplication.java @@ -53,14 +53,14 @@ public class ServerMonitorSocketApplication extends WebSocketApplication private ServerMonitorSocketApplication(boolean allServers) { this.allServers = allServers; - TIMER.scheduleAtFixedRate(new TimerTask() + ServerWebSocketApplication.TIMER_NETWORK.scheduleAtFixedRate(new TimerTask() { @Override public void run() { for (WebSocket socket : getWebSockets()) socket.sendPing("ping".getBytes()); } - }, SOCKET_PING_TIME, SOCKET_PING_TIME); + }, ServerWebSocketApplication.SOCKET_PING_TIME, ServerWebSocketApplication.SOCKET_PING_TIME); } public static void sendUpdateToAll(Server server) @@ -159,7 +159,7 @@ public JsonObject getData(Server server) root.add("diskspace", object); root.add("coOwners", GSON.toJsonTree(server.getCoOwners())); root.add("admins", GSON.toJsonTree(server.getAdmins())); - root.addProperty("ram", Helper.DECIMAL_FORMAT.format(server.getJvmData().ramMin / 1024.0) + " GB to " + Helper.DECIMAL_FORMAT.format(server.getJvmData().ramMax / 1024.0) + " GB"); + root.addProperty("ram", server.getJvmData().ramMin + " MB to " + server.getJvmData().ramMax + " MB"); return root; } diff --git a/src/main/java/net/doubledoordev/backend/web/socket/ServerPropertiesSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/ServerPropertiesSocketApplication.java index 364a1d7..f38bed8 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/ServerPropertiesSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/ServerPropertiesSocketApplication.java @@ -41,7 +41,7 @@ public class ServerPropertiesSocketApplication extends ServerWebSocketApplicatio private ServerPropertiesSocketApplication() { - TIMER.scheduleAtFixedRate(new TimerTask() + TIMER_NETWORK.scheduleAtFixedRate(new TimerTask() { @Override public void run() diff --git a/src/main/java/net/doubledoordev/backend/web/socket/ServerWebSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/ServerWebSocketApplication.java index ee247bd..70a7775 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/ServerWebSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/ServerWebSocketApplication.java @@ -29,6 +29,8 @@ import org.glassfish.grizzly.websockets.WebSocket; import org.glassfish.grizzly.websockets.WebSocketApplication; +import java.util.Timer; + import static net.doubledoordev.backend.util.Constants.SERVER; import static net.doubledoordev.backend.util.Constants.USER; @@ -39,6 +41,9 @@ */ public abstract class ServerWebSocketApplication extends WebSocketApplication { + protected static final Timer TIMER_NETWORK = new Timer(); + protected static final long SOCKET_PING_TIME = 1000 * 50; // 50 seconds + @Override public void onConnect(WebSocket socket) { diff --git a/src/main/java/net/doubledoordev/backend/web/socket/ServerconsoleSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/ServerconsoleSocketApplication.java index 5f03317..ea23477 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/ServerconsoleSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/ServerconsoleSocketApplication.java @@ -38,7 +38,7 @@ public class ServerconsoleSocketApplication extends ServerWebSocketApplication private ServerconsoleSocketApplication() { - TIMER.scheduleAtFixedRate(new TimerTask() + TIMER_NETWORK.scheduleAtFixedRate(new TimerTask() { @Override public void run() diff --git a/src/main/java/net/doubledoordev/backend/web/socket/UsersSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/UsersSocketApplication.java index a180ae3..e69c7b4 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/UsersSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/UsersSocketApplication.java @@ -19,13 +19,10 @@ package net.doubledoordev.backend.web.socket; import com.google.common.base.Strings; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import net.doubledoordev.backend.permissions.User; import net.doubledoordev.backend.util.Helper; import net.doubledoordev.backend.util.Settings; import net.doubledoordev.backend.util.WebSocketHelper; -import net.doubledoordev.backend.util.methodCaller.IMethodCaller; import org.glassfish.grizzly.http.server.DefaultSessionManager; import org.glassfish.grizzly.http.server.Session; import org.glassfish.grizzly.websockets.DefaultWebSocket; @@ -33,8 +30,6 @@ import org.glassfish.grizzly.websockets.WebSocketApplication; import org.glassfish.grizzly.websockets.WebSocketEngine; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; import java.util.TimerTask; import static net.doubledoordev.backend.util.Constants.*; @@ -49,14 +44,14 @@ public class UsersSocketApplication extends WebSocketApplication private UsersSocketApplication() { - TIMER.scheduleAtFixedRate(new TimerTask() + ServerWebSocketApplication.TIMER_NETWORK.scheduleAtFixedRate(new TimerTask() { @Override public void run() { for (WebSocket socket : getWebSockets()) socket.sendPing("ping".getBytes()); } - }, SOCKET_PING_TIME, SOCKET_PING_TIME); + }, ServerWebSocketApplication.SOCKET_PING_TIME, ServerWebSocketApplication.SOCKET_PING_TIME); } public static void register() @@ -68,24 +63,7 @@ public static void register() public void onMessage(WebSocket socket, String text) { User user = (User) ((DefaultWebSocket) socket).getUpgradeRequest().getAttribute(USER); - try - { - JsonObject object = JSONPARSER.parse(text).getAsJsonObject(); - String name = object.get("method").getAsString(); - ArrayList args = new ArrayList<>(); - if (object.has("args")) for (JsonElement arg : object.getAsJsonArray("args")) args.add(arg.getAsString()); - IMethodCaller methodCaller = Helper.invokeWithRefectionMagic(socket, user, name, args); - if (methodCaller == null) - { - WebSocketHelper.sendOk(socket); - socket.close(); - } - } - catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) - { - WebSocketHelper.sendError(socket, e); - socket.close(); - } + Helper.doWebMethodCall(socket, text, user); } @Override diff --git a/src/main/java/net/doubledoordev/backend/web/socket/WorldManagerSocketApplication.java b/src/main/java/net/doubledoordev/backend/web/socket/WorldManagerSocketApplication.java index d98ca51..759a767 100644 --- a/src/main/java/net/doubledoordev/backend/web/socket/WorldManagerSocketApplication.java +++ b/src/main/java/net/doubledoordev/backend/web/socket/WorldManagerSocketApplication.java @@ -18,19 +18,15 @@ package net.doubledoordev.backend.web.socket; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; import net.doubledoordev.backend.permissions.User; import net.doubledoordev.backend.server.Server; import net.doubledoordev.backend.server.WorldManager; import net.doubledoordev.backend.util.Helper; import net.doubledoordev.backend.util.WebSocketHelper; -import net.doubledoordev.backend.util.methodCaller.IMethodCaller; import org.glassfish.grizzly.websockets.DefaultWebSocket; import org.glassfish.grizzly.websockets.WebSocket; import org.glassfish.grizzly.websockets.WebSocketEngine; -import java.util.ArrayList; import java.util.TimerTask; import static net.doubledoordev.backend.util.Constants.*; @@ -45,7 +41,7 @@ public class WorldManagerSocketApplication extends ServerWebSocketApplication private WorldManagerSocketApplication() { - TIMER.scheduleAtFixedRate(new TimerTask() + TIMER_NETWORK.scheduleAtFixedRate(new TimerTask() { @Override public void run() @@ -57,7 +53,7 @@ public void run() public static void register() { - WebSocketEngine.getEngine().register(SOCKET_CONTEXT, URL_PATTERN, APPLICATION); +// WebSocketEngine.getEngine().register(SOCKET_CONTEXT, URL_PATTERN, APPLICATION); } @Override @@ -78,23 +74,6 @@ public void onMessage(WebSocket socket, String text) socket.close(); return; } - try - { - JsonObject object = JSONPARSER.parse(text).getAsJsonObject(); - String name = object.get("method").getAsString(); - ArrayList args = new ArrayList<>(); - if (object.has("args")) for (JsonElement arg : object.getAsJsonArray("args")) args.add(arg.getAsString()); - IMethodCaller methodCaller = Helper.invokeWithRefectionMagic(socket, worldManager, name, args); - if (methodCaller == null) - { - WebSocketHelper.sendOk(socket); - socket.close(); - } - } - catch (Exception e) - { - e.printStackTrace(); - WebSocketHelper.sendError(socket, e); - } + Helper.doWebMethodCall(socket, text, worldManager); } } diff --git a/src/main/resources/licenseTemplate.html b/src/main/resources/licenseTemplate.html index 80d95f7..c777032 100644 --- a/src/main/resources/licenseTemplate.html +++ b/src/main/resources/licenseTemplate.html @@ -1,20 +1,20 @@ diff --git a/src/main/resources/templates/advancedsettings.ftl b/src/main/resources/templates/advancedsettings.ftl index fc35051..f3a9c8b 100644 --- a/src/main/resources/templates/advancedsettings.ftl +++ b/src/main/resources/templates/advancedsettings.ftl @@ -10,7 +10,8 @@

Restart info

-

Last autorestart: ${restartInfo.getLastRestart("YYYY-MM-dd hh:mm:ss")}

+

Last Auto Restart: ${restartInfo.getLastRestart("YYYY-MM-dd hh:mm:ss")}

+

Next Auto Restart: ${restartInfo.getNextRestart("YYYY-MM-dd hh:mm:ss")}

Start the server when the backend starts.
-
-
- - -
- - -
MB
-
-
diff --git a/src/main/resources/templates/header.ftl b/src/main/resources/templates/header.ftl index cf876a2..0001299 100644 --- a/src/main/resources/templates/header.ftl +++ b/src/main/resources/templates/header.ftl @@ -1,21 +1,21 @@ <#setting url_escaping_charset="UTF-8"> diff --git a/src/main/resources/templates/index.ftl b/src/main/resources/templates/index.ftl index b0e37e3..8408923 100644 --- a/src/main/resources/templates/index.ftl +++ b/src/main/resources/templates/index.ftl @@ -1,6 +1,14 @@ <#include "header.ftl"> <#if !Helper.usingHttps()> - + + +

Home

Some statistics

@@ -12,11 +20,4 @@ Players online on all servers: ${Helper.getGlobalPlayers()}
Backend has been online for: ${Helper.getOnlineTime("%2d days, ", "%2d hours, ", "%2d min and ", "%2d sec")}

- <#include "footer.ftl"> diff --git a/src/main/resources/templates/login.ftl b/src/main/resources/templates/login.ftl index 227b57f..1c527a6 100644 --- a/src/main/resources/templates/login.ftl +++ b/src/main/resources/templates/login.ftl @@ -1,5 +1,15 @@ <#include "header.ftl"> +<#if !Helper.usingHttps()> + + + <#if !user??>
-
- - -
- -
-
@@ -121,13 +114,20 @@ function checkName() { var name = document.getElementById("name").value; - while (!name.match(/^[\w]+$/)) + while (!name.match(/^\w+$/) || name.length > 16) { - name = prompt('Your server ID contains non allowed characters.\nPlease remove all spaces and special characters.', name); + if (name.length > 16) + { + name = prompt('Your server ID is too long.\nIt can only be 16 characters long.', name); + } + else + { + name = prompt('Your server ID contains non allowed characters.\nPlease remove all spaces and special characters.', name); + } if (name == null) break; } - if (name == null || !name.match(/^[\w]+$/)) + if (name == null || !name.match(/^\w+$/) || name.length > 16) { document.getElementById("submit").disabled = true; document.getElementById("name-div").className = "form-group has-error"; diff --git a/src/main/resources/templates/register.ftl b/src/main/resources/templates/register.ftl index 28c4665..49597de 100644 --- a/src/main/resources/templates/register.ftl +++ b/src/main/resources/templates/register.ftl @@ -1,4 +1,14 @@ <#include "header.ftl"> +<#if !Helper.usingHttps()> + + + <#if !user??> @@ -6,14 +16,37 @@ - - - -
- +
+ + Alphanumerical, max 15 characters. +
+
+ +
+
+ +
+
+ +
+ <#else>

Account registered!

diff --git a/src/main/resources/templates/server.ftl b/src/main/resources/templates/server.ftl index 38ff844..1fd814c 100644 --- a/src/main/resources/templates/server.ftl +++ b/src/main/resources/templates/server.ftl @@ -55,7 +55,7 @@
Advanced Settings diff --git a/src/main/resources/templates/serverconsole.ftl b/src/main/resources/templates/serverconsole.ftl index bfecccf..1311e31 100644 --- a/src/main/resources/templates/serverconsole.ftl +++ b/src/main/resources/templates/serverconsole.ftl @@ -1,20 +1,20 @@ @@ -47,7 +47,6 @@ history: false, name: 'console_${server.ID?js_string}', greetings: 'Server console for ${server.ID?js_string}.' - }); websocket.onerror = function (evt) { diff --git a/src/main/resources/templates/worldmanager.ftl b/src/main/resources/templates/worldmanager.ftl index 84d5c56..82aa198 100644 --- a/src/main/resources/templates/worldmanager.ftl +++ b/src/main/resources/templates/worldmanager.ftl @@ -6,11 +6,12 @@

World Manager ${server.ID?js_string}

- + Broken.
+

+ +<#--

World information

@@ -57,7 +58,6 @@
-