From af2c5c33e80d0c7e8f9fb77244d53448485ad1aa Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Fri, 25 Apr 2025 17:54:00 +0700 Subject: [PATCH] [FEATURE][EXPERIMENTAL] Usage Java modular system for start, change proguard libraries --- LaunchServer/build.gradle | 22 +++++-- .../pro/gravit/launchserver/LaunchServer.java | 8 ++- .../launchserver/asm/ClassMetadataReader.java | 65 +++++++++++++++++-- .../tasks/AdditionalFixesApplyTask.java | 2 +- .../binary/tasks/MainBuildTask.java | 6 +- .../components/ProGuardComponent.java | 2 +- modules | 2 +- 7 files changed, 90 insertions(+), 17 deletions(-) diff --git a/LaunchServer/build.gradle b/LaunchServer/build.gradle index d65390bf..6f4973fe 100644 --- a/LaunchServer/build.gradle +++ b/LaunchServer/build.gradle @@ -29,6 +29,7 @@ bundleOnly bundle pack + proguardPack bundleOnly.extendsFrom bundle api.extendsFrom bundle, pack } @@ -36,11 +37,13 @@ jar { dependsOn parent.childProjects.Launcher.tasks.assemble from { configurations.pack.collect { it.isDirectory() ? it : zipTree(it) } } + exclude("module-info.class") from(parent.childProjects.Launcher.tasks.shadowJar) from(parent.childProjects.Launcher.tasks.genRuntimeJS) manifest.attributes("Main-Class": mainClassName, "Premain-Class": mainAgentName, "Multi-Release": "true", + "Automatic-Module-Name": "launchserver" ) } @@ -72,7 +75,10 @@ dependencies { - pack project(':LauncherAPI') + pack(project(':LauncherAPI')) { + exclude group: "com.google.code.gson" + } + bundle group: 'com.google.code.gson', name: 'gson', version: rootProject['verGson'] bundle group: 'me.tongfei', name: 'progressbar', version: '0.10.1' bundle group: 'org.fusesource.jansi', name: 'jansi', version: rootProject['verJansi'] bundle group: 'org.jline', name: 'jline-native', version: rootProject['verJline'] @@ -84,10 +90,10 @@ pack project(':LauncherAPI') bundle group: 'io.netty', name: 'netty-codec-http', version: rootProject['verNetty'] bundle group: 'io.netty', name: 'netty-transport-classes-epoll', version: rootProject['verNetty'] bundle group: 'io.netty', name: 'netty-transport-native-epoll', version: rootProject['verNetty'], classifier: 'linux-x86_64' - bundle group: 'io.netty', name: 'netty-transport-native-epoll', version: rootProject['verNetty'], classifier: 'linux-aarch_64' + //bundle group: 'io.netty', name: 'netty-transport-native-epoll', version: rootProject['verNetty'], classifier: 'linux-aarch_64' bundle group: 'io.netty', name: 'netty-transport-classes-io_uring', version: rootProject['verNetty'] bundle group: 'io.netty', name: 'netty-transport-native-io_uring', version: rootProject['verNetty'], classifier: 'linux-x86_64' - bundle group: 'io.netty', name: 'netty-transport-native-io_uring', version: rootProject['verNetty'], classifier: 'linux-aarch_64' + //bundle group: 'io.netty', name: 'netty-transport-native-io_uring', version: rootProject['verNetty'], classifier: 'linux-aarch_64' // Netty bundle 'org.jboss.marshalling:jboss-marshalling:1.4.11.Final' bundle 'com.google.protobuf.nano:protobuf-javanano:3.1.0' @@ -97,7 +103,7 @@ pack project(':LauncherAPI') bundle group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: rootProject['verMariaDBConn'] bundle group: 'org.postgresql', name: 'postgresql', version: rootProject['verPostgreSQLConn'] bundle group: 'com.h2database', name: 'h2', version: rootProject['verH2Conn'] - bundle group: 'com.guardsquare', name: 'proguard-base', version: rootProject['verProguard'] + proguardPack group: 'com.guardsquare', name: 'proguard-base', version: rootProject['verProguard'] bundle group: 'org.apache.logging.log4j', name: 'log4j-core', version: rootProject['verLog4j'] bundle group: 'org.apache.logging.log4j', name: 'log4j-slf4j2-impl', version: rootProject['verLog4j'] bundle group: 'io.jsonwebtoken', name: 'jjwt-api', version: rootProject['verJwt'] @@ -121,6 +127,12 @@ pack project(':LauncherAPI') from configurations.bundleOnly } +tasks.register('dumpProguard', Copy) { + duplicatesStrategy = 'EXCLUDE' + into "$buildDir/libs/proguard" + from configurations.proguardPack +} + tasks.register('bundle', Zip) { duplicatesStrategy = 'EXCLUDE' dependsOn parent.childProjects.Launcher.tasks.build, tasks.dumpLibs, tasks.jar @@ -137,7 +149,7 @@ pack project(':LauncherAPI') from parent.childProjects.Launcher.tasks.dumpLibs } -assemble.dependsOn tasks.dumpLibs, tasks.dumpClientLibs, tasks.bundle, tasks.cleanjar +assemble.dependsOn tasks.dumpLibs, tasks.dumpClientLibs, tasks.bundle, tasks.cleanjar, tasks.dumpProguard publishing { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index 81246ff8..2d644ea7 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -82,6 +82,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab public final Path launcherModulesDir; public final Path librariesDir; public final Path controlFile; + public final Path proguardDir; /** * This object contains runtime configuration */ @@ -138,6 +139,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La launcherModulesDir = directories.launcherModules; librariesDir = directories.librariesDir; controlFile = directories.controlFile; + proguardDir = directories.proguardDir; this.shardId = shardId; if(!Files.isDirectory(launcherPack)) { Files.createDirectories(launcherPack); @@ -462,13 +464,16 @@ public interface LaunchServerConfigManager { public static class LaunchServerDirectories { public static final String UPDATES_NAME = "updates", TRUSTSTORE_NAME = "truststore", LAUNCHERLIBRARIES_NAME = "launcher-libraries", - LAUNCHERLIBRARIESCOMPILE_NAME = "launcher-libraries-compile", LAUNCHERPACK_NAME = "launcher-pack", KEY_NAME = ".keys", MODULES = "modules", LAUNCHER_MODULES = "launcher-modules", LIBRARIES = "libraries", CONTROL_FILE = "control-file"; + LAUNCHERLIBRARIESCOMPILE_NAME = "launcher-libraries-compile", LAUNCHERPACK_NAME = "launcher-pack", + KEY_NAME = ".keys", MODULES = "modules", LAUNCHER_MODULES = "launcher-modules", + LIBRARIES = "libraries", CONTROL_FILE = "control-file", PROGUARD_DIR = "proguard-libraries"; public Path updatesDir; public Path librariesDir; public Path launcherLibrariesDir; public Path launcherLibrariesCompileDir; public Path launcherPackDir; public Path keyDirectory; + public Path proguardDir; public Path dir; public Path trustStore; public Path tmpDir; @@ -489,6 +494,7 @@ public void collect() { if (launcherModules == null) launcherModules = getPath(LAUNCHER_MODULES); if (librariesDir == null) librariesDir = getPath(LIBRARIES); if (controlFile == null) controlFile = getPath(CONTROL_FILE); + if (proguardDir == null) proguardDir = getPath(PROGUARD_DIR); if (tmpDir == null) tmpDir = Paths.get(System.getProperty("java.io.tmpdir")).resolve("launchserver-%s".formatted(SecurityHelper.randomStringToken())); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/asm/ClassMetadataReader.java b/LaunchServer/src/main/java/pro/gravit/launchserver/asm/ClassMetadataReader.java index 07ccbaa1..c5ccc0ff 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/asm/ClassMetadataReader.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/asm/ClassMetadataReader.java @@ -1,16 +1,17 @@ package pro.gravit.launchserver.asm; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Opcodes; import pro.gravit.utils.helper.IOHelper; import java.io.Closeable; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.jar.JarFile; /** @@ -18,14 +19,32 @@ * чего угодно. Работает через поиск class-файлов в classpath. */ public class ClassMetadataReader implements Closeable { + private final Logger logger = LogManager.getLogger(ClassMetadataReader.class); private final List cp; + private final Map moduleClassFinder; public ClassMetadataReader(List cp) { this.cp = cp; + //var moduleLayer = ClassMetadataReader.class.getModule().getLayer() == null ? ModuleLayer.boot() : ClassMetadataReader.class.getModule().getLayer(); + var moduleLayer = ModuleLayer.boot(); + moduleClassFinder = collectModulePackages(moduleLayer); } public ClassMetadataReader() { this.cp = new ArrayList<>(); + //var moduleLayer = ClassMetadataReader.class.getModule().getLayer() == null ? ModuleLayer.boot() : ClassMetadataReader.class.getModule().getLayer(); + var moduleLayer = ModuleLayer.boot(); + moduleClassFinder = collectModulePackages(moduleLayer); + } + + private Map collectModulePackages(ModuleLayer layer) { + var map = new HashMap(); + for(var m : layer.modules()) { + for(var p : m.getPackages()) { + map.put(p, m); + } + } + return map; } public List getCp() { @@ -58,7 +77,42 @@ public byte[] getClassData(String className) throws IOException { return bytes; } } - return IOHelper.read(IOHelper.getResourceURL(className + ".class")); + if(ClassMetadataReader.class.getModule().isNamed()) { + String pkg = getClassPackage(className).replace('/', '.'); + var module = moduleClassFinder.get(pkg); + if(module != null) { + var cl = module.getClassLoader(); + if(cl == null) { + cl = ClassLoader.getPlatformClassLoader(); + } + var stream = cl.getResourceAsStream(className+".class"); + if(stream != null) { + try(stream) { + return IOHelper.read(stream); + } + } else { + throw new FileNotFoundException("Class "+className + ".class"); + } + } else { + throw new FileNotFoundException("Package "+pkg); + } + } + var stream = ClassLoader.getSystemClassLoader().getResourceAsStream(className+".class"); + if(stream != null) { + try(stream) { + return IOHelper.read(stream); + } + } else { + throw new FileNotFoundException(className + ".class"); + } + } + + private String getClassPackage(String type) { + int idx = type.lastIndexOf("/"); + if(idx <= 0) { + return type; + } + return type.substring(0, idx); } public String getSuperClass(String type) { @@ -66,6 +120,7 @@ public String getSuperClass(String type) { try { return getSuperClassASM(type); } catch (Exception e) { + logger.warn("getSuperClass: type {} not found ({}: {})", type, e.getClass().getName(), e.getMessage()); return "java/lang/Object"; } } @@ -100,7 +155,7 @@ private static class CheckSuperClassVisitor extends ClassVisitor { String superClassName; public CheckSuperClassVisitor() { - super(Opcodes.ASM7); + super(Opcodes.ASM9); } @Override diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AdditionalFixesApplyTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AdditionalFixesApplyTask.java index fdb2c3ee..b21abd2c 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AdditionalFixesApplyTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/AdditionalFixesApplyTask.java @@ -54,7 +54,7 @@ public static void apply(Path inputFile, Path addFile, ZipOutputStream output, L private static byte[] classFix(InputStream input, ClassMetadataReader reader, boolean stripNumbers) throws IOException { ClassReader cr = new ClassReader(input); ClassNode cn = new ClassNode(); - cr.accept(cn, stripNumbers ? (ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES) : ClassReader.SKIP_FRAMES); + cr.accept(cn, stripNumbers ? (ClassReader.SKIP_DEBUG) : 0); ClassWriter cw = new SafeClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); cn.accept(cw); return cw.toByteArray(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java index 9475456f..f6141e78 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java @@ -146,7 +146,7 @@ public byte[] transformClass(byte[] bytes, String classname, BuildContext contex asmTransformer.transform(cn, classname, context); continue; } else if (cn != null) { - writer = new SafeClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + writer = new SafeClassWriter(reader, 0); cn.accept(writer); result = writer.toByteArray(); } @@ -157,7 +157,7 @@ public byte[] transformClass(byte[] bytes, String classname, BuildContext contex } } if (cn != null) { - writer = new SafeClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + writer = new SafeClassWriter(reader, 0); cn.accept(writer); result = writer.toByteArray(); } @@ -175,7 +175,7 @@ default byte[] transform(byte[] input, String classname, BuildContext context) { ClassNode cn = new ClassNode(); reader.accept(cn, 0); transform(cn, classname, context); - SafeClassWriter writer = new SafeClassWriter(context.task.reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + SafeClassWriter writer = new SafeClassWriter(context.task.reader, 0); cn.accept(writer); return writer.toByteArray(); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/components/ProGuardComponent.java b/LaunchServer/src/main/java/pro/gravit/launchserver/components/ProGuardComponent.java index 47370210..cafea4f6 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/components/ProGuardComponent.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/components/ProGuardComponent.java @@ -213,7 +213,7 @@ public Path process(Path inputFile) throws IOException { args.add(IOHelper.resolveJavaBin(IOHelper.JVM_DIR).toAbsolutePath().toString()); args.addAll(component.jvmArgs); args.add("-cp"); - try(Stream files = Files.walk(server.librariesDir, FileVisitOption.FOLLOW_LINKS)) { + try(Stream files = Files.walk(server.proguardDir, FileVisitOption.FOLLOW_LINKS)) { args.add(files .filter(e -> e.getFileName().toString().endsWith(".jar")) .map(path -> path.toAbsolutePath().toString()) diff --git a/modules b/modules index eeea0709..03804a3a 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit eeea07098281c5cc98feffaae9b5a01677ca2eb7 +Subproject commit 03804a3a0e638f05c9ce65c01dbdb2f6c9ae630c