diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/ru/gravit/launchserver/LaunchServer.java index a5b5fd99..8750977a 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/LaunchServer.java @@ -32,6 +32,7 @@ import java.util.zip.CRC32; import ru.gravit.launcher.Launcher; +import ru.gravit.launcher.LauncherConfig; import ru.gravit.launcher.hasher.HashedDir; import ru.gravit.launcher.managers.GarbageManager; import ru.gravit.launcher.profiles.ClientProfile; @@ -48,10 +49,7 @@ import ru.gravit.launchserver.auth.handler.AuthHandler; import ru.gravit.launchserver.auth.hwid.HWIDHandler; import ru.gravit.launchserver.auth.provider.AuthProvider; -import ru.gravit.launchserver.binary.EXEL4JLauncherBinary; -import ru.gravit.launchserver.binary.EXELauncherBinary; -import ru.gravit.launchserver.binary.JARLauncherBinary; -import ru.gravit.launchserver.binary.LauncherBinary; +import ru.gravit.launchserver.binary.*; import ru.gravit.launchserver.command.handler.CommandHandler; import ru.gravit.launchserver.command.handler.JLineCommandHandler; import ru.gravit.launchserver.command.handler.StdCommandHandler; @@ -112,6 +110,7 @@ public static final class Config extends ConfigObject { public final String binaryName; private final StringConfigEntry address; private final String bindAddress; + public final LauncherConfig.LauncherEnvironment env; private Config(BlockConfigEntry block, Path coredir, LaunchServer server) { super(block); @@ -157,6 +156,7 @@ private Config(BlockConfigEntry block, Path coredir, LaunchServer server) { isUsingWrapper = block.getEntryValue("isUsingWrapper", BooleanConfigEntry.class); isDownloadJava = block.getEntryValue("isDownloadJava", BooleanConfigEntry.class); + env = LauncherConfig.LauncherEnvironment.STD; } diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/auth/MySQLSourceConfig.java b/LaunchServer/src/main/java/ru/gravit/launchserver/auth/MySQLSourceConfig.java index 6a0c1321..11837fbd 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/auth/MySQLSourceConfig.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/auth/MySQLSourceConfig.java @@ -105,19 +105,13 @@ public synchronized Connection getConnection() throws SQLException { Class.forName("com.zaxxer.hikari.HikariDataSource"); hikari = true; // Used for shutdown. Not instanceof because of possible classpath error HikariConfig cfg = new HikariConfig(); - cfg.setUsername(username); - cfg.setPassword(password); cfg.setDataSource(mysqlSource); cfg.setPoolName(poolName); - cfg.setMinimumIdle(0); cfg.setMaximumPoolSize(MAX_POOL_SIZE); - cfg.setIdleTimeout(TIMEOUT * 1000L); // Set HikariCP pool - HikariDataSource hikariSource = new HikariDataSource(cfg); // Replace source with hds - source = hikariSource; + source = new HikariDataSource(cfg); LogHelper.info("HikariCP pooling enabled for '%s'", poolName); - return hikariSource.getConnection(); } catch (ClassNotFoundException ignored) { LogHelper.warning("HikariCP isn't in classpath for '%s'", poolName); } diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JAConfigurator.java b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JAConfigurator.java index b6d6182c..e0bf0464 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JAConfigurator.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JAConfigurator.java @@ -8,8 +8,9 @@ import javassist.CtConstructor; import javassist.CtMethod; import javassist.NotFoundException; +import ru.gravit.launcher.LauncherConfig; -public class JAConfigurator implements AutoCloseable { + public class JAConfigurator implements AutoCloseable { public ClassPool pool; public CtClass ctClass; public CtConstructor ctConstructor; @@ -92,6 +93,28 @@ public void setPort(int port) { body.append(port); body.append(";"); } + public void setEnv(LauncherConfig.LauncherEnvironment env) { + int i = 2; + switch(env) + { + + case DEV: + i = 0; + break; + case DEBUG: + i = 1; + break; + case STD: + i = 2; + break; + case PROD: + i = 3; + break; + } + body.append("this.env = "); + body.append(i); + body.append(";"); + } public void setClientPort(int port) { body.append("this.clientPort = "); diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java index cbab0d08..981ae0c7 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java @@ -216,6 +216,7 @@ private void stdBuild() throws IOException { jaConfigurator.setClientPort(32148 + SecurityHelper.newRandom().nextInt(512)); jaConfigurator.setUsingWrapper(server.config.isUsingWrapper); jaConfigurator.setDownloadJava(server.config.isDownloadJava); + jaConfigurator.setEnv(server.config.env); server.buildHookManager.registerAllClientModuleClass(jaConfigurator); try (ZipInputStream input = new ZipInputStream(IOHelper.newInput(cleanJar))) { ZipEntry e = input.getNextEntry(); diff --git a/ServerWrapper/src/main/java/ru/gravit/launcher/server/ServerAgent.java b/ServerWrapper/src/main/java/ru/gravit/launcher/server/ServerAgent.java index b776f501..8f3578dc 100644 --- a/ServerWrapper/src/main/java/ru/gravit/launcher/server/ServerAgent.java +++ b/ServerWrapper/src/main/java/ru/gravit/launcher/server/ServerAgent.java @@ -1,9 +1,13 @@ package ru.gravit.launcher.server; +import ru.gravit.utils.helper.IOHelper; import ru.gravit.utils.helper.LogHelper; import java.io.IOException; import java.lang.instrument.Instrumentation; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.Collections; @@ -31,21 +35,42 @@ public static void addJVMClassPath(JarFile file) throws IOException { inst.appendToSystemClassLoaderSearch(file); } - public boolean isAgentStarted() { + public static boolean isAgentStarted() { return isAgentStarted; } public static long getObjSize(Object obj) { return inst.getObjectSize(obj); } - + public static Boolean isAutoloadLibraries = Boolean.getBoolean(System.getProperty("serverwrapper,agentlibrariesload","false")); + public static Boolean isAgentProxy = Boolean.getBoolean(System.getProperty("serverwrapper,agentproxy","false")); public static void premain(String agentArgument, Instrumentation instrumentation) { LogHelper.debug("Server Agent"); inst = instrumentation; isAgentStarted = true; - + if(isAutoloadLibraries) + { + Path libraries = Paths.get("libraries"); + if(IOHelper.exists(libraries)) loadLibraries(libraries); + } + if(isAgentProxy) + { + String proxyClassName = System.getProperty("serverwrapper,agentproxyclass"); + Class proxyClass; + try { + proxyClass = Class.forName(proxyClassName); + MethodHandle mainMethod = MethodHandles.publicLookup().findStatic(proxyClass, "premain", MethodType.methodType(void.class, String.class, Instrumentation.class)); + Object[] args = {agentArgument,instrumentation}; + mainMethod.invoke(args); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + public static void loadLibraries(Path dir) + { try { - Files.walkFileTree(Paths.get("libraries"), Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new StarterVisitor()); + Files.walkFileTree(dir, Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new StarterVisitor()); } catch (IOException e) { e.printStackTrace(System.err); } diff --git a/ServerWrapper/src/main/java/ru/gravit/launcher/server/ServerWrapper.java b/ServerWrapper/src/main/java/ru/gravit/launcher/server/ServerWrapper.java index 1b54ba2a..3b8cad0d 100644 --- a/ServerWrapper/src/main/java/ru/gravit/launcher/server/ServerWrapper.java +++ b/ServerWrapper/src/main/java/ru/gravit/launcher/server/ServerWrapper.java @@ -7,8 +7,10 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import java.util.HashMap; import ru.gravit.launcher.Launcher; @@ -21,6 +23,7 @@ import ru.gravit.launcher.serialize.config.entry.BooleanConfigEntry; import ru.gravit.launcher.serialize.config.entry.IntegerConfigEntry; import ru.gravit.launcher.serialize.config.entry.StringConfigEntry; +import ru.gravit.utils.PublicURLClassLoader; import ru.gravit.utils.helper.CommonHelper; import ru.gravit.utils.helper.IOHelper; import ru.gravit.utils.helper.LogHelper; @@ -31,8 +34,13 @@ public class ServerWrapper { public static ModulesManager modulesManager; - public static Path configFile; public static Config config; + public static PublicURLClassLoader ucp; + public static ClassLoader loader; + + public static Path modulesDir = Paths.get(System.getProperty("serverwrapper.modulesDir","modules")); + public static Path configFile = Paths.get(System.getProperty("serverwrapper.configFile","ServerWrapper.cfg")); + public static Path publicKeyFile = Paths.get(System.getProperty("serverwrapper.publicKeyFile","public.key")); public static boolean auth(ServerWrapper wrapper) { try { @@ -79,15 +87,14 @@ public static void main(String[] args) throws Throwable { LogHelper.printVersion("ServerWrapper"); LogHelper.printLicense("ServerWrapper"); modulesManager = new ModulesManager(wrapper); - modulesManager.autoload(Paths.get("srv_modules")); //BungeeCord using modules dir + modulesManager.autoload(modulesDir); Launcher.modulesManager = modulesManager; - configFile = Paths.get("ServerWrapper.cfg"); modulesManager.preInitModules(); generateConfigIfNotExists(); try (BufferedReader reader = IOHelper.newReader(configFile)) { config = new Config(TextConfigReader.read(reader, true)); } - LauncherConfig cfg = new LauncherConfig(config.address, config.port, SecurityHelper.toPublicRSAKey(IOHelper.read(Paths.get("public.key"))), new HashMap<>(), config.projectname); + LauncherConfig cfg = new LauncherConfig(config.address, config.port, SecurityHelper.toPublicRSAKey(IOHelper.read(publicKeyFile)), new HashMap<>(), config.projectname); Launcher.setConfig(cfg); if (config.syncAuth) auth(wrapper); else @@ -99,19 +106,43 @@ public static void main(String[] args) throws Throwable { LogHelper.error("MainClass not found. Please set MainClass for ServerWrapper.cfg or first commandline argument"); } Class mainClass; - if (config.customClassLoader) { - @SuppressWarnings("unchecked") - Class classloader_class = (Class) Class.forName(config.classloader); - ClassLoader loader = classloader_class.getConstructor(ClassLoader.class).newInstance(ClassLoader.getSystemClassLoader()); - Thread.currentThread().setContextClassLoader(loader); - mainClass = Class.forName(classname, false, loader); - } else mainClass = Class.forName(classname); + if(config.customClassPath) + { + String[] cp = config.classpath.split(":"); + if(!ServerAgent.isAgentStarted()) + { + LogHelper.warning("JavaAgent not found. Using URLClassLoader"); + URL[] urls = Arrays.stream(cp).map(Paths::get).map(IOHelper::toURL).toArray(URL[]::new); + ucp = new PublicURLClassLoader(urls); + Thread.currentThread().setContextClassLoader(ucp); + loader = ucp; + } + else + { + LogHelper.info("Found %d custom classpath elements",cp.length); + for(String c : cp) + ServerAgent.addJVMClassPath(c); + } + } + if(config.autoloadLibraries) + { + if(!ServerAgent.isAgentStarted()) + { + throw new UnsupportedOperationException("JavaAgent not found, autoloadLibraries not available"); + } + Path librariesDir = Paths.get(config.librariesDir); + LogHelper.info("Load libraries"); + ServerAgent.loadLibraries(librariesDir); + } + if(loader != null) mainClass = Class.forName(classname,true, loader); + else mainClass = Class.forName(classname); MethodHandle mainMethod = MethodHandles.publicLookup().findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class)); String[] real_args = new String[args.length - 1]; System.arraycopy(args, 1, real_args, 0, args.length - 1); modulesManager.postInitModules(); LogHelper.info("ServerWrapper: Project %s, LaunchServer address: %s port %d. Title: %s",config.projectname,config.address,config.port,config.title); LogHelper.info("Minecraft Version (for profile): %s",wrapper.profile.getVersion().name); + LogHelper.info("Start Minecraft Server"); LogHelper.debug("Invoke main method %s", mainClass.getName()); mainMethod.invoke(real_args); } @@ -143,9 +174,11 @@ public static final class Config extends ConfigObject { public int port; public int reconnectCount; public int reconnectSleep; - public boolean customClassLoader; + public boolean customClassPath; + public boolean autoloadLibraries; public boolean syncAuth; - public String classloader; + public String classpath; + public String librariesDir; public String mainclass; public String login; public String password; @@ -158,9 +191,12 @@ protected Config(BlockConfigEntry block) { login = block.getEntryValue("login", StringConfigEntry.class); password = block.getEntryValue("password", StringConfigEntry.class); port = block.getEntryValue("port", IntegerConfigEntry.class); - customClassLoader = block.getEntryValue("customClassLoader", BooleanConfigEntry.class); - if (customClassLoader) - classloader = block.getEntryValue("classloader", StringConfigEntry.class); + customClassPath = block.getEntryValue("customClassPath", BooleanConfigEntry.class); + autoloadLibraries = block.getEntryValue("autoloadLibraries", BooleanConfigEntry.class); + if (customClassPath) + classpath = block.getEntryValue("classpath", StringConfigEntry.class); + if (autoloadLibraries) + librariesDir = block.getEntryValue("librariesDir", StringConfigEntry.class); mainclass = block.getEntryValue("MainClass", StringConfigEntry.class); reconnectCount = block.hasEntry("reconnectCount") ? block.getEntryValue("reconnectCount", IntegerConfigEntry.class) : 1; reconnectSleep = block.hasEntry("reconnectSleep") ? block.getEntryValue("reconnectSleep", IntegerConfigEntry.class) : 30000; diff --git a/ServerWrapper/src/main/resources/ru/gravit/launcher/server/ServerWrapper.cfg b/ServerWrapper/src/main/resources/ru/gravit/launcher/server/ServerWrapper.cfg index 9250a4d4..9b1ce0c7 100644 --- a/ServerWrapper/src/main/resources/ru/gravit/launcher/server/ServerWrapper.cfg +++ b/ServerWrapper/src/main/resources/ru/gravit/launcher/server/ServerWrapper.cfg @@ -1,6 +1,11 @@ title: "xxxx"; -customClassLoader: false; -classloader: "ru.gravit.utils.PublicURLClassLoader"; + +autoloadLibraries: false; +librariesDir: "libraries"; + +customClassPath: false; +classpath: "server.jar"; + MainClass: ""; address: "localhost"; port: 7240; diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 0d4a9516..457aad0d 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a95009c3..75b8c7c8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index cccdd3d5..af6708ff 100755 --- a/gradlew +++ b/gradlew @@ -28,7 +28,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index f9553162..6d57edc7 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/libLauncher/src/main/java/ru/gravit/launcher/AutogenConfig.java b/libLauncher/src/main/java/ru/gravit/launcher/AutogenConfig.java index 4434bb6b..371ab370 100644 --- a/libLauncher/src/main/java/ru/gravit/launcher/AutogenConfig.java +++ b/libLauncher/src/main/java/ru/gravit/launcher/AutogenConfig.java @@ -9,6 +9,11 @@ public class AutogenConfig { public boolean isUsingWrapper; public boolean isDownloadJava; //Выставление этого флага требует модификации runtime части public String secretKeyClient; + public int env; + // 0 - Dev (дебаг включен по умолчанию, все сообщения) + // 1 - Debug (дебаг включен по умолчанию, основные сообщения) + // 2 - Std (дебаг выключен по умолчанию, основные сообщения) + // 3 - Production (дебаг выключен, минимальный объем сообщений, stacktrace не выводится) AutogenConfig() { diff --git a/libLauncher/src/main/java/ru/gravit/launcher/Launcher.java b/libLauncher/src/main/java/ru/gravit/launcher/Launcher.java index d1df3038..eb0442c6 100644 --- a/libLauncher/src/main/java/ru/gravit/launcher/Launcher.java +++ b/libLauncher/src/main/java/ru/gravit/launcher/Launcher.java @@ -59,7 +59,7 @@ public final class Launcher { public static int MAJOR = 4; public static int MINOR = 1; public static int PATCH = 0; - public static int BUILD = 1; + public static int BUILD = 3; public static Version.Type RELEASE = Version.Type.DEV; @LauncherAPI diff --git a/libLauncher/src/main/java/ru/gravit/launcher/LauncherConfig.java b/libLauncher/src/main/java/ru/gravit/launcher/LauncherConfig.java index 6d220f64..abe997e7 100644 --- a/libLauncher/src/main/java/ru/gravit/launcher/LauncherConfig.java +++ b/libLauncher/src/main/java/ru/gravit/launcher/LauncherConfig.java @@ -56,6 +56,20 @@ public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException secretKeyClient = config.secretKeyClient; isDownloadJava = config.isDownloadJava; isUsingWrapper = config.isUsingWrapper; + LauncherEnvironment env; + if(config.env == 0) env = LauncherEnvironment.DEV; + else if(config.env == 1) env = LauncherEnvironment.DEBUG; + else if(config.env == 2) env = LauncherEnvironment.STD; + else if(config.env == 3) env = LauncherEnvironment.PROD; + else env = LauncherEnvironment.STD; + if(env == LauncherEnvironment.PROD) { + LogHelper.setStacktraceEnabled(false); + LogHelper.setDebugEnabled(false); + } + if(env == LauncherEnvironment.DEV || env == LauncherEnvironment.DEBUG) + { + LogHelper.setDebugEnabled(true); + } // Read signed runtime int count = input.readLength(0); Map localResources = new HashMap<>(count); @@ -108,4 +122,9 @@ public void write(HOutput output) throws IOException { output.writeByteArray(entry.getValue(), SecurityHelper.CRYPTO_MAX_LENGTH); } } + + public enum LauncherEnvironment + { + DEV,DEBUG,STD,PROD + } } diff --git a/libLauncher/src/main/java/ru/gravit/utils/helper/LogHelper.java b/libLauncher/src/main/java/ru/gravit/utils/helper/LogHelper.java index 46cfa1a3..23125e63 100644 --- a/libLauncher/src/main/java/ru/gravit/utils/helper/LogHelper.java +++ b/libLauncher/src/main/java/ru/gravit/utils/helper/LogHelper.java @@ -27,6 +27,8 @@ public final class LogHelper { @LauncherAPI public static final String DEBUG_PROPERTY = "launcher.debug"; @LauncherAPI + public static final String STACKTRACE_PROPERTY = "launcher.stacktrace"; + @LauncherAPI public static final String NO_JANSI_PROPERTY = "launcher.noJAnsi"; @LauncherAPI public static final boolean JANSI; @@ -34,6 +36,7 @@ public final class LogHelper { // Output settings private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss", Locale.US); private static final AtomicBoolean DEBUG_ENABLED = new AtomicBoolean(Boolean.getBoolean(DEBUG_PROPERTY)); + private static final AtomicBoolean STACKTRACE_ENABLED = new AtomicBoolean(Boolean.getBoolean(STACKTRACE_PROPERTY)); private static final Set OUTPUTS = Collections.newSetFromMap(new ConcurrentHashMap<>(2)); private static final Output STD_OUTPUT; @@ -73,7 +76,7 @@ public static void debug(String format, Object... args) { @LauncherAPI public static void error(Throwable exc) { - error(isDebugEnabled() ? toString(exc) : exc.toString()); + error(isStacktraceEnabled() ? toString(exc) : exc.toString()); } @LauncherAPI @@ -106,6 +109,16 @@ public static void setDebugEnabled(boolean debugEnabled) { DEBUG_ENABLED.set(debugEnabled); } + @LauncherAPI + public static boolean isStacktraceEnabled() { + return STACKTRACE_ENABLED.get(); + } + + @LauncherAPI + public static void setStacktraceEnabled(boolean stacktraceEnabled) { + STACKTRACE_ENABLED.set(stacktraceEnabled); + } + @LauncherAPI public static void log(Level level, String message, boolean sub) { String dateTime = DATE_TIME_FORMATTER.format(LocalDateTime.now());