[REFACTOR] Remove log4j support, new LaunchServer start

This commit is contained in:
Gravita 2023-12-23 12:06:54 +07:00
commit 0855fc589d
12 changed files with 105 additions and 163 deletions

View file

@ -1,4 +1,4 @@
def mainClassName = "pro.gravit.launchserver.LaunchServerStarter"
def mainClassName = "pro.gravit.launchserver.Main"
def mainAgentName = "pro.gravit.launchserver.StarterAgent"
evaluationDependsOn(':Launcher')
@ -65,9 +65,7 @@
archiveClassifier.set('clean')
manifest.attributes("Main-Class": mainClassName,
"Premain-Class": mainAgentName,
"Can-Redefine-Classes": "true",
"Can-Retransform-Classes": "true",
"Can-Set-Native-Method-Prefix": "true"
"Automatic-Module-Name": "launchserver"
)
from sourceSets.main.output
}
@ -84,13 +82,15 @@ pack project(':LauncherModernCore')
bundle group: 'org.jline', name: 'jline-terminal', version: rootProject['verJline']
bundle group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: rootProject['verBcpkix']
bundle group: 'org.ow2.asm', name: 'asm-commons', version: rootProject['verAsm']
bundle group: 'io.netty', name: 'netty-all', version: rootProject['verNetty']
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: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j']
bundle group: 'com.mysql', name: 'mysql-connector-j', version: rootProject['verMySQLConn']
bundle group: 'org.postgresql', name: 'postgresql', version: rootProject['verPostgreSQLConn']
bundle 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-slf4j-impl', 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']
bundle group: 'io.jsonwebtoken', name: 'jjwt-impl', version: rootProject['verJwt']
bundle group: 'io.jsonwebtoken', name: 'jjwt-gson', version: rootProject['verJwt']
@ -104,16 +104,6 @@ pack project(':LauncherModernCore')
exclude group: 'org.slf4j'
}
launch4j('net.sf.launch4j:launch4j:' + rootProject['verLaunch4j']) {
exclude group: 'org.apache.ant'
exclude group: 'net.java.abeille'
exclude group: 'foxtrot'
exclude group: 'com.jgoodies'
exclude group: 'org.slf4j'
}
launch4j('net.sf.launch4j:launch4j:' + rootProject['verLaunch4j'] + ':workdir-win32') { transitive = false }
launch4j('net.sf.launch4j:launch4j:' + rootProject['verLaunch4j'] + ':workdir-linux64') { transitive = false }
compileOnlyA group: 'com.google.guava', name: 'guava', version: rootProject['verGuavaC']
// Do not update (laggy deps).
compileOnlyA 'log4j:log4j:1.2.17'

View file

