From 867ae334fa34017719408b9ced43a2dba6ccebd1 Mon Sep 17 00:00:00 2001 From: Gravit Date: Sun, 25 Aug 2019 16:39:08 +0700 Subject: [PATCH] =?UTF-8?q?[FEATURE]=20=D0=91=D0=BE=D0=BB=D1=8C=D1=88?= =?UTF-8?q?=D0=B0=D1=8F=20=D1=84=D0=B8=D1=82=D1=87=D0=B0=20-=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D1=85=D0=BE=D0=B4=20=D0=BD=D0=B0=20LaunchSer?= =?UTF-8?q?verBuilder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LaunchServer/build.gradle | 2 +- .../pro/gravit/launchserver/LaunchServer.java | 284 ++++-------------- .../launchserver/LaunchServerBuilder.java | 104 +++++++ .../launchserver/LaunchServerStarter.java | 232 ++++++++++++++ .../command/modules/LoadModuleCommand.java | 2 +- .../command/service/ServerStatusCommand.java | 2 +- .../config/LaunchServerConfig.java | 2 +- .../manangers/ModulesManager.java | 11 +- .../java/pro/gravit/launcher/StartTest.java | 4 +- 9 files changed, 409 insertions(+), 234 deletions(-) create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerBuilder.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java diff --git a/LaunchServer/build.gradle b/LaunchServer/build.gradle index 295cc8f0..a4df21d6 100644 --- a/LaunchServer/build.gradle +++ b/LaunchServer/build.gradle @@ -1,4 +1,4 @@ -def mainClassName = "pro.gravit.launchserver.LaunchServer" +def mainClassName = "pro.gravit.launchserver.LaunchServerStarter" def mainAgentName = "pro.gravit.launchserver.StarterAgent" evaluationDependsOn(':Launcher') diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index e3891b96..3678f12e 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -1,10 +1,7 @@ package pro.gravit.launchserver; import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; import java.io.IOException; -import java.io.Writer; import java.lang.ProcessBuilder.Redirect; import java.lang.reflect.InvocationTargetException; import java.nio.file.DirectoryStream; @@ -33,62 +30,33 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.zip.CRC32; -import io.netty.channel.epoll.Epoll; import org.bouncycastle.crypto.util.PrivateKeyFactory; import org.bouncycastle.operator.OperatorCreationException; -import io.netty.handler.logging.LogLevel; import pro.gravit.launcher.Launcher; -import pro.gravit.launcher.LauncherConfig; import pro.gravit.launcher.NeedGarbageCollection; import pro.gravit.launcher.hasher.HashedDir; -import pro.gravit.launcher.hwid.HWIDProvider; import pro.gravit.launcher.managers.ConfigManager; import pro.gravit.launcher.managers.GarbageManager; import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launchserver.auth.AuthProviderPair; -import pro.gravit.launchserver.auth.handler.AuthHandler; -import pro.gravit.launchserver.auth.handler.MemoryAuthHandler; -import pro.gravit.launchserver.auth.hwid.AcceptHWIDHandler; -import pro.gravit.launchserver.auth.hwid.HWIDHandler; -import pro.gravit.launchserver.auth.permissions.DefaultPermissionsHandler; -import pro.gravit.launchserver.auth.permissions.JsonFilePermissionsHandler; -import pro.gravit.launchserver.auth.permissions.PermissionsHandler; -import pro.gravit.launchserver.auth.protect.ProtectHandler; -import pro.gravit.launchserver.auth.protect.StdProtectHandler; -import pro.gravit.launchserver.auth.provider.AuthProvider; -import pro.gravit.launchserver.auth.provider.RejectAuthProvider; -import pro.gravit.launchserver.auth.texture.RequestTextureProvider; -import pro.gravit.launchserver.auth.texture.TextureProvider; import pro.gravit.launchserver.binary.EXEL4JLauncherBinary; import pro.gravit.launchserver.binary.EXELauncherBinary; import pro.gravit.launchserver.binary.JARLauncherBinary; import pro.gravit.launchserver.binary.LauncherBinary; import pro.gravit.launchserver.binary.ProguardConf; import pro.gravit.launchserver.binary.SimpleEXELauncherBinary; -import pro.gravit.launchserver.components.AuthLimiterComponent; -import pro.gravit.launchserver.components.Component; -import pro.gravit.launchserver.components.RegLimiterComponent; import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerRuntimeConfig; -import pro.gravit.launchserver.dao.provider.DaoProvider; -import pro.gravit.launchserver.manangers.CertificateManager; -import pro.gravit.launchserver.manangers.LaunchServerGsonManager; -import pro.gravit.launchserver.manangers.MirrorManager; -import pro.gravit.launchserver.manangers.ModulesManager; -import pro.gravit.launchserver.manangers.ReconfigurableManager; -import pro.gravit.launchserver.manangers.SessionManager; +import pro.gravit.launchserver.manangers.*; import pro.gravit.launchserver.manangers.hook.AuthHookManager; import pro.gravit.launchserver.manangers.hook.BuildHookManager; -import pro.gravit.launchserver.socket.WebSocketService; import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler; -import pro.gravit.utils.Version; import pro.gravit.utils.command.*; import pro.gravit.utils.helper.CommonHelper; import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.JVMHelper; import pro.gravit.utils.helper.LogHelper; -import pro.gravit.utils.helper.SecurityHelper; public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurable { @@ -98,6 +66,20 @@ public enum ReloadType NO_COMPONENTS, FULL } + public enum LaunchServerEnv + { + TEST, + DEV, + DEBUG, + PRODUCTION + } + public interface LaunchServerConfigManager + { + LaunchServerConfig readConfig() throws IOException; + LaunchServerRuntimeConfig readRuntimeConfig() throws IOException; + void writeConfig(LaunchServerConfig config) throws IOException; + void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException; + } public void reload(ReloadType type) throws Exception { config.close(type); @@ -107,9 +89,7 @@ public void reload(ReloadType type) throws Exception { pairs = config.auth; } LogHelper.info("Reading LaunchServer config file"); - try (BufferedReader reader = IOHelper.newReader(configFile)) { - config = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class); - } + config = launchServerConfigManager.readConfig(); config.setLaunchServer(this); if(type.equals(ReloadType.NO_AUTH)) { @@ -198,53 +178,16 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO } } - public static void main(String... args) throws Throwable { - JVMHelper.checkStackTrace(LaunchServer.class); - JVMHelper.verifySystemProperties(LaunchServer.class, true); - LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log")); - LogHelper.printVersion("LaunchServer"); - LogHelper.printLicense("LaunchServer"); - if (!StarterAgent.isAgentStarted()) { - LogHelper.error("StarterAgent is not started!"); - LogHelper.error("You should add to JVM options this option: `-javaagent:LaunchServer.jar`"); - } - - // Start LaunchServer - long startTime = System.currentTimeMillis(); - try { - @SuppressWarnings("resource") - LaunchServer launchserver = new LaunchServer(IOHelper.WORKING_DIR, false, args); - if (args.length == 0) launchserver.run(); - else { //Обработка команды - launchserver.commandHandler.eval(args, false); - } - } catch (Throwable exc) { - LogHelper.error(exc); - return; - } - long endTime = System.currentTimeMillis(); - LogHelper.debug("LaunchServer started in %dms", endTime - startTime); - } - // Constant paths public final Path dir; - public final boolean testEnv; + public final LaunchServerEnv env; public final Path launcherLibraries; public final Path launcherLibrariesCompile; - public final List args; - - public final Path configFile; - public final Path runtimeConfigFile; - - public final Path publicKeyFile; - - public final Path privateKeyFile; - public final Path caCertFile; public final Path caKeyFile; @@ -255,6 +198,8 @@ public static void main(String... args) throws Throwable { public final Path updatesDir; + public final LaunchServerConfigManager launchServerConfigManager; + //public static LaunchServer server = null; public final Path profilesDir; @@ -311,33 +256,35 @@ public static void main(String... args) throws Throwable { public static Class defaultLauncherEXEBinaryClass = null; - public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException, InvalidKeySpecException { - this.dir = dir; - this.testEnv = testEnv; + public static class LaunchServerDirectories + { + public Path updatesDir; + public Path profilesDir; + public Path dir; + public void collect() + { + if(updatesDir == null) updatesDir = dir.resolve("updates"); + if(profilesDir == null) profilesDir = dir.resolve("profiles"); + } + } + + public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, ModulesManager modulesManager, RSAPublicKey publicKey, RSAPrivateKey privateKey, CommandHandler commandHandler) throws IOException, InvalidKeySpecException { + this.dir = directories.dir; + this.env = env; + this.config = config; + this.launchServerConfigManager = launchServerConfigManager; + this.modulesManager = modulesManager; + this.profilesDir = directories.profilesDir; + this.updatesDir = directories.updatesDir; + this.publicKey = publicKey; + this.privateKey = privateKey; + this.commandHandler = commandHandler; + this.runtime = runtimeConfig; taskPool = new Timer("Timered task worker thread", true); launcherLibraries = dir.resolve("launcher-libraries"); launcherLibrariesCompile = dir.resolve("launcher-libraries-compile"); - this.args = Arrays.asList(args); - if(IOHelper.exists(dir.resolve("LaunchServer.conf"))) - { - configFile = dir.resolve("LaunchServer.conf"); - } - else - { - configFile = dir.resolve("LaunchServer.json"); - } - if(IOHelper.exists(dir.resolve("RuntimeLaunchServer.conf"))) - { - runtimeConfigFile = dir.resolve("RuntimeLaunchServer.conf"); - } - else - { - runtimeConfigFile = dir.resolve("RuntimeLaunchServer.json"); - } - publicKeyFile = dir.resolve("public.key"); - privateKeyFile = dir.resolve("private.key"); - updatesDir = dir.resolve("updates"); - profilesDir = dir.resolve("profiles"); + + config.setLaunchServer(this); caCertFile = dir.resolve("ca.crt"); caKeyFile = dir.resolve("ca.key"); @@ -345,54 +292,7 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException serverCertFile = dir.resolve("server.crt"); serverKeyFile = dir.resolve("server.key"); - //Registration handlers and providers - AuthHandler.registerHandlers(); - AuthProvider.registerProviders(); - TextureProvider.registerProviders(); - HWIDHandler.registerHandlers(); - PermissionsHandler.registerHandlers(); - Component.registerComponents(); - ProtectHandler.registerHandlers(); - WebSocketService.registerResponses(); - HWIDProvider.registerHWIDs(); - DaoProvider.registerProviders(); - //LaunchServer.server = this; - - // Set command handler - CommandHandler localCommandHandler; - if (testEnv) - localCommandHandler = new StdCommandHandler(false); - else - try { - Class.forName("org.jline.terminal.Terminal"); - - // JLine2 available - localCommandHandler = new JLineCommandHandler(); - LogHelper.info("JLine2 terminal enabled"); - } catch (ClassNotFoundException ignored) { - localCommandHandler = new StdCommandHandler(true); - LogHelper.warning("JLine2 isn't in classpath, using std"); - } - commandHandler = localCommandHandler; - - // Set key pair - if (IOHelper.isFile(publicKeyFile) && IOHelper.isFile(privateKeyFile)) { - LogHelper.info("Reading RSA keypair"); - publicKey = SecurityHelper.toPublicRSAKey(IOHelper.read(publicKeyFile)); - privateKey = SecurityHelper.toPrivateRSAKey(IOHelper.read(privateKeyFile)); - if (!publicKey.getModulus().equals(privateKey.getModulus())) - throw new IOException("Private and public key modulus mismatch"); - } else { - LogHelper.info("Generating RSA keypair"); - KeyPair pair = SecurityHelper.genRSAKeyPair(); - publicKey = (RSAPublicKey) pair.getPublic(); - privateKey = (RSAPrivateKey) pair.getPrivate(); - - // Write key pair list - LogHelper.info("Writing RSA keypair list"); - IOHelper.write(publicKeyFile, publicKey.getEncoded()); - IOHelper.write(privateKeyFile, privateKey.getEncoded()); - } + modulesManager.initContext(this); // Print keypair fingerprints CRC32 crc = new CRC32(); @@ -403,28 +303,10 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException launcherEXEBinaryClass = defaultLauncherEXEBinaryClass; // pre init modules - modulesManager = new ModulesManager(this); - modulesManager.autoload(dir.resolve("modules")); + //modulesManager = new ModulesManager(this); + //modulesManager.autoload(dir.resolve("modules")); modulesManager.preInitModules(); - initGson(); - // Read LaunchServer config - generateConfigIfNotExists(testEnv); - LogHelper.info("Reading LaunchServer config file"); - try (BufferedReader reader = IOHelper.newReader(configFile)) { - config = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class); - } - config.setLaunchServer(this); - if (!Files.exists(runtimeConfigFile)) { - LogHelper.info("Reset LaunchServer runtime config file"); - runtime = new LaunchServerRuntimeConfig(); - runtime.reset(); - } else { - LogHelper.info("Reading LaunchServer runtime config file"); - try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) { - runtime = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class); - } - } runtime.verify(); config.verify(); if (config.components != null) { @@ -486,7 +368,7 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException registerObject("launchServer", this); GarbageManager.registerNeedGC(sessionManager); - pro.gravit.launchserver.command.handler.CommandHandler.registerCommands(localCommandHandler, this); + pro.gravit.launchserver.command.handler.CommandHandler.registerCommands(commandHandler, this); // init modules modulesManager.initModules(); @@ -534,11 +416,6 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException nettyServerSocketHandler = null; } - public static void initGson() { - Launcher.gsonManager = new LaunchServerGsonManager(); - Launcher.gsonManager.initGson(); - } - private LauncherBinary binary() { if (launcherEXEBinaryClass != null) { try { @@ -576,66 +453,17 @@ public void buildLauncherBinaries() throws IOException { launcherEXEBinary.build(); } - public void close() { + public void close() throws Exception { // Close handlers & providers config.close(ReloadType.FULL); modulesManager.close(); LogHelper.info("Save LaunchServer runtime config"); - try (Writer writer = IOHelper.newWriter(runtimeConfigFile)) { - if (Launcher.gsonManager.configGson != null) { - Launcher.gsonManager.configGson.toJson(runtime, writer); - } else { - LogHelper.error("Error writing LaunchServer runtime config file. Gson is null"); - } - } catch (IOException e) { - LogHelper.error(e); - } + launchServerConfigManager.writeRuntimeConfig(runtime); // Print last message before death :( LogHelper.info("LaunchServer stopped"); } - private void generateConfigIfNotExists(boolean testEnv) throws IOException { - if (IOHelper.isFile(configFile)) - return; - - // Create new config - LogHelper.info("Creating LaunchServer config"); - - - LaunchServerConfig newConfig = LaunchServerConfig.getDefault(); - // Set server address - String address; - if (testEnv) { - address = "localhost"; - newConfig.setProjectName("test"); - } else { - System.out.println("LaunchServer address(default: localhost): "); - address = commandHandler.readLine(); - System.out.println("LaunchServer projectName: "); - newConfig.setProjectName(commandHandler.readLine()); - } - if (address == null || address.isEmpty()) { - LogHelper.error("Address null. Using localhost"); - address = "localhost"; - } - if (newConfig.projectName == null || newConfig.projectName.isEmpty()) { - LogHelper.error("ProjectName null. Using MineCraft"); - newConfig.projectName = "MineCraft"; - } - - newConfig.netty.address = "ws://" + address + ":9274/api"; - newConfig.netty.downloadURL = "http://" + address + ":9274/%dirname%/"; - newConfig.netty.launcherURL = "http://" + address + ":9274/Launcher.jar"; - newConfig.netty.launcherEXEURL = "http://" + address + ":9274/Launcher.exe"; - - // Write LaunchServer config - LogHelper.info("Writing LaunchServer config file"); - try (BufferedWriter writer = IOHelper.newWriter(configFile)) { - Launcher.gsonManager.configGson.toJson(newConfig, writer); - } - } - public List getProfiles() { return profilesList; } @@ -664,8 +492,14 @@ public void run() { throw new IllegalStateException("LaunchServer has been already started"); // Add shutdown hook, then start LaunchServer - if (!this.testEnv) { - JVMHelper.RUNTIME.addShutdownHook(CommonHelper.newThread(null, false, this::close)); + if (!this.env.equals(LaunchServerEnv.TEST)) { + JVMHelper.RUNTIME.addShutdownHook(CommonHelper.newThread(null, false, () -> { + try { + close(); + } catch (Exception e) { + LogHelper.error(e); + } + })); CommonHelper.newThread("Command Thread", true, commandHandler).start(); } if (config.netty != null) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerBuilder.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerBuilder.java new file mode 100644 index 00000000..3b9f8c6c --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerBuilder.java @@ -0,0 +1,104 @@ +package pro.gravit.launchserver; + +import pro.gravit.launchserver.config.LaunchServerConfig; +import pro.gravit.launchserver.config.LaunchServerRuntimeConfig; +import pro.gravit.launchserver.manangers.ModulesManager; +import pro.gravit.utils.command.CommandHandler; + +import java.nio.file.Path; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +public class LaunchServerBuilder { + private LaunchServerConfig config; + private LaunchServerRuntimeConfig runtimeConfig; + private CommandHandler commandHandler; + private LaunchServer.LaunchServerEnv env; + private ModulesManager modulesManager; + private LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories(); + private RSAPublicKey publicKey; + private RSAPrivateKey privateKey; + private LaunchServer.LaunchServerConfigManager launchServerConfigManager; + + public LaunchServerBuilder setConfig(LaunchServerConfig config) { + this.config = config; + return this; + } + + public LaunchServerBuilder setEnv(LaunchServer.LaunchServerEnv env) { + this.env = env; + return this; + } + + public LaunchServerBuilder setModulesManager(ModulesManager modulesManager) { + this.modulesManager = modulesManager; + return this; + } + + public LaunchServerBuilder setRuntimeConfig(LaunchServerRuntimeConfig runtimeConfig) { + this.runtimeConfig = runtimeConfig; + return this; + } + + public LaunchServerBuilder setCommandHandler(CommandHandler commandHandler) { + this.commandHandler = commandHandler; + return this; + } + + public LaunchServerBuilder setDirectories(LaunchServer.LaunchServerDirectories directories) { + this.directories = directories; + return this; + } + + public LaunchServerBuilder setDir(Path dir) { + this.directories.dir = dir; + return this; + } + + public LaunchServerBuilder setPublicKey(RSAPublicKey publicKey) { + this.publicKey = publicKey; + return this; + } + + public LaunchServerBuilder setPrivateKey(RSAPrivateKey privateKey) { + this.privateKey = privateKey; + return this; + } + + public LaunchServerBuilder setLaunchServerConfigManager(LaunchServer.LaunchServerConfigManager launchServerConfigManager) { + this.launchServerConfigManager = launchServerConfigManager; + return this; + } + + public LaunchServer build() throws Exception + { + //if(updatesDir == null) updatesDir = dir.resolve("updates"); + //if(profilesDir == null) profilesDir = dir.resolve("profiles"); + directories.collect(); + if(launchServerConfigManager == null) + { + launchServerConfigManager = new LaunchServer.LaunchServerConfigManager() { + @Override + public LaunchServerConfig readConfig() { + throw new UnsupportedOperationException(); + } + + @Override + public LaunchServerRuntimeConfig readRuntimeConfig() { + throw new UnsupportedOperationException(); + } + + @Override + public void writeConfig(LaunchServerConfig config) { + throw new UnsupportedOperationException(); + } + + @Override + public void writeRuntimeConfig(LaunchServerRuntimeConfig config) { + throw new UnsupportedOperationException(); + } + }; + } + return new LaunchServer(directories, env, config, runtimeConfig, launchServerConfigManager, modulesManager, publicKey, privateKey, commandHandler); + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java new file mode 100644 index 00000000..bef6592a --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java @@ -0,0 +1,232 @@ +package pro.gravit.launchserver; + +import pro.gravit.launcher.Launcher; +import pro.gravit.launcher.hwid.HWIDProvider; +import pro.gravit.launchserver.auth.handler.AuthHandler; +import pro.gravit.launchserver.auth.hwid.HWIDHandler; +import pro.gravit.launchserver.auth.permissions.PermissionsHandler; +import pro.gravit.launchserver.auth.protect.ProtectHandler; +import pro.gravit.launchserver.auth.provider.AuthProvider; +import pro.gravit.launchserver.auth.texture.TextureProvider; +import pro.gravit.launchserver.components.Component; +import pro.gravit.launchserver.config.LaunchServerConfig; +import pro.gravit.launchserver.config.LaunchServerRuntimeConfig; +import pro.gravit.launchserver.dao.provider.DaoProvider; +import pro.gravit.launchserver.manangers.LaunchServerGsonManager; +import pro.gravit.launchserver.manangers.ModulesManager; +import pro.gravit.launchserver.socket.WebSocketService; +import pro.gravit.utils.command.CommandHandler; +import pro.gravit.utils.command.JLineCommandHandler; +import pro.gravit.utils.command.StdCommandHandler; +import pro.gravit.utils.helper.IOHelper; +import pro.gravit.utils.helper.JVMHelper; +import pro.gravit.utils.helper.LogHelper; +import pro.gravit.utils.helper.SecurityHelper; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.KeyPair; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +public class LaunchServerStarter { + public static void main(String[] args) throws Exception { + JVMHelper.checkStackTrace(LaunchServerStarter.class); + JVMHelper.verifySystemProperties(LaunchServer.class, true); + LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log")); + LogHelper.printVersion("LaunchServer"); + LogHelper.printLicense("LaunchServer"); + if (!StarterAgent.isAgentStarted()) { + LogHelper.error("StarterAgent is not started!"); + LogHelper.error("You should add to JVM options this option: `-javaagent:LaunchServer.jar`"); + } + + Path dir = IOHelper.WORKING_DIR; + Path configFile, runtimeConfigFile; + Path publicKeyFile =dir.resolve("public.key"); + Path privateKeyFile = dir.resolve("private.key"); + RSAPublicKey publicKey; + RSAPrivateKey privateKey; + + LaunchServerRuntimeConfig runtimeConfig; + LaunchServerConfig config; + LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION; + ModulesManager modulesManager = new ModulesManager(dir.resolve("config")); + modulesManager.autoload(dir.resolve("modules")); + registerAll(); + initGson(); + if (IOHelper.exists(dir.resolve("LaunchServer.conf"))) { + configFile = dir.resolve("LaunchServer.conf"); + } else { + configFile = dir.resolve("LaunchServer.json"); + } + if (IOHelper.exists(dir.resolve("RuntimeLaunchServer.conf"))) { + runtimeConfigFile = dir.resolve("RuntimeLaunchServer.conf"); + } else { + runtimeConfigFile = dir.resolve("RuntimeLaunchServer.json"); + } + CommandHandler localCommandHandler; + try { + Class.forName("org.jline.terminal.Terminal"); + + // JLine2 available + localCommandHandler = new JLineCommandHandler(); + LogHelper.info("JLine2 terminal enabled"); + } catch (ClassNotFoundException ignored) { + localCommandHandler = new StdCommandHandler(true); + LogHelper.warning("JLine2 isn't in classpath, using std"); + } + if (IOHelper.isFile(publicKeyFile) && IOHelper.isFile(privateKeyFile)) { + LogHelper.info("Reading RSA keypair"); + publicKey = SecurityHelper.toPublicRSAKey(IOHelper.read(publicKeyFile)); + privateKey = SecurityHelper.toPrivateRSAKey(IOHelper.read(privateKeyFile)); + if (!publicKey.getModulus().equals(privateKey.getModulus())) + throw new IOException("Private and public key modulus mismatch"); + } else { + LogHelper.info("Generating RSA keypair"); + KeyPair pair = SecurityHelper.genRSAKeyPair(); + publicKey = (RSAPublicKey) pair.getPublic(); + privateKey = (RSAPrivateKey) pair.getPrivate(); + + // Write key pair list + LogHelper.info("Writing RSA keypair list"); + IOHelper.write(publicKeyFile, publicKey.getEncoded()); + IOHelper.write(privateKeyFile, privateKey.getEncoded()); + } + if (!Files.exists(runtimeConfigFile)) { + LogHelper.info("Reset LaunchServer runtime config file"); + runtimeConfig = new LaunchServerRuntimeConfig(); + runtimeConfig.reset(); + } else { + LogHelper.info("Reading LaunchServer runtime config file"); + try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) { + runtimeConfig = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class); + } + } + generateConfigIfNotExists(configFile, localCommandHandler, env); + LogHelper.info("Reading LaunchServer config file"); + try (BufferedReader reader = IOHelper.newReader(configFile)) { + config = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class); + } + + LaunchServer.LaunchServerConfigManager launchServerConfigManager = new LaunchServer.LaunchServerConfigManager() { + @Override + public LaunchServerConfig readConfig() throws IOException { + LaunchServerConfig config1; + try (BufferedReader reader = IOHelper.newReader(configFile)) { + config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerConfig.class); + } + return config1; + } + + @Override + public LaunchServerRuntimeConfig readRuntimeConfig() throws IOException { + LaunchServerRuntimeConfig config1; + try (BufferedReader reader = IOHelper.newReader(runtimeConfigFile)) { + config1 = Launcher.gsonManager.gson.fromJson(reader, LaunchServerRuntimeConfig.class); + } + return config1; + } + + @Override + public void writeConfig(LaunchServerConfig config) throws IOException { + try (Writer writer = IOHelper.newWriter(configFile)) { + if (Launcher.gsonManager.configGson != null) { + Launcher.gsonManager.configGson.toJson(config, writer); + } else { + LogHelper.error("Error writing LaunchServer runtime config file. Gson is null"); + } + } + } + + @Override + public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException { + try (Writer writer = IOHelper.newWriter(runtimeConfigFile)) { + if (Launcher.gsonManager.configGson != null) { + Launcher.gsonManager.configGson.toJson(config, writer); + } else { + LogHelper.error("Error writing LaunchServer runtime config file. Gson is null"); + } + } + } + }; + + LaunchServer server = new LaunchServerBuilder() + .setDir(dir) + .setEnv(env) + .setCommandHandler(localCommandHandler) + .setPrivateKey(privateKey) + .setPublicKey(publicKey) + .setRuntimeConfig(runtimeConfig) + .setConfig(config) + .setModulesManager(modulesManager) + .setLaunchServerConfigManager(launchServerConfigManager) + .build(); + server.run(); + } + + public static void initGson() { + Launcher.gsonManager = new LaunchServerGsonManager(); + Launcher.gsonManager.initGson(); + } + + public static void registerAll() + { + + AuthHandler.registerHandlers(); + AuthProvider.registerProviders(); + TextureProvider.registerProviders(); + HWIDHandler.registerHandlers(); + PermissionsHandler.registerHandlers(); + Component.registerComponents(); + ProtectHandler.registerHandlers(); + WebSocketService.registerResponses(); + HWIDProvider.registerHWIDs(); + DaoProvider.registerProviders(); + } + + public static void generateConfigIfNotExists(Path configFile, CommandHandler commandHandler, LaunchServer.LaunchServerEnv env) throws IOException { + if (IOHelper.isFile(configFile)) + return; + + // Create new config + LogHelper.info("Creating LaunchServer config"); + + + LaunchServerConfig newConfig = LaunchServerConfig.getDefault(env); + // Set server address + String address; + if (env.equals(LaunchServer.LaunchServerEnv.TEST)) { + address = "localhost"; + newConfig.setProjectName("test"); + } else { + System.out.println("LaunchServer address(default: localhost): "); + address = commandHandler.readLine(); + System.out.println("LaunchServer projectName: "); + newConfig.setProjectName(commandHandler.readLine()); + } + if (address == null || address.isEmpty()) { + LogHelper.error("Address null. Using localhost"); + address = "localhost"; + } + if (newConfig.projectName == null || newConfig.projectName.isEmpty()) { + LogHelper.error("ProjectName null. Using MineCraft"); + newConfig.projectName = "MineCraft"; + } + + newConfig.netty.address = "ws://" + address + ":9274/api"; + newConfig.netty.downloadURL = "http://" + address + ":9274/%dirname%/"; + newConfig.netty.launcherURL = "http://" + address + ":9274/Launcher.jar"; + newConfig.netty.launcherEXEURL = "http://" + address + ":9274/Launcher.exe"; + + // Write LaunchServer config + LogHelper.info("Writing LaunchServer config file"); + try (BufferedWriter writer = IOHelper.newWriter(configFile)) { + Launcher.gsonManager.configGson.toJson(newConfig, writer); + } + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/modules/LoadModuleCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/modules/LoadModuleCommand.java index 88439e0c..f8adec3c 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/modules/LoadModuleCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/modules/LoadModuleCommand.java @@ -25,6 +25,6 @@ public String getUsageDescription() { public void invoke(String... args) throws Exception { verifyArgs(args, 1); URI uri = Paths.get(args[0]).toUri(); - server.modulesManager.loadModuleFull(uri.toURL()); + server.modulesManager.loadModule(uri.toURL()); } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/ServerStatusCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/ServerStatusCommand.java index 9520dd45..d5a270e5 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/ServerStatusCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/ServerStatusCommand.java @@ -38,7 +38,7 @@ public void invoke(String... args) { for (CommandHandler.Category category : server.commandHandler.getCategories()) { commands += category.category.commandsMap().size(); } - LogHelper.info("Sessions: %d | Modules: %d | Commands: %d(%d categories)", server.sessionManager.getSessions().size(), server.modulesManager.modules.size(), commands, server.commandHandler.getCategories().size() + 1); + LogHelper.info("Sessions: %d | Commands: %d(%d categories)", server.sessionManager.getSessions().size(), commands, server.commandHandler.getCategories().size() + 1); for (AuthProviderPair pair : server.config.auth) { if (pair.handler instanceof CachedAuthHandler) { LogHelper.info("AuthHandler %s: EntryCache: %d | usernameCache: %d", pair.name, ((CachedAuthHandler) pair.handler).getEntryCache().size(), ((CachedAuthHandler) pair.handler).getUsernamesCache().size()); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java index 94c58c7d..80ad1675 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -285,7 +285,7 @@ public static class GuardLicenseConf { public String key; public String encryptKey; } - public static LaunchServerConfig getDefault() + public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) { LaunchServerConfig newConfig = new LaunchServerConfig(); newConfig.mirrors = new String[]{"https://mirror.gravit.pro/"}; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/ModulesManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/ModulesManager.java index 776f461e..0dbcb0c7 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/ModulesManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/ModulesManager.java @@ -1,6 +1,7 @@ package pro.gravit.launchserver.manangers; import java.net.URL; +import java.nio.file.Path; import java.util.ArrayList; import pro.gravit.launcher.managers.SimpleModuleManager; @@ -13,14 +14,18 @@ public class ModulesManager extends SimpleModuleManager { public SimpleModulesConfigManager configManager; - public ModulesManager(LaunchServer lsrv) { + public ModulesManager(Path configDir) { modules = new ArrayList<>(1); - configManager = new SimpleModulesConfigManager(lsrv.dir.resolve("config")); + configManager = new SimpleModulesConfigManager(configDir); classloader = new PublicURLClassLoader(new URL[0], ClassLoader.getSystemClassLoader()); - context = new LaunchServerModuleContext(lsrv, classloader, configManager); registerCoreModule(); } + public void initContext(LaunchServer server) + { + context = new LaunchServerModuleContext(server, classloader, configManager); + } + private void registerCoreModule() { load(new CoreModule()); } diff --git a/LauncherTest/src/test/java/pro/gravit/launcher/StartTest.java b/LauncherTest/src/test/java/pro/gravit/launcher/StartTest.java index 52a53d7e..739f6479 100644 --- a/LauncherTest/src/test/java/pro/gravit/launcher/StartTest.java +++ b/LauncherTest/src/test/java/pro/gravit/launcher/StartTest.java @@ -24,13 +24,13 @@ public static void prepare() { @Test public void checkLaunchServerStarts() { - try { + /*try { LaunchServer srv = new LaunchServer(dir, true, new String[]{"checkInstall"}); srv.run(); srv.commandHandler.eval(new String[]{"checkInstall"}, false); srv.close(); } catch (InvalidKeySpecException | IOException e) { throw new RuntimeException(e); - } + }*/ } }