@ -28,12 +28,15 @@
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.launch.LaunchOptions;
import pro.gravit.utils.launch.ModuleLaunch;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.Security;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
public class LaunchServerStarter {
@ -42,15 +45,10 @@ public class LaunchServerStarter {
private static final Logger logger = LogManager.getLogger();
public static void main(String[] args) throws Exception {
JVMHelper.checkStackTrace(LaunchServerStarter.class);
JVMHelper.verifySystemProperties(LaunchServer.class, true);
JVMHelper.verifySystemProperties(LaunchServer.class, false);
//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;
try {

View file

@ -0,0 +1,53 @@
package pro.gravit.launchserver;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.launch.ClassLoaderControl;
import pro.gravit.utils.launch.LaunchOptions;
import pro.gravit.utils.launch.ModuleLaunch;
import java.nio.file.FileVisitOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class Main {
private static final List<String> classpathOnly = List.of("proguard", "jline", "kotlin", "epoll");
private static boolean isClasspathOnly(Path path) {
var fileName = path.getFileName().toString();
for(var e : classpathOnly) {
if(fileName.contains(e)) {
return true;
}
}
return false;
}
public static void main(String[] args) throws Throwable {
ModuleLaunch launch = new ModuleLaunch();
LaunchOptions options = new LaunchOptions();
options.disablePackageDelegateSupport = true;
options.moduleConf = new LaunchOptions.ModuleConf();
List<Path> libraries;
try(Stream<Path> files = Files.walk(Path.of("libraries"), FileVisitOption.FOLLOW_LINKS)) {
libraries = new ArrayList<>(files.filter(e -> e.getFileName().toString().endsWith(".jar")).toList());
}
List<Path> classpath = new ArrayList<>();
List<String> modulepath = new ArrayList<>();
for(var l : libraries) {
if(isClasspathOnly(l)) {
classpath.add(l);
} else {
modulepath.add(l.toAbsolutePath().toString());
}
}
classpath.add(IOHelper.getCodeSource(LaunchServerStarter.class));
options.moduleConf.modulePath.addAll(modulepath);
options.moduleConf.modules.add("ALL-MODULE-PATH");
ClassLoaderControl control = launch.init(classpath, "natives", options);
ModuleLayer.Controller controller = (ModuleLayer.Controller) control.getJava9ModuleController();
launch.launch("pro.gravit.launchserver.LaunchServerStarter", null, Arrays.asList(args));
}
}

View file

@ -20,47 +20,6 @@ public static boolean isAgentStarted() {
}
public static void premain(String agentArgument, Instrumentation inst) {
StarterAgent.inst = inst;
libraries = Paths.get(Optional.ofNullable(agentArgument).map(String::trim).filter(e -> !e.isEmpty()).orElse("libraries"));
isStarted = true;
try {
Files.walkFileTree(libraries, Collections.singleton(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new StarterVisitor());
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
private static final class StarterVisitor extends SimpleFileVisitor<Path> {
private static final Set<PosixFilePermission> DPERMS;
static {
Set<PosixFilePermission> perms = new HashSet<>(Arrays.asList(PosixFilePermission.values()));
perms.remove(PosixFilePermission.OTHERS_WRITE);
perms.remove(PosixFilePermission.GROUP_WRITE);
DPERMS = Collections.unmodifiableSet(perms);
}
private final boolean fixLib;
private StarterVisitor() {
Path filef = StarterAgent.libraries.resolve(".libraries_chmoded");
this.fixLib = !Files.exists(filef) && !Boolean.getBoolean("launcher.noLibrariesPosixPermsFix");
if (fixLib) {
try {
Files.deleteIfExists(filef);
Files.createFile(filef);
} catch (Throwable ignored) {
}
}
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (fixLib && Files.getFileAttributeView(file, PosixFileAttributeView.class) != null)
Files.setPosixFilePermissions(file, DPERMS);
if (file.toFile().getName().endsWith(".jar"))
inst.appendToSystemClassLoaderSearch(new JarFile(file.toFile()));
return super.visitFile(file, attrs);
}
throw new UnsupportedOperationException("Please remove -javaagent option from start.sh");
}
}

View file

@ -1,8 +1,5 @@
package pro.gravit.launchserver.binary.tasks.exe;
import net.sf.launch4j.Builder;
import net.sf.launch4j.Log;
import net.sf.launch4j.config.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import pro.gravit.launchserver.LaunchServer;
@ -37,89 +34,6 @@ public String getName() {
@Override
public Path process(Path inputFile) throws IOException {
logger.info("Building launcher EXE binary file (Using Launch4J)");
Path output = setConfig();
// Set favicon path
Config config = ConfigPersister.getInstance().getConfig();
if (IOHelper.isFile(faviconFile))
config.setIcon(faviconFile.toFile());
else {
config.setIcon(null);
logger.warn("Missing favicon.ico file");
}
// Start building
Builder builder = new Builder(Launch4JLog.INSTANCE);
try {
builder.build();
} catch (Throwable e) {
throw new IOException(e);
}
return output;
}
private Path setConfig() {
Path path = server.launcherEXEBinary.nextPath(getName());
Config config = new Config();
// Set file options
config.setChdir(".");
config.setErrTitle("JVM Error");
config.setDownloadUrl(server.config.launch4j.downloadUrl);
if (server.config.launch4j.supportURL != null) config.setSupportUrl(server.config.launch4j.supportURL);
// Set boolean options
config.setPriorityIndex(0);
config.setHeaderType(Config.GUI_HEADER);
config.setStayAlive(false);
config.setRestartOnCrash(false);
// Prepare JRE
Jre jre = new Jre();
jre.setMinVersion(server.config.launch4j.minVersion);
if (server.config.launch4j.setMaxVersion)
jre.setMaxVersion(server.config.launch4j.maxVersion);
jre.setPath(System.getProperty("java.home"));
config.setJre(jre);
// Prepare version info (product)
VersionInfo info = new VersionInfo();
info.setProductName(server.config.launch4j.productName);
info.setProductVersion(formatVars(server.config.launch4j.productVer));
info.setFileDescription(server.config.launch4j.fileDesc);
info.setFileVersion(formatVars(server.config.launch4j.fileVer));
info.setCopyright(server.config.launch4j.copyright);
info.setTrademarks(server.config.launch4j.trademarks);
info.setInternalName(formatVars(server.config.launch4j.internalName));
// Prepare version info (file)
info.setTxtFileVersion(formatVars(server.config.launch4j.txtFileVersion));
info.setTxtProductVersion(formatVars(server.config.launch4j.txtProductVersion));
// Prepare version info (misc)
info.setOriginalFilename(path.getFileName().toString());
info.setLanguage(LanguageID.RUSSIAN);
config.setVersionInfo(info);
// Set JAR wrapping options
config.setDontWrapJar(false);
config.setJar(server.launcherBinary.syncBinaryFile.toFile());
config.setOutfile(path.toFile());
// Return prepared config
ConfigPersister.getInstance().setAntConfig(config, null);
return path;
}
private final static class Launch4JLog extends Log {
private static final Launch4JLog INSTANCE = new Launch4JLog();
private static final Logger logger = LogManager.getLogger();
@Override
public void append(String s) {
logger.info(s);
}
@Override
public void clear() {
// Do nothing
}
throw new UnsupportedOperationException("Launch4j not supported");
}
}

View file

@ -171,6 +171,14 @@ public void start(boolean pipeOutput) throws IOException, InterruptedException {
LogHelper.debug("Commandline: %s", Arrays.toString(processArgs.toArray()));
ProcessBuilder processBuilder = new ProcessBuilder(processArgs);
EnvHelper.addEnv(processBuilder);
if(JVMHelper.OS_TYPE == JVMHelper.OS.LINUX){
var env = processBuilder.environment();
// https://github.com/Admicos/minecraft-wayland/issues/55
env.put("__GL_THREADED_OPTIMIZATIONS", "0");
if(params.lwjglGlfwWayland) {
env.remove("DISPLAY"); // No X11
}
}
processBuilder.environment().put("JAVA_HOME", javaVersion.jvmDir.toAbsolutePath().toString());
processBuilder.environment().putAll(systemEnv);
processBuilder.directory(workDir.toFile());

View file

@ -7,6 +7,7 @@
import java.util.UUID;
public class AuthService {
public static String projectName;
public static String username;
public static ClientPermissions permissions = new ClientPermissions();
public static UUID uuid;

View file

@ -33,7 +33,7 @@ public class SimpleModuleManager implements LauncherModulesManager {
protected final ModulesConfigManager modulesConfigManager;
protected final Path modulesDir;
protected final LauncherTrustManager trustManager;
protected final PublicURLClassLoader classLoader = new PublicURLClassLoader(new URL[]{});
protected final PublicURLClassLoader classLoader = new PublicURLClassLoader(new URL[]{}, SimpleModuleManager.class.getClassLoader());
protected LauncherInitContext initContext;
public SimpleModuleManager(Path modulesDir, Path configDir) {

View file

@ -60,6 +60,8 @@ public final class ClientProfile implements Comparable<ClientProfile> {
@LauncherNetworkAPI
private List<String> compatClasses;
@LauncherNetworkAPI
private List<String> loadNatives;
@LauncherNetworkAPI
private Map<String, String> properties;
@LauncherNetworkAPI
private List<ServerProfile> servers;
@ -253,6 +255,10 @@ public ProfileDefaultSettings getSettings() {
return settings;
}
public List<String> getLoadNatives() {
return loadNatives;
}
public void updateOptionalGraph() {
for (OptionalFile file : updateOptional) {
if (file.dependenciesFile != null) {
@ -460,7 +466,7 @@ public enum ClassLoaderConfig {
}
public enum CompatibilityFlags {
LEGACY_NATIVES_DIR, CLASS_CONTROL_API, ENABLE_HACKS
LEGACY_NATIVES_DIR, CLASS_CONTROL_API, ENABLE_HACKS, WAYLAND_USE_CUSTOM_GLFW
}
public static class Version implements Comparable<Version> {

View file

@ -145,6 +145,12 @@ private static void realMain(String[] args) throws Throwable {
LaunchOptions options = new LaunchOptions();
options.enableHacks = profile.hasFlag(ClientProfile.CompatibilityFlags.ENABLE_HACKS);
options.moduleConf = profile.getModuleConf();
ClientService.nativePath = params.nativesDir;
if(profile.getLoadNatives() != null) {
for(String e : profile.getLoadNatives()) {
System.load(Paths.get(params.nativesDir).resolve(ClientService.findLibrary(e)).toAbsolutePath().toString());
}
}
if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER) {
if(JVMHelper.JVM_VERSION <= 11) {
launch = new LegacyLaunch();
@ -154,7 +160,6 @@ private static void realMain(String[] args) throws Throwable {
classLoaderControl = launch.init(classpath, params.nativesDir, options);
System.setProperty("java.class.path", classpath.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator)));
modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(launch, classLoaderControl, profile));
ClientService.nativePath = params.nativesDir;
ClientService.baseURLs = classLoaderControl.getURLs();
} else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.AGENT) {
launch = new BasicLaunch(LauncherAgent.inst);
@ -164,22 +169,21 @@ private static void realMain(String[] args) throws Throwable {
LauncherAgent.addJVMClassPath(Paths.get(url.toURI()));
}
ClientService.instrumentation = LauncherAgent.inst;
ClientService.nativePath = params.nativesDir;
modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(launch, null, profile));
ClientService.baseURLs = classpathURLs.toArray(new URL[0]);
} else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
launch = new BasicLaunch();
classLoaderControl = launch.init(classpath, params.nativesDir, options);
ClientService.baseURLs = classpathURLs.toArray(new URL[0]);
ClientService.nativePath = params.nativesDir;
}
if(profile.hasFlag(ClientProfile.CompatibilityFlags.CLASS_CONTROL_API)) {
ClientService.classLoaderControl = classLoaderControl;
}
if(params.lwjglGlfwWayland) {
String glfwPath = ClientService.findLibrary("glfw_wayland");
System.setProperty("org.lwjgl.glfw.libname", glfwPath);
if(params.lwjglGlfwWayland && profile.hasFlag(ClientProfile.CompatibilityFlags.WAYLAND_USE_CUSTOM_GLFW)) {
String glfwName = ClientService.findLibrary("glfw_wayland");
System.setProperty("org.lwjgl.glfw.libname", glfwName);
}
AuthService.projectName = Launcher.getConfig().projectName;
AuthService.username = params.playerProfile.username;
AuthService.uuid = params.playerProfile.uuid;
KeyService.serverRsaPublicKey = Launcher.getConfig().rsaPublicKey;

View file

@ -24,6 +24,7 @@
import pro.gravit.utils.helper.SecurityHelper;
import pro.gravit.utils.launch.*;
import java.io.File;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@ -180,12 +181,21 @@ public void run(String... args) throws Throwable {
System.arraycopy(args, 1, real_args, 0, args.length - 1);
} else real_args = args;
Launch launch;
ClientService.nativePath = config.nativesDir;
ConfigService.serverName = config.serverName;
if(config.loadNatives != null) {
for(String e : config.loadNatives) {
System.load(Paths.get(config.nativesDir).resolve(ClientService.findLibrary(e)).toAbsolutePath().toString());
}
}
switch (config.classLoaderConfig) {
case LAUNCHER:
launch = new LegacyLaunch();
System.setProperty("java.class.path", String.join(File.pathSeparator, config.classpath));
break;
case MODULE:
launch = new ModuleLaunch();
System.setProperty("java.class.path", String.join(File.pathSeparator, config.classpath));
break;
default:
if(ServerAgent.isAgentStarted()) {
@ -204,13 +214,10 @@ public void run(String... args) throws Throwable {
}
ClientService.classLoaderControl = classLoaderControl;
ClientService.baseURLs = classLoaderControl.getURLs();
ClientService.nativePath = config.nativesDir;
ConfigService.serverName = config.serverName;
if(config.configServiceSettings != null) {
config.configServiceSettings.apply();
}
LogHelper.info("Start Minecraft Server");
LogHelper.debug("Invoke main method %s with %s", classname, launch.getClass().getName());
try {
if(config.compatClasses != null) {
for (String e : config.compatClasses) {
@ -219,6 +226,7 @@ public void run(String... args) throws Throwable {
runMethod.invoke(classLoaderControl);
}
}
LogHelper.debug("Invoke main method %s with %s", classname, launch.getClass().getName());
launch.launch(config.mainclass, config.mainmodule, Arrays.asList(real_args));
} catch (Throwable e) {
LogHelper.error(e);
@ -271,6 +279,7 @@ public static final class Config {
public String nativesDir = "natives";
public List<String> args;
public List<String> compatClasses;
public List<String> loadNatives;
public String authId;
public AuthRequestEvent.OAuthRequestEvent oauth;
public long oauthExpireTime;

View file

@ -10,7 +10,7 @@
verBcprov = '1.70'
verGson = '2.10.1'
verBcpkix = '1.70'
verSlf4j = '1.7.36'
verSlf4j = '2.0.9'
verLog4j = '2.20.0'
verMySQLConn = '8.1.0'
verPostgreSQLConn = '42.6.0'