From 88f1eaf750140547014f63a2510c1cf3327c3875 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Sun, 21 Jul 2024 20:39:18 +0700 Subject: [PATCH 01/31] [ANY] Update modules --- modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules b/modules index 9f1ccd0b..c5087d40 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit 9f1ccd0bbc767d04a8a2d2909cc050980c8a458f +Subproject commit c5087d40c9dd5b065fccedeac21afb967a25e112 From d720328bc4236d5d0d5de138c231d60505187f6f Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Thu, 25 Jul 2024 15:51:43 +0700 Subject: [PATCH 02/31] [FEATURE] moduleConf in SYSTEM_ARGS --- .../runtime/client/ClientLauncherProcess.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Launcher/src/main/java/pro/gravit/launcher/runtime/client/ClientLauncherProcess.java b/Launcher/src/main/java/pro/gravit/launcher/runtime/client/ClientLauncherProcess.java index aaf4c5be..22b1b843 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/runtime/client/ClientLauncherProcess.java +++ b/Launcher/src/main/java/pro/gravit/launcher/runtime/client/ClientLauncherProcess.java @@ -145,7 +145,22 @@ public void start(boolean pipeOutput) throws IOException, InterruptedException { if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.AGENT) { processArgs.add("-javaagent:".concat(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString())); } else if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) { - systemClassPath.addAll(ClientLauncherEntryPoint.resolveClassPath(new HashSet<>(), workDir, params.actions, params.profile) + Set ignorePath = new HashSet<>(); + var moduleConf = params.profile.getModuleConf(); + if(moduleConf != null) { + if(moduleConf.modulePath != null && !moduleConf.modulePath.isEmpty()) { + processArgs.add("-p"); + for(var e : moduleConf.modulePath) { + ignorePath.add(Path.of(e)); + } + processArgs.add(String.join(File.pathSeparator, moduleConf.modulePath)); + } + if(moduleConf.modules != null && !moduleConf.modules.isEmpty()) { + processArgs.add("--add-modules"); + processArgs.add(String.join(",", moduleConf.modules)); + } + } + systemClassPath.addAll(ClientLauncherEntryPoint.resolveClassPath(ignorePath, workDir, params.actions, params.profile) .map(Path::toString) .toList()); } From ef4f14f9b4c63310f53373989ce25950a70b3c46 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:33:49 +0700 Subject: [PATCH 03/31] [FIX] Add netty epoll lib for aarch64 (ARM) --- LaunchServer/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/LaunchServer/build.gradle b/LaunchServer/build.gradle index 303c086f..d03cc45d 100644 --- a/LaunchServer/build.gradle +++ b/LaunchServer/build.gradle @@ -80,6 +80,7 @@ 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: 'org.slf4j', name: 'slf4j-api', version: rootProject['verSlf4j'] bundle group: 'com.mysql', name: 'mysql-connector-j', version: rootProject['verMySQLConn'] bundle group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: rootProject['verMariaDBConn'] From 4be299f6ca8e47750ba522dc9d79f89c0fe08e94 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:43:00 +0700 Subject: [PATCH 04/31] [FIX] Add ClassLoader.registerAsParallelCapable() --- .../src/main/java/pro/gravit/utils/launch/LegacyLaunch.java | 4 ++++ .../src/main/java/pro/gravit/utils/launch/ModuleLaunch.java | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/LauncherCore/src/main/java/pro/gravit/utils/launch/LegacyLaunch.java b/LauncherCore/src/main/java/pro/gravit/utils/launch/LegacyLaunch.java index 1a155fe4..a7511ad9 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/launch/LegacyLaunch.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/launch/LegacyLaunch.java @@ -54,6 +54,10 @@ private class LegacyClassLoader extends URLClassLoader { private final Map> classMap = new ConcurrentHashMap<>(); private String nativePath; + static { + ClassLoader.registerAsParallelCapable(); + } + private final List packages = new ArrayList<>(); public LegacyClassLoader(URL[] urls) { super(urls); diff --git a/LauncherCore/src/main/java/pro/gravit/utils/launch/ModuleLaunch.java b/LauncherCore/src/main/java/pro/gravit/utils/launch/ModuleLaunch.java index 5a414ea8..d83e3c44 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/launch/ModuleLaunch.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/launch/ModuleLaunch.java @@ -164,6 +164,11 @@ private class ModuleClassLoader extends URLClassLoader { private String nativePath; private final List packages = new ArrayList<>(); + + static { + ClassLoader.registerAsParallelCapable(); + } + public ModuleClassLoader(URL[] urls, ClassLoader parent) { super("LAUNCHER", urls, parent); packages.add("pro.gravit.launcher."); From 9bffe07d369921850574cfcb408cc2514187852d Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Thu, 25 Jul 2024 22:20:48 +0700 Subject: [PATCH 05/31] [FEATURE] ProfileProvider --- .../pro/gravit/launchserver/LaunchServer.java | 51 ++-------- .../launchserver/LaunchServerStarter.java | 2 + .../auth/profiles/LocalProfileProvider.java | 93 +++++++++++++++++++ .../auth/profiles/ProfileProvider.java | 76 +++++++++++++++ .../command/hash/DownloadClientCommand.java | 5 +- .../command/profiles/CloneProfileCommand.java | 19 ++-- .../profiles/DeleteProfileCommand.java | 21 ++--- .../command/profiles/MakeProfileCommand.java | 4 +- .../command/profiles/SaveProfilesCommand.java | 30 ++---- .../config/LaunchServerConfig.java | 12 +++ .../manangers/LaunchServerGsonManager.java | 2 + 11 files changed, 218 insertions(+), 97 deletions(-) create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/ProfileProvider.java diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index 3745386f..595d1cdb 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -80,7 +80,6 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab /** * The path to the folder with profiles */ - public final Path profilesDir; public final Path tmpDir; public final Path modulesDir; public final Path launcherModulesDir; @@ -119,8 +118,6 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab private final Logger logger = LogManager.getLogger(); public final int shardId; public LaunchServerConfig config; - // Updates and profiles - private volatile Set profilesList; public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, KeyAgreementManager keyAgreementManager, CommandHandler commandHandler, CertificateManager certificateManager, int shardId) throws IOException { this.dir = directories.dir; @@ -129,7 +126,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La this.config = config; this.launchServerConfigManager = launchServerConfigManager; this.modulesManager = modulesManager; - this.profilesDir = directories.profilesDir; this.updatesDir = directories.updatesDir; this.keyAgreementManager = keyAgreementManager; this.commandHandler = commandHandler; @@ -326,12 +322,14 @@ public void close() throws Exception { logger.info("LaunchServer stopped"); } + @Deprecated public Set getProfiles() { - return profilesList; + return config.profileProvider.getProfiles(); } + @Deprecated public void setProfiles(Set profilesList) { - this.profilesList = Collections.unmodifiableSet(profilesList); + throw new UnsupportedOperationException(); } public void rebindNettyServerSocket() { @@ -358,8 +356,6 @@ public void run() { CommonHelper.newThread("Profiles and updates sync", true, () -> { try { // Sync profiles dir - if (!IOHelper.isDir(profilesDir)) - Files.createDirectory(profilesDir); syncProfilesDir(); // Sync updates dir @@ -402,12 +398,7 @@ public void syncLauncherBinaries() throws IOException { public void syncProfilesDir() throws IOException { logger.info("Syncing profiles dir"); - List newProfies = new LinkedList<>(); - IOHelper.walk(profilesDir, new ProfilesFileVisitor(newProfies), false); - - // Sort and set new profiles - newProfies.sort(Comparator.comparing(a -> a)); - profilesList = Set.copyOf(newProfies); + config.profileProvider.sync(); if (config.netty.sendProfileUpdatesEvent) { sendUpdateProfilesEvent(); } @@ -422,7 +413,7 @@ private void sendUpdateProfilesEvent() { if (client == null || !client.isAuth) { return; } - ProfilesRequestEvent event = new ProfilesRequestEvent(ProfilesResponse.getListVisibleProfiles(this, client)); + ProfilesRequestEvent event = new ProfilesRequestEvent(config.profileProvider.getProfiles(client)); event.requestUUID = RequestEvent.eventUUID; handler.service.sendObject(ch, event); }); @@ -468,38 +459,11 @@ public interface LaunchServerConfigManager { void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOException; } - private static final class ProfilesFileVisitor extends SimpleFileVisitor { - private final Collection result; - private final Logger logger = LogManager.getLogger(); - - private ProfilesFileVisitor(Collection result) { - this.result = result; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - logger.info("Syncing '{}' profile", IOHelper.getFileName(file)); - - // Read profile - ClientProfile profile; - try (BufferedReader reader = IOHelper.newReader(file)) { - profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class); - } - profile.verify(); - profile.setProfileFilePath(file); - - // Add SIGNED profile to result list - result.add(profile); - return super.visitFile(file, attrs); - } - } - public static class LaunchServerDirectories { - public static final String UPDATES_NAME = "updates", PROFILES_NAME = "profiles", + 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"; public Path updatesDir; - public Path profilesDir; public Path librariesDir; public Path launcherLibrariesDir; public Path launcherLibrariesCompileDir; @@ -513,7 +477,6 @@ public static class LaunchServerDirectories { public void collect() { if (updatesDir == null) updatesDir = getPath(UPDATES_NAME); - if (profilesDir == null) profilesDir = getPath(PROFILES_NAME); if (trustStore == null) trustStore = getPath(TRUSTSTORE_NAME); if (launcherLibrariesDir == null) launcherLibrariesDir = getPath(LAUNCHERLIBRARIES_NAME); if (launcherLibrariesCompileDir == null) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java index 16542fb6..ac26c218 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java @@ -13,6 +13,7 @@ import pro.gravit.launchserver.auth.core.AuthCoreProvider; import pro.gravit.launchserver.auth.mix.MixProvider; import pro.gravit.launchserver.auth.password.PasswordVerifier; +import pro.gravit.launchserver.auth.profiles.ProfileProvider; import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.texture.TextureProvider; import pro.gravit.launchserver.components.Component; @@ -178,6 +179,7 @@ public static void registerAll() { OptionalAction.registerProviders(); OptionalTrigger.registerProviders(); MixProvider.registerProviders(); + ProfileProvider.registerProviders(); } private static void printExperimentalBranch() { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java new file mode 100644 index 00000000..6fe18d54 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java @@ -0,0 +1,93 @@ +package pro.gravit.launchserver.auth.profiles; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import pro.gravit.launcher.base.Launcher; +import pro.gravit.launcher.base.profiles.ClientProfile; +import pro.gravit.utils.helper.IOHelper; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.*; + +public class LocalProfileProvider extends ProfileProvider { + public String profilesDir = "profiles"; + private transient volatile Map profilesMap; + private transient volatile Set profilesList; // Cache + @Override + public void sync() throws IOException { + Path profilesDirPath = Path.of(profilesDir); + if (!IOHelper.isDir(profilesDirPath)) + Files.createDirectory(profilesDirPath); + Map newProfiles = new HashMap<>(); + IOHelper.walk(profilesDirPath, new ProfilesFileVisitor(newProfiles), false); + Set newProfilesList = new HashSet<>(newProfiles.values()); + profilesMap = newProfiles; + profilesList = newProfilesList; + } + + @Override + public Set getProfiles() { + return profilesList; + } + + @Override + public void addProfile(ClientProfile profile) throws IOException { + Path profilesDirPath = Path.of(profilesDir); + Path target = IOHelper.resolveIncremental(profilesDirPath, + profile.getDir(), "json"); + try (BufferedWriter writer = IOHelper.newWriter(target)) { + Launcher.gsonManager.configGson.toJson(profile, writer); + } + addProfile(target, profile); + } + + @Override + public void deleteProfile(ClientProfile profile) throws IOException { + for(var e : profilesMap.entrySet()) { + if(e.getValue().getUUID().equals(profile.getUUID())) { + Files.deleteIfExists(e.getKey()); + profilesMap.remove(e.getKey()); + profilesList.remove(e.getValue()); + break; + } + } + } + + private void addProfile(Path path, ClientProfile profile) { + profilesMap.put(path, profile); + profilesList.add(profile); + } + + private static final class ProfilesFileVisitor extends SimpleFileVisitor { + private final Map result; + private final Logger logger = LogManager.getLogger(); + + private ProfilesFileVisitor(Map result) { + this.result = result; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + logger.info("Syncing '{}' profile", IOHelper.getFileName(file)); + + // Read profile + ClientProfile profile; + try (BufferedReader reader = IOHelper.newReader(file)) { + profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class); + } + profile.verify(); + profile.setProfileFilePath(file); + + // Add SIGNED profile to result list + result.put(file, profile); + return super.visitFile(file, attrs); + } + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/ProfileProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/ProfileProvider.java new file mode 100644 index 00000000..b5580021 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/ProfileProvider.java @@ -0,0 +1,76 @@ +package pro.gravit.launchserver.auth.profiles; + +import pro.gravit.launcher.base.profiles.ClientProfile; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.auth.protect.interfaces.ProfilesProtectHandler; +import pro.gravit.launchserver.socket.Client; +import pro.gravit.utils.ProviderMap; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public abstract class ProfileProvider { + public static final ProviderMap providers = new ProviderMap<>("ProfileProvider"); + private static boolean registredProviders = false; + protected transient LaunchServer server; + + public static void registerProviders() { + if (!registredProviders) { + providers.register("local", LocalProfileProvider.class); + registredProviders = true; + } + } + + public void init(LaunchServer server) { + this.server = server; + } + + public abstract void sync() throws IOException; + + public abstract Set getProfiles(); + + public abstract void addProfile(ClientProfile profile) throws IOException; + + public abstract void deleteProfile(ClientProfile profile) throws IOException; + + public void close() { + + } + + public ClientProfile getProfile(UUID uuid) { + for(var e : getProfiles()) { + if(e.getUUID().equals(uuid)) { + return e; + } + } + return null; + } + + public ClientProfile getProfile(String title) { + for(var e : getProfiles()) { + if(e.getTitle().equals(title)) { + return e; + } + } + return null; + } + + public List getProfiles(Client client) { + List profileList; + Set serverProfiles = getProfiles(); + if (server.config.protectHandler instanceof ProfilesProtectHandler protectHandler) { + profileList = new ArrayList<>(4); + for (ClientProfile profile : serverProfiles) { + if (protectHandler.canGetProfile(profile, client)) { + profileList.add(profile); + } + } + } else { + profileList = List.copyOf(serverProfiles); + } + return profileList; + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadClientCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadClientCommand.java index 9da32e9c..3b331e25 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadClientCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/hash/DownloadClientCommand.java @@ -97,10 +97,7 @@ public void invoke(String... args) throws IOException, CommandException { isMirrorClientDownload = true; } } - try (BufferedWriter writer = IOHelper.newWriter(IOHelper.resolveIncremental(server.profilesDir, - dirName, "json"))) { - Launcher.gsonManager.configGson.toJson(clientProfile, writer); - } + server.config.profileProvider.addProfile(clientProfile); // Finished server.syncProfilesDir(); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/CloneProfileCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/CloneProfileCommand.java index e943aa05..1b33cd43 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/CloneProfileCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/CloneProfileCommand.java @@ -7,6 +7,7 @@ import pro.gravit.launcher.base.profiles.ClientProfileBuilder; import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.command.Command; +import pro.gravit.utils.helper.CommonHelper; import pro.gravit.utils.helper.IOHelper; import java.io.IOException; @@ -26,7 +27,7 @@ public CloneProfileCommand(LaunchServer server) { @Override public String getArgsDescription() { - return "[profile file name] [new profile title]"; + return "[profile title/uuid] [new profile title]"; } @Override @@ -37,13 +38,12 @@ public String getUsageDescription() { @Override public void invoke(String... args) throws Exception { verifyArgs(args, 2); - var profilePath = server.profilesDir.resolve(args[0].concat(".json")); - if(!Files.exists(profilePath)) { - logger.error("File {} not found", profilePath); - } ClientProfile profile; - try(Reader reader = IOHelper.newReader(profilePath)) { - profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class); + try { + UUID uuid = UUID.fromString(args[0]); + profile = server.config.profileProvider.getProfile(uuid); + } catch (IllegalArgumentException ex) { + profile = server.config.profileProvider.getProfile(args[0]); } var builder = new ClientProfileBuilder(profile); builder.setTitle(args[1]); @@ -65,10 +65,7 @@ public void invoke(String... args) throws Exception { } builder.setDir(args[1]); profile = builder.createClientProfile(); - var targetPath = server.profilesDir.resolve(args[1].concat(".json")); - try(Writer writer = IOHelper.newWriter(targetPath)) { - Launcher.gsonManager.gson.toJson(profile, writer); - } + server.config.profileProvider.addProfile(profile); logger.info("Profile {} cloned from {}", args[1], args[0]); server.syncProfilesDir(); server.syncUpdatesDir(List.of(args[1])); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/DeleteProfileCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/DeleteProfileCommand.java index 642a115c..034d791b 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/DeleteProfileCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/DeleteProfileCommand.java @@ -8,6 +8,7 @@ import pro.gravit.utils.helper.IOHelper; import java.nio.file.Files; +import java.util.UUID; public class DeleteProfileCommand extends Command { private final transient Logger logger = LogManager.getLogger(ListProfilesCommand.class); @@ -28,12 +29,12 @@ public String getUsageDescription() { @Override public void invoke(String... args) throws Exception { verifyArgs(args, 1); - ClientProfile profile = null; - for(var p : server.getProfiles()) { - if(p.getUUID().toString().equals(args[0]) || p.getTitle().equals(args[0])) { - profile = p; - break; - } + ClientProfile profile; + try { + UUID uuid = UUID.fromString(args[0]); + profile = server.config.profileProvider.getProfile(uuid); + } catch (IllegalArgumentException ex) { + profile = server.config.profileProvider.getProfile(args[0]); } if(profile == null) { logger.error("Profile {} not found", args[0]); @@ -44,13 +45,9 @@ public void invoke(String... args) throws Exception { if(!showApplyDialog("Continue?")) { return; } + logger.info("Delete {} ({})", profile.getTitle(), profile.getUUID()); + server.config.profileProvider.deleteProfile(profile); logger.info("Delete {}", clientDir); IOHelper.deleteDir(clientDir, true); - var profileFile = profile.getProfileFilePath(); - if(profileFile == null) { - profileFile = server.profilesDir.resolve(profile.getTitle().concat(".json")); - } - logger.info("Delete {}", profileFile); - Files.deleteIfExists(profileFile); } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/MakeProfileCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/MakeProfileCommand.java index ad57670c..7a010c64 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/MakeProfileCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/MakeProfileCommand.java @@ -37,9 +37,7 @@ public void invoke(String... args) throws Exception { logger.info("Detected option {}", option); } ClientProfile profile = MakeProfileHelper.makeProfile(version, args[0], options); - try (Writer writer = IOHelper.newWriter(server.profilesDir.resolve(args[0].concat(".json")))) { - Launcher.gsonManager.configGson.toJson(profile, writer); - } + server.config.profileProvider.addProfile(profile); logger.info("Profile {} created", args[0]); server.syncProfilesDir(); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/SaveProfilesCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/SaveProfilesCommand.java index 7aba43a4..ab677c9c 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/SaveProfilesCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/SaveProfilesCommand.java @@ -22,20 +22,6 @@ public SaveProfilesCommand(LaunchServer server) { super(server); } - public static void saveProfile(ClientProfile profile, Path path) throws IOException { - if (profile.getServers().isEmpty()) { - ClientProfile.ServerProfile serverProfile = new ClientProfile.ServerProfile(); - serverProfile.isDefault = true; - serverProfile.name = profile.getTitle(); - serverProfile.serverAddress = profile.getServerAddress(); - serverProfile.serverPort = profile.getServerPort(); - profile.getServers().add(serverProfile); - } - try (Writer w = IOHelper.newWriter(path)) { - Launcher.gsonManager.configGson.toJson(profile, w); - } - } - @Override public String getArgsDescription() { return "[profile names...]"; @@ -51,17 +37,15 @@ public void invoke(String... args) throws Exception { verifyArgs(args, 1); if (args.length > 0) { for (String profileName : args) { - Path profilePath = server.profilesDir.resolve(profileName.concat(".json")); - if (!Files.exists(profilePath)) { - logger.error("Profile {} not found", profilePath.toString()); - return; - } ClientProfile profile; - try (Reader reader = IOHelper.newReader(profilePath)) { - profile = Launcher.gsonManager.configGson.fromJson(reader, ClientProfile.class); + try { + UUID uuid = UUID.fromString(profileName); + profile = server.config.profileProvider.getProfile(uuid); + } catch (IllegalArgumentException ex) { + profile = server.config.profileProvider.getProfile(profileName); } - saveProfile(profile, profilePath); - logger.info("Profile {} save successful", profilePath.toString()); + server.config.profileProvider.deleteProfile(profile); + server.config.profileProvider.addProfile(profile); } server.syncProfilesDir(); } 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 ecba3a95..562460c7 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -9,6 +9,8 @@ import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.auth.AuthProviderPair; import pro.gravit.launchserver.auth.core.RejectAuthCoreProvider; +import pro.gravit.launchserver.auth.profiles.LocalProfileProvider; +import pro.gravit.launchserver.auth.profiles.ProfileProvider; import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.protect.StdProtectHandler; import pro.gravit.launchserver.auth.texture.RequestTextureProvider; @@ -36,6 +38,7 @@ public final class LaunchServerConfig { // Handlers & Providers public ProtectHandler protectHandler; public Map components; + public ProfileProvider profileProvider = new LocalProfileProvider(); public NettyConfig netty; public LauncherConf launcher; public JarSignerConf sign; @@ -85,6 +88,7 @@ public static LaunchServerConfig getDefault(LaunchServer.LaunchServerEnv env) { newConfig.components.put("authLimiter", authLimiterComponent); ProGuardComponent proGuardComponent = new ProGuardComponent(); newConfig.components.put("proguard", proGuardComponent); + newConfig.profileProvider = new LocalProfileProvider(); return newConfig; } @@ -166,6 +170,10 @@ public void init(LaunchServer.ReloadType type) { server.registerObject("protectHandler", protectHandler); protectHandler.init(server); } + if(profileProvider != null) { + server.registerObject("profileProvider", profileProvider); + profileProvider.init(server); + } if (components != null) { components.forEach((k, v) -> server.registerObject("component.".concat(k), v)); } @@ -206,6 +214,10 @@ public void close(LaunchServer.ReloadType type) { server.unregisterObject("protectHandler", protectHandler); protectHandler.close(); } + if(profileProvider != null) { + server.unregisterObject("profileProvider", profileProvider); + profileProvider.close(); + } } public static class JarSignerConf { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java index 7f26c486..74a6ba98 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java @@ -14,6 +14,7 @@ import pro.gravit.launchserver.auth.core.AuthCoreProvider; import pro.gravit.launchserver.auth.mix.MixProvider; import pro.gravit.launchserver.auth.password.PasswordVerifier; +import pro.gravit.launchserver.auth.profiles.ProfileProvider; import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.texture.TextureProvider; import pro.gravit.launchserver.components.Component; @@ -46,6 +47,7 @@ public void registerAdapters(GsonBuilder builder) { builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers)); builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers)); builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers)); + builder.registerTypeAdapter(ProfileProvider.class, new UniversalJsonAdapter<>(ProfileProvider.providers)); modulesManager.invokeEvent(new PreGsonPhase(builder)); //ClientWebSocketService.appendTypeAdapters(builder); } From af2dcec8cd77f0ad45dbb970882fc5f9229bb982 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Thu, 25 Jul 2024 22:28:26 +0700 Subject: [PATCH 06/31] [FIX] ProfileProvider support overwrite profile --- .../auth/profiles/LocalProfileProvider.java | 32 ++++++++++++++----- .../command/profiles/SaveProfilesCommand.java | 1 - .../launcher/base/profiles/ClientProfile.java | 9 ------ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java index 6fe18d54..5c3725ea 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java @@ -9,10 +9,7 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; +import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.*; @@ -40,8 +37,21 @@ public Set getProfiles() { @Override public void addProfile(ClientProfile profile) throws IOException { Path profilesDirPath = Path.of(profilesDir); - Path target = IOHelper.resolveIncremental(profilesDirPath, - profile.getDir(), "json"); + ClientProfile oldProfile; + Path target = null; + for(var e : profilesMap.entrySet()) { + if(e.getValue().getUUID().equals(profile.getUUID())) { + target = e.getKey(); + } + } + if(target == null) { + target = IOHelper.resolveIncremental(profilesDirPath, + profile.getTitle(), "json"); + oldProfile = profilesMap.get(target); + if(oldProfile != null && !oldProfile.getUUID().equals(profile.getUUID())) { + throw new FileAlreadyExistsException(target.toString()); + } + } try (BufferedWriter writer = IOHelper.newWriter(target)) { Launcher.gsonManager.configGson.toJson(profile, writer); } @@ -61,6 +71,13 @@ public void deleteProfile(ClientProfile profile) throws IOException { } private void addProfile(Path path, ClientProfile profile) { + for(var e : profilesMap.entrySet()) { + if(e.getValue().getUUID().equals(profile.getUUID())) { + profilesMap.remove(e.getKey()); + profilesList.remove(e.getValue()); + break; + } + } profilesMap.put(path, profile); profilesList.add(profile); } @@ -83,10 +100,9 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO profile = Launcher.gsonManager.gson.fromJson(reader, ClientProfile.class); } profile.verify(); - profile.setProfileFilePath(file); // Add SIGNED profile to result list - result.put(file, profile); + result.put(file.toAbsolutePath(), profile); return super.visitFile(file, attrs); } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/SaveProfilesCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/SaveProfilesCommand.java index ab677c9c..9d796c1e 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/SaveProfilesCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/SaveProfilesCommand.java @@ -44,7 +44,6 @@ public void invoke(String... args) throws Exception { } catch (IllegalArgumentException ex) { profile = server.config.profileProvider.getProfile(profileName); } - server.config.profileProvider.deleteProfile(profile); server.config.profileProvider.addProfile(profile); } server.syncProfilesDir(); diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java index 5d55896d..0e4bab59 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java @@ -18,7 +18,6 @@ public final class ClientProfile implements Comparable { private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher( new String[0], new String[]{"indexes", "objects"}, new String[0]); - private transient Path profileFilePath; @LauncherNetworkAPI private String title; @LauncherNetworkAPI @@ -392,14 +391,6 @@ public List getFlags() { return flags; } - public Path getProfileFilePath() { - return profileFilePath; - } - - public void setProfileFilePath(Path profileFilePath) { - this.profileFilePath = profileFilePath; - } - public enum ClassLoaderConfig { AGENT, LAUNCHER, MODULE, SYSTEM_ARGS } From 2ed4abf9b0c8ed9a1911350cf87a083af3c0c149 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Fri, 26 Jul 2024 01:27:01 +0700 Subject: [PATCH 07/31] [FIX] Usage profilesProvider --- .../launchserver/socket/response/auth/ProfilesResponse.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ProfilesResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ProfilesResponse.java index 39058b76..6e5be16a 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ProfilesResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/auth/ProfilesResponse.java @@ -13,6 +13,7 @@ import java.util.Set; public class ProfilesResponse extends SimpleResponse { + @Deprecated public static List getListVisibleProfiles(LaunchServer server, Client client) { List profileList; Set serverProfiles = server.getProfiles(); @@ -40,6 +41,6 @@ public void execute(ChannelHandlerContext ctx, Client client) { sendError("Access denied"); return; } - sendResult(new ProfilesRequestEvent(getListVisibleProfiles(server, client))); + sendResult(new ProfilesRequestEvent(server.config.profileProvider.getProfiles(client))); } } From e6f5b585a767aab607a1eff11c0800dcec645c3c Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Tue, 30 Jul 2024 15:33:46 +0700 Subject: [PATCH 08/31] [ANY] Update modules --- modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules b/modules index c5087d40..e988b10d 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit c5087d40c9dd5b065fccedeac21afb967a25e112 +Subproject commit e988b10d8ac074230bae805d8dec85949db89a25 From 1e7a856a991c1341f0f4b762c2d6a468220530ef Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Tue, 30 Jul 2024 15:43:22 +0700 Subject: [PATCH 09/31] [FIX] Profile duplicate --- .../launchserver/auth/profiles/LocalProfileProvider.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java index 5c3725ea..c938a1f8 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/profiles/LocalProfileProvider.java @@ -45,8 +45,7 @@ public void addProfile(ClientProfile profile) throws IOException { } } if(target == null) { - target = IOHelper.resolveIncremental(profilesDirPath, - profile.getTitle(), "json"); + target = profilesDirPath.resolve(profile.getTitle()+".json"); oldProfile = profilesMap.get(target); if(oldProfile != null && !oldProfile.getUUID().equals(profile.getUUID())) { throw new FileAlreadyExistsException(target.toString()); From d5abe0d411389acbfe96089bd017d90728707b47 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Tue, 30 Jul 2024 17:34:20 +0700 Subject: [PATCH 10/31] [ANY] Update modules --- modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules b/modules index e988b10d..6639aefa 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit e988b10d8ac074230bae805d8dec85949db89a25 +Subproject commit 6639aefae714e6671e0dd3fecc803845d0e07d42 From a30d0624a1aaab12d19f5d677fbfe2fd76dd0338 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Tue, 30 Jul 2024 21:05:37 +0700 Subject: [PATCH 11/31] [ANY] Update modules --- modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules b/modules index 6639aefa..c1b3fd0a 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit 6639aefae714e6671e0dd3fecc803845d0e07d42 +Subproject commit c1b3fd0a89e398d9a726537aa756cf42e3058a40 From 3969d81db7df213cbcbbd3c105b33facd15645f0 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Tue, 30 Jul 2024 23:06:54 +0700 Subject: [PATCH 12/31] [ANY] Update modules --- modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules b/modules index c1b3fd0a..9127b086 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit c1b3fd0a89e398d9a726537aa756cf42e3058a40 +Subproject commit 9127b086a22c01a174e74a5101329500b106de62 From a687c5afd839bb417bc485c9ddc22f9815d319a2 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Tue, 30 Jul 2024 23:20:35 +0700 Subject: [PATCH 13/31] [ANY] Update gradle --- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43504 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 7 +++++-- gradlew.bat | 2 ++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..2c3521197d7c4586c843d1d3e9090525f1898cde 100644 GIT binary patch delta 8703 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 Ojj7^59?Sdh$^Qpp*~F>< delta 8662 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e7646dea..dedd5d1e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a42..f5feea6d 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # 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 25da30db..9d21a218 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## From b8ccbc5e48293ad1f00ef4ff58769d57c09106c5 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Wed, 31 Jul 2024 00:15:08 +0700 Subject: [PATCH 14/31] [FEATURE] UpdatesProvider Part 1 --- .../pro/gravit/launchserver/LaunchServer.java | 5 +- .../auth/updates/LocalUpdatesProvider.java | 168 ++++++++++++++++++ .../auth/updates/UpdatesProvider.java | 45 +++++ .../config/LaunchServerConfig.java | 4 +- .../manangers/LaunchServerGsonManager.java | 2 + .../manangers/UpdatesManager.java | 98 ++-------- 6 files changed, 232 insertions(+), 90 deletions(-) create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/LocalUpdatesProvider.java create mode 100644 LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java index 595d1cdb..a117dd48 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServer.java @@ -70,6 +70,7 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab /** * The path to the folder with updates/webroot */ + @Deprecated public final Path updatesDir; // Constant paths @@ -359,9 +360,7 @@ public void run() { syncProfilesDir(); // Sync updates dir - if (!IOHelper.isDir(updatesDir)) - Files.createDirectory(updatesDir); - updatesManager.readUpdatesDir(); + config.updatesProvider.syncInitially(); modulesManager.invokeEvent(new LaunchServerProfilesSyncEvent(this)); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/LocalUpdatesProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/LocalUpdatesProvider.java new file mode 100644 index 00000000..dc429863 --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/LocalUpdatesProvider.java @@ -0,0 +1,168 @@ +package pro.gravit.launchserver.auth.updates; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import pro.gravit.launcher.core.hasher.HashedDir; +import pro.gravit.launcher.core.serialize.HInput; +import pro.gravit.launcher.core.serialize.HOutput; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.modules.events.LaunchServerUpdatesSyncEvent; +import pro.gravit.utils.helper.IOHelper; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.stream.Stream; + +public class LocalUpdatesProvider extends UpdatesProvider { + private final transient Logger logger = LogManager.getLogger(); + public String cacheFile = ".updates-cache"; + public String updatesDir = "updates"; + public boolean cacheUpdates = true; + private volatile transient Map updatesDirMap; + + private void writeCache(Path file) throws IOException { + try (HOutput output = new HOutput(IOHelper.newOutput(file))) { + output.writeLength(updatesDirMap.size(), 0); + for (Map.Entry entry : updatesDirMap.entrySet()) { + output.writeString(entry.getKey(), 0); + entry.getValue().write(output); + } + } + logger.debug("Saved {} updates to cache", updatesDirMap.size()); + } + + private void readCache(Path file) throws IOException { + Map updatesDirMap = new HashMap<>(16); + try (HInput input = new HInput(IOHelper.newInput(file))) { + int size = input.readLength(0); + for (int i = 0; i < size; ++i) { + String name = input.readString(0); + HashedDir dir = new HashedDir(input); + updatesDirMap.put(name, dir); + } + } + logger.debug("Found {} updates from cache", updatesDirMap.size()); + this.updatesDirMap = Collections.unmodifiableMap(updatesDirMap); + } + + public void readUpdatesFromCache() throws IOException { + readCache(Path.of(cacheFile)); + } + + public void readUpdatesDir() throws IOException { + var cacheFilePath = Path.of(cacheFile); + if (cacheUpdates) { + if (Files.exists(cacheFilePath)) { + try { + readCache(cacheFilePath); + return; + } catch (Throwable e) { + logger.error("Read updates cache failed", e); + } + } + } + sync(null); + } + + @Override + public void init(LaunchServer server) { + super.init(server); + try { + if (!IOHelper.isDir(Path.of(updatesDir))) + Files.createDirectory(Path.of(updatesDir)); + } catch (IOException e) { + logger.error("Updates not synced", e); + } + } + + @Override + public void syncInitially() throws IOException { + readUpdatesDir(); + } + + public void sync(Collection dirs) throws IOException { + logger.info("Syncing updates dir"); + Map newUpdatesDirMap = new HashMap<>(16); + try (DirectoryStream dirStream = Files.newDirectoryStream(Path.of(updatesDir))) { + for (final Path updateDir : dirStream) { + if (Files.isHidden(updateDir)) + continue; // Skip hidden + + // Resolve name and verify is dir + String name = IOHelper.getFileName(updateDir); + if (!IOHelper.isDir(updateDir)) { + if (!IOHelper.isFile(updateDir) && Stream.of(".jar", ".exe", ".hash").noneMatch(e -> updateDir.toString().endsWith(e))) + logger.warn("Not update dir: '{}'", name); + continue; + } + + // Add from previous map (it's guaranteed to be non-null) + if (dirs != null && !dirs.contains(name)) { + HashedDir hdir = updatesDirMap.get(name); + if (hdir != null) { + newUpdatesDirMap.put(name, hdir); + continue; + } + } + + // Sync and sign update dir + logger.info("Syncing '{}' update dir", name); + HashedDir updateHDir = new HashedDir(updateDir, null, true, true); + newUpdatesDirMap.put(name, updateHDir); + } + } + updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap); + if (cacheUpdates) { + try { + writeCache(Path.of(cacheFile)); + } catch (Throwable e) { + logger.error("Write updates cache failed", e); + } + } + server.modulesManager.invokeEvent(new LaunchServerUpdatesSyncEvent(server)); + } + + @Override + public HashedDir getUpdatesDir(String updateName) { + return updatesDirMap.get(updateName); + } + + @Override + public void upload(String updateName, Map files, boolean deleteAfterUpload) throws IOException { + var path = Path.of(updatesDir).resolve(updateName); + for(var e : files.entrySet()) { + var target = path.resolve(e.getKey()); + var source = Path.of(e.getKey()); + IOHelper.createParentDirs(target); + if(deleteAfterUpload) { + Files.move(source, target); + } else { + Files.copy(source, target); + } + } + } + + @Override + public void delete(String updateName, List files) throws IOException { + var path = Path.of(updatesDir).resolve(updateName); + for(var e : files) { + var target = path.resolve(e); + Files.delete(target); + } + } + + @Override + public void delete(String updateName) throws IOException { + var path = Path.of(updatesDir).resolve(updateName); + IOHelper.deleteDir(path, true); + } + + @Override + public void create(String updateName) throws IOException { + var path = Path.of(updatesDir).resolve(updateName); + Files.createDirectories(path); + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java new file mode 100644 index 00000000..a6912d1e --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java @@ -0,0 +1,45 @@ +package pro.gravit.launchserver.auth.updates; + +import pro.gravit.launcher.core.hasher.HashedDir; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.utils.ProviderMap; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public abstract class UpdatesProvider { + public static final ProviderMap providers = new ProviderMap<>("UpdatesProvider"); + private static boolean registredProviders = false; + protected transient LaunchServer server; + + public static void registerProviders() { + if (!registredProviders) { + registredProviders = true; + } + } + + public void init(LaunchServer server) { + this.server = server; + } + + public void sync() throws IOException { + sync(null); + } + + public abstract void syncInitially() throws IOException; + + public abstract void sync(Collection updateNames) throws IOException; + + public abstract HashedDir getUpdatesDir(String updateName); + + public abstract void upload(String updateName, Map files, boolean deleteAfterUpload) throws IOException; + + public abstract void delete(String updateName, List files) throws IOException; + + public abstract void delete(String updateName) throws IOException; + + public abstract void create(String updateName) throws IOException; +} 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 562460c7..0b4e6937 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -14,6 +14,8 @@ import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.protect.StdProtectHandler; import pro.gravit.launchserver.auth.texture.RequestTextureProvider; +import pro.gravit.launchserver.auth.updates.LocalUpdatesProvider; +import pro.gravit.launchserver.auth.updates.UpdatesProvider; import pro.gravit.launchserver.components.AuthLimiterComponent; import pro.gravit.launchserver.components.Component; import pro.gravit.launchserver.components.ProGuardComponent; @@ -32,13 +34,13 @@ public final class LaunchServerConfig { public String[] mirrors; public String binaryName; public boolean copyBinaries = true; - public boolean cacheUpdates = true; public LauncherConfig.LauncherEnvironment env; public Map auth; // Handlers & Providers public ProtectHandler protectHandler; public Map components; public ProfileProvider profileProvider = new LocalProfileProvider(); + public UpdatesProvider updatesProvider = new LocalUpdatesProvider(); public NettyConfig netty; public LauncherConf launcher; public JarSignerConf sign; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java index 74a6ba98..4970e4f0 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/LaunchServerGsonManager.java @@ -17,6 +17,7 @@ import pro.gravit.launchserver.auth.profiles.ProfileProvider; import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.texture.TextureProvider; +import pro.gravit.launchserver.auth.updates.UpdatesProvider; import pro.gravit.launchserver.components.Component; import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager; import pro.gravit.launchserver.socket.WebSocketService; @@ -48,6 +49,7 @@ public void registerAdapters(GsonBuilder builder) { builder.registerTypeAdapter(OptionalTrigger.class, new UniversalJsonAdapter<>(OptionalTrigger.providers)); builder.registerTypeAdapter(MixProvider.class, new UniversalJsonAdapter<>(MixProvider.providers)); builder.registerTypeAdapter(ProfileProvider.class, new UniversalJsonAdapter<>(ProfileProvider.providers)); + builder.registerTypeAdapter(UpdatesProvider.class, new UniversalJsonAdapter<>(UpdatesProvider.providers)); modulesManager.invokeEvent(new PreGsonPhase(builder)); //ClientWebSocketService.appendTypeAdapters(builder); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/UpdatesManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/UpdatesManager.java index c2642d2e..717c65a7 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/UpdatesManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/UpdatesManager.java @@ -18,112 +18,38 @@ public class UpdatesManager { private final LaunchServer server; - private final Logger logger = LogManager.getLogger(); - private final Path cacheFile; - private volatile Map updatesDirMap; public UpdatesManager(LaunchServer server) { this.server = server; - this.cacheFile = server.dir.resolve(".updates-cache"); - } - - private void writeCache(Path file) throws IOException { - try (HOutput output = new HOutput(IOHelper.newOutput(file))) { - output.writeLength(updatesDirMap.size(), 0); - for (Map.Entry entry : updatesDirMap.entrySet()) { - output.writeString(entry.getKey(), 0); - entry.getValue().write(output); - } - } - logger.debug("Saved {} updates to cache", updatesDirMap.size()); - } - - private void readCache(Path file) throws IOException { - Map updatesDirMap = new HashMap<>(16); - try (HInput input = new HInput(IOHelper.newInput(file))) { - int size = input.readLength(0); - for (int i = 0; i < size; ++i) { - String name = input.readString(0); - HashedDir dir = new HashedDir(input); - updatesDirMap.put(name, dir); - } - } - logger.debug("Found {} updates from cache", updatesDirMap.size()); - this.updatesDirMap = Collections.unmodifiableMap(updatesDirMap); } + @Deprecated public void readUpdatesFromCache() throws IOException { - readCache(cacheFile); + } + @Deprecated public void readUpdatesDir() throws IOException { - if (server.config.cacheUpdates) { - if (Files.exists(cacheFile)) { - try { - readCache(cacheFile); - return; - } catch (Throwable e) { - logger.error("Read updates cache failed", e); - } - } - } - syncUpdatesDir(null); + } + @Deprecated public void syncUpdatesDir(Collection dirs) throws IOException { - logger.info("Syncing updates dir"); - Map newUpdatesDirMap = new HashMap<>(16); - try (DirectoryStream dirStream = Files.newDirectoryStream(server.updatesDir)) { - for (final Path updateDir : dirStream) { - if (Files.isHidden(updateDir)) - continue; // Skip hidden - - // Resolve name and verify is dir - String name = IOHelper.getFileName(updateDir); - if (!IOHelper.isDir(updateDir)) { - if (!IOHelper.isFile(updateDir) && Stream.of(".jar", ".exe", ".hash").noneMatch(e -> updateDir.toString().endsWith(e))) - logger.warn("Not update dir: '{}'", name); - continue; - } - - // Add from previous map (it's guaranteed to be non-null) - if (dirs != null && !dirs.contains(name)) { - HashedDir hdir = updatesDirMap.get(name); - if (hdir != null) { - newUpdatesDirMap.put(name, hdir); - continue; - } - } - - // Sync and sign update dir - logger.info("Syncing '{}' update dir", name); - HashedDir updateHDir = new HashedDir(updateDir, null, true, true); - newUpdatesDirMap.put(name, updateHDir); - } - } - updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap); - if (server.config.cacheUpdates) { - try { - writeCache(cacheFile); - } catch (Throwable e) { - logger.error("Write updates cache failed", e); - } - } - server.modulesManager.invokeEvent(new LaunchServerUpdatesSyncEvent(server)); + server.config.updatesProvider.sync(dirs); } + @Deprecated public HashSet getUpdatesList() { - HashSet set = new HashSet<>(); - for (Map.Entry entry : updatesDirMap.entrySet()) - set.add(entry.getKey()); - return set; + return new HashSet<>(); } + @Deprecated public HashedDir getUpdate(String name) { - return updatesDirMap.get(name); + return server.config.updatesProvider.getUpdatesDir(name); } + @Deprecated public void addUpdate(String name, HashedDir dir) { - updatesDirMap.put(name, dir); + throw new UnsupportedOperationException(); } } From 63f9f8e21dfc399503f695eadd46089ca7585234 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Wed, 31 Jul 2024 00:36:04 +0700 Subject: [PATCH 15/31] [FEATURE] UpdatesProvider Part 2 --- .../launchserver/binary/BinaryPipeline.java | 25 ++----------------- .../launchserver/binary/LauncherBinary.java | 22 ++++++++++++++-- .../profiles/DeleteProfileCommand.java | 7 +++--- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BinaryPipeline.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BinaryPipeline.java index 86fbf9c3..c735d0e0 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BinaryPipeline.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/BinaryPipeline.java @@ -14,11 +14,11 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -public class BinaryPipeline { +public abstract class BinaryPipeline { public final List tasks = new ArrayList<>(); public final Path buildDir; public final String nameFormat; - private transient final Logger logger = LogManager.getLogger(); + protected transient final Logger logger = LogManager.getLogger(); public BinaryPipeline(Path buildDir, String nameFormat) { this.buildDir = buildDir; @@ -80,27 +80,6 @@ public Optional getTaskBefore(Predicate pr return Optional.empty(); } - public void build(Path target, boolean deleteTempFiles) throws IOException { - logger.info("Building launcher binary file"); - Path thisPath = null; - long time_start = System.currentTimeMillis(); - long time_this = time_start; - for (LauncherBuildTask task : tasks) { - logger.info("Task {}", task.getName()); - Path oldPath = thisPath; - thisPath = task.process(oldPath); - long time_task_end = System.currentTimeMillis(); - long time_task = time_task_end - time_this; - time_this = time_task_end; - logger.info("Task {} processed from {} millis", task.getName(), time_task); - } - long time_end = System.currentTimeMillis(); - if (deleteTempFiles) IOHelper.move(thisPath, target); - else IOHelper.copy(thisPath, target); - IOHelper.deleteDir(buildDir, false); - logger.info("Build successful from {} millis", time_end - time_start); - } - public String nextName(String taskName) { return nameFormat.formatted(taskName); } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherBinary.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherBinary.java index a4ba76c0..6a2d4e97 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherBinary.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherBinary.java @@ -1,11 +1,13 @@ package pro.gravit.launchserver.binary; import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.binary.tasks.LauncherBuildTask; import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.SecurityHelper; import java.io.IOException; import java.nio.file.Path; +import java.util.Map; public abstract class LauncherBinary extends BinaryPipeline { public final LaunchServer server; @@ -19,11 +21,27 @@ protected LauncherBinary(LaunchServer server, Path binaryFile, String nameFormat } public static Path resolve(LaunchServer server, String ext) { - return server.config.copyBinaries ? server.updatesDir.resolve(server.config.binaryName + ext) : server.dir.resolve(server.config.binaryName + ext); + return Path.of(server.config.binaryName + ext); } public void build() throws IOException { - build(syncBinaryFile, server.config.launcher.deleteTempFiles); + logger.info("Building launcher binary file"); + Path thisPath = null; + long time_start = System.currentTimeMillis(); + long time_this = time_start; + for (LauncherBuildTask task : tasks) { + logger.info("Task {}", task.getName()); + Path oldPath = thisPath; + thisPath = task.process(oldPath); + long time_task_end = System.currentTimeMillis(); + long time_task = time_task_end - time_this; + time_this = time_task_end; + logger.info("Task {} processed from {} millis", task.getName(), time_task); + } + long time_end = System.currentTimeMillis(); + server.config.updatesProvider.upload(null, Map.of(syncBinaryFile.toString(), thisPath), true); + IOHelper.deleteDir(buildDir, false); + logger.info("Build successful from {} millis", time_end - time_start); } public final boolean exists() { diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/DeleteProfileCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/DeleteProfileCommand.java index 034d791b..f6a36659 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/DeleteProfileCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/profiles/DeleteProfileCommand.java @@ -40,14 +40,13 @@ public void invoke(String... args) throws Exception { logger.error("Profile {} not found", args[0]); return; } - var clientDir = server.updatesDir.resolve(profile.getDir()).toAbsolutePath(); - logger.warn("THIS ACTION DELETE PROFILE AND ALL FILES IN {}", clientDir); + logger.warn("THIS ACTION DELETE PROFILE AND ALL FILES IN {}", profile.getDir()); if(!showApplyDialog("Continue?")) { return; } logger.info("Delete {} ({})", profile.getTitle(), profile.getUUID()); server.config.profileProvider.deleteProfile(profile); - logger.info("Delete {}", clientDir); - IOHelper.deleteDir(clientDir, true); + logger.info("Delete {}", profile.getDir()); + server.config.updatesProvider.delete(profile.getDir()); } } From b0f799d1945f612659d12e7bd4bf302bc817ed91 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Mon, 5 Aug 2024 03:24:42 +0700 Subject: [PATCH 16/31] [FIX] UpdatesProvider init --- .../gravit/launchserver/auth/updates/UpdatesProvider.java | 4 ++++ .../gravit/launchserver/config/LaunchServerConfig.java | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java index a6912d1e..572b07d1 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java @@ -42,4 +42,8 @@ public void sync() throws IOException { public abstract void delete(String updateName) throws IOException; public abstract void create(String updateName) throws IOException; + + public void close() { + + } } 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 0b4e6937..f2121ba7 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -176,6 +176,10 @@ public void init(LaunchServer.ReloadType type) { server.registerObject("profileProvider", profileProvider); profileProvider.init(server); } + if(updatesProvider != null) { + server.registerObject("updatesProvider", updatesProvider); + updatesProvider.init(server); + } if (components != null) { components.forEach((k, v) -> server.registerObject("component.".concat(k), v)); } @@ -220,6 +224,10 @@ public void close(LaunchServer.ReloadType type) { server.unregisterObject("profileProvider", profileProvider); profileProvider.close(); } + if(updatesProvider != null) { + server.unregisterObject("updatesProvider", updatesProvider); + updatesProvider.close(); + } } public static class JarSignerConf { From 5e116a81e5f057cdd4acc3c7766862d771b0b264 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Mon, 5 Aug 2024 03:25:05 +0700 Subject: [PATCH 17/31] [ANY] Update modules --- modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules b/modules index 9127b086..f6158556 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit 9127b086a22c01a174e74a5101329500b106de62 +Subproject commit f615855642ebcb69c5bc98c918782b65ca785a74 From ca70ee78d1569d9d7ab25fbfa78b183ae06ff2c0 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Mon, 5 Aug 2024 05:34:45 +0700 Subject: [PATCH 18/31] [FIX] Launcher update --- .../auth/updates/LocalUpdatesProvider.java | 32 +++++++++++++++---- .../auth/updates/UpdatesProvider.java | 2 ++ .../launchserver/binary/LauncherBinary.java | 13 +++++--- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/LocalUpdatesProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/LocalUpdatesProvider.java index dc429863..581b35ac 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/LocalUpdatesProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/LocalUpdatesProvider.java @@ -13,6 +13,7 @@ import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.*; import java.util.stream.Stream; @@ -130,24 +131,41 @@ public HashedDir getUpdatesDir(String updateName) { return updatesDirMap.get(updateName); } + private Path resolveUpdateName(String updateName) { + if(updateName == null) { + return Path.of(updatesDir); + } + return Path.of(updatesDir).resolve(updateName); + } + @Override public void upload(String updateName, Map files, boolean deleteAfterUpload) throws IOException { - var path = Path.of(updatesDir).resolve(updateName); + var path = resolveUpdateName(updateName); for(var e : files.entrySet()) { var target = path.resolve(e.getKey()); - var source = Path.of(e.getKey()); + var source = e.getValue(); IOHelper.createParentDirs(target); if(deleteAfterUpload) { - Files.move(source, target); + Files.move(source, target, StandardCopyOption.REPLACE_EXISTING); } else { - Files.copy(source, target); + Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); } } } + @Override + public Map download(String updateName, List files) { + var path = resolveUpdateName(updateName); + Map map = new HashMap<>(); + for(var e : files) { + map.put(e, path.resolve(e)); + } + return map; + } + @Override public void delete(String updateName, List files) throws IOException { - var path = Path.of(updatesDir).resolve(updateName); + var path = resolveUpdateName(updateName); for(var e : files) { var target = path.resolve(e); Files.delete(target); @@ -156,13 +174,13 @@ public void delete(String updateName, List files) throws IOException { @Override public void delete(String updateName) throws IOException { - var path = Path.of(updatesDir).resolve(updateName); + var path = resolveUpdateName(updateName); IOHelper.deleteDir(path, true); } @Override public void create(String updateName) throws IOException { - var path = Path.of(updatesDir).resolve(updateName); + var path = resolveUpdateName(updateName); Files.createDirectories(path); } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java index 572b07d1..832f729c 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java @@ -37,6 +37,8 @@ public void sync() throws IOException { public abstract void upload(String updateName, Map files, boolean deleteAfterUpload) throws IOException; + public abstract Map download(String updateName, List files); + public abstract void delete(String updateName, List files) throws IOException; public abstract void delete(String updateName) throws IOException; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherBinary.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherBinary.java index 6a2d4e97..a336c439 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherBinary.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/LauncherBinary.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.List; import java.util.Map; public abstract class LauncherBinary extends BinaryPipeline { @@ -56,9 +57,13 @@ public void init() { } public final boolean sync() throws IOException { - boolean exists = exists(); - digest = exists ? SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512, IOHelper.read(syncBinaryFile)) : null; - - return exists; + try { + var target = syncBinaryFile.toString(); + var path = server.config.updatesProvider.download(null, List.of(target)).get(target); + digest = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA512, IOHelper.read(path)); + return true; + } catch (Throwable e) { + return false; + } } } From 9fba637f83e44feb155110e5f49a998c35e544b9 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Mon, 5 Aug 2024 05:36:53 +0700 Subject: [PATCH 19/31] [FIX] Launcher update token --- .../launchserver/socket/response/update/LauncherResponse.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java index 05e6c958..1e2285f1 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/socket/response/update/LauncherResponse.java @@ -52,7 +52,7 @@ public void execute(ChannelHandlerContext ctx, Client client) { client.checkSign = true; sendResult(new LauncherRequestEvent(false, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000)); } else { - sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000)); + sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherURL, null, 0)); } } else if (launcher_type == 2) //EXE { @@ -62,7 +62,7 @@ public void execute(ChannelHandlerContext ctx, Client client) { client.checkSign = true; sendResult(new LauncherRequestEvent(false, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000)); } else { - sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, createLauncherExtendedToken(), server.config.netty.security.launcherTokenExpire*1000)); + sendResultAndClose(new LauncherRequestEvent(true, server.config.netty.launcherEXEURL, null, 0)); } } else sendError("Request launcher type error"); } From 1ff58099bd5af8ca8922d2ce6e4f27d3d824beb3 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Tue, 6 Aug 2024 06:19:12 +0700 Subject: [PATCH 20/31] [FIX] UpdatesProvider register --- .../pro/gravit/launchserver/auth/updates/UpdatesProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java index 832f729c..f7677ea8 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/auth/updates/UpdatesProvider.java @@ -17,6 +17,7 @@ public abstract class UpdatesProvider { public static void registerProviders() { if (!registredProviders) { + providers.register("local", LocalUpdatesProvider.class); registredProviders = true; } } From c43edeb9829893aabf089e69fdd0b5c3191c84a8 Mon Sep 17 00:00:00 2001 From: Antoni Date: Tue, 6 Aug 2024 03:25:02 +0300 Subject: [PATCH 21/31] [FIX] UpdatesProvider register --- .../main/java/pro/gravit/launchserver/LaunchServerStarter.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java index ac26c218..3db4c2be 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/LaunchServerStarter.java @@ -16,6 +16,7 @@ import pro.gravit.launchserver.auth.profiles.ProfileProvider; import pro.gravit.launchserver.auth.protect.ProtectHandler; import pro.gravit.launchserver.auth.texture.TextureProvider; +import pro.gravit.launchserver.auth.updates.UpdatesProvider; import pro.gravit.launchserver.components.Component; import pro.gravit.launchserver.config.LaunchServerConfig; import pro.gravit.launchserver.config.LaunchServerRuntimeConfig; @@ -180,6 +181,7 @@ public static void registerAll() { OptionalTrigger.registerProviders(); MixProvider.registerProviders(); ProfileProvider.registerProviders(); + UpdatesProvider.registerProviders(); } private static void printExperimentalBranch() { From b3349044b51c6496a66f4ec6ba5208459feeb18c Mon Sep 17 00:00:00 2001 From: Antoni Date: Wed, 7 Aug 2024 01:27:18 +0300 Subject: [PATCH 22/31] [ANY] Update patch Version and Type release --- LauncherCore/src/main/java/pro/gravit/utils/Version.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LauncherCore/src/main/java/pro/gravit/utils/Version.java b/LauncherCore/src/main/java/pro/gravit/utils/Version.java index 8201c010..64bbe4bd 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/Version.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/Version.java @@ -6,9 +6,9 @@ public final class Version implements Comparable { public static final int MAJOR = 5; public static final int MINOR = 6; - public static final int PATCH = 5; + public static final int PATCH = 6; public static final int BUILD = 1; - public static final Version.Type RELEASE = Type.STABLE; + public static final Version.Type RELEASE = Type.DEV; public final int major; public final int minor; public final int patch; From 27ebadcd1914805419a384b8b9d9a320c5743602 Mon Sep 17 00:00:00 2001 From: microwin7 Date: Mon, 12 Aug 2024 02:00:49 +0300 Subject: [PATCH 23/31] [ANY] Update modules --- modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules b/modules index f6158556..c34aa949 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit f615855642ebcb69c5bc98c918782b65ca785a74 +Subproject commit c34aa94997b0a60bbc8526143b7bba07d37af56a From 31cbfe29199d84dcb8492e77748add6665b959e7 Mon Sep 17 00:00:00 2001 From: microwin7 Date: Mon, 12 Aug 2024 06:01:08 +0300 Subject: [PATCH 24/31] [ANY][FEATURE] Update modules. Removed mainClass for Cleanroom In MakeProfileHelper --- .../java/pro/gravit/launchserver/helper/MakeProfileHelper.java | 3 --- modules | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/MakeProfileHelper.java b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/MakeProfileHelper.java index 5b139d12..5b375301 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/MakeProfileHelper.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/MakeProfileHelper.java @@ -197,9 +197,6 @@ public static String getMainClassByVersion(ClientProfile.Version version, MakePr if(version.compareTo(ClientProfileVersions.MINECRAFT_1_7_10) == 0) { return "com.gtnewhorizons.retrofuturabootstrap.Main"; } - if(version.compareTo(ClientProfileVersions.MINECRAFT_1_12_2) == 0) { - return "top.outlands.foundation.boot.Foundation"; // Cleanroom - } if (findOption(options, MakeProfileOptionLaunchWrapper.class).isPresent()) { return "net.minecraft.launchwrapper.Launch"; } diff --git a/modules b/modules index c34aa949..b0b57683 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit c34aa94997b0a60bbc8526143b7bba07d37af56a +Subproject commit b0b576830b0ecf2e375128b05aaab2fba73ad4ce From 9a69426547eda1d0b1358338fdfac690d6881c7c Mon Sep 17 00:00:00 2001 From: microwin7 Date: Mon, 12 Aug 2024 07:03:17 +0300 Subject: [PATCH 25/31] [ANY] Update modules --- modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules b/modules index b0b57683..40601b50 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit b0b576830b0ecf2e375128b05aaab2fba73ad4ce +Subproject commit 40601b5062a50a74263b79224038233b5d205254 From 1119625d12f897a0d0e80ac160022a052e5bfe3b Mon Sep 17 00:00:00 2001 From: microwin7 Date: Tue, 13 Aug 2024 05:44:32 +0300 Subject: [PATCH 26/31] [ANY] Update modules --- modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules b/modules index 40601b50..3ab73b0b 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit 40601b5062a50a74263b79224038233b5d205254 +Subproject commit 3ab73b0b40f8b647ba7c61598a76fa8239f76530 From 8509cbb6b54bcee6b67748fb22460b3a224662de Mon Sep 17 00:00:00 2001 From: microwin7 Date: Wed, 14 Aug 2024 00:13:45 +0300 Subject: [PATCH 27/31] [ANY] Update modules --- modules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules b/modules index 3ab73b0b..fd0bbc04 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit 3ab73b0b40f8b647ba7c61598a76fa8239f76530 +Subproject commit fd0bbc04d1bcc2af9b0c86569166f491c266693b From 981f2ac3dd9981ab74d0b5e81726034c6fd46996 Mon Sep 17 00:00:00 2001 From: microwin7 Date: Sun, 18 Aug 2024 01:00:08 +0300 Subject: [PATCH 28/31] [ANY] Update modules and update version oshi --- modules | 2 +- props.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules b/modules index fd0bbc04..65f882bd 160000 --- a/modules +++ b/modules @@ -1 +1 @@ -Subproject commit fd0bbc04d1bcc2af9b0c86569166f491c266693b +Subproject commit 65f882bd90623aa1581ad24cfa4f52563ea95bc0 diff --git a/props.gradle b/props.gradle index af811c06..8c8498c3 100644 --- a/props.gradle +++ b/props.gradle @@ -1,7 +1,7 @@ project.ext { verAsm = '9.7' verNetty = '4.1.111.Final' - verOshiCore = '6.6.1' + verOshiCore = '6.6.2' verJunit = '5.10.2' verJansi = '2.4.1' verJline = '3.26.1' From 46f1f7b69e139aadbcefa9e1a33d868447e120d5 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Sun, 18 Aug 2024 19:18:53 +0700 Subject: [PATCH 29/31] [FIX] Symlink in launcher-pack --- .../gravit/launchserver/binary/tasks/PrepareBuildTask.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/PrepareBuildTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/PrepareBuildTask.java index e509edf3..753f48c5 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/PrepareBuildTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/PrepareBuildTask.java @@ -7,10 +7,7 @@ import pro.gravit.utils.helper.UnpackHelper; import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; +import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.List; import java.util.stream.Collectors; @@ -40,7 +37,7 @@ public Path process(Path inputFile) throws IOException { if(Files.isDirectory(server.launcherLibrariesCompile)) { IOHelper.walk(server.launcherLibrariesCompile, new ListFileVisitor(server.launcherBinary.addonLibs), false); } - try(Stream stream = Files.walk(server.launcherPack).filter((e) -> { + try(Stream stream = Files.walk(server.launcherPack, FileVisitOption.FOLLOW_LINKS).filter((e) -> { try { return !Files.isDirectory(e) && !Files.isHidden(e); } catch (IOException ex) { From 3e654f4d79213d3d5c6d2a1c59c10c92d2d91bf5 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Sun, 18 Aug 2024 23:10:58 +0700 Subject: [PATCH 30/31] [FEATURE] Add support opens, exports, reads to SYSTEM_CLASS_LOADER. Remove AGENT --- Launcher/build.gradle | 2 - .../launcher/runtime/LauncherEngine.java | 1 - .../runtime/client/ClientLauncherProcess.java | 22 ++++++- .../launcher/base/profiles/ClientProfile.java | 2 +- LauncherClient/build.gradle | 4 +- .../client/ClientLauncherEntryPoint.java | 18 ++---- .../gravit/launcher/client/LauncherAgent.java | 59 ------------------- 7 files changed, 25 insertions(+), 83 deletions(-) delete mode 100644 LauncherClient/src/main/java/pro/gravit/launcher/client/LauncherAgent.java diff --git a/Launcher/build.gradle b/Launcher/build.gradle index a2253345..42ed13a7 100644 --- a/Launcher/build.gradle +++ b/Launcher/build.gradle @@ -1,7 +1,6 @@ apply plugin: 'com.github.johnrengelman.shadow' String mainClassName = "pro.gravit.launcher.start.ClientLauncherWrapper" -String mainAgentName = "pro.gravit.launcher.runtime.LauncherAgent" repositories { maven { @@ -20,7 +19,6 @@ jar { archiveClassifier.set('clean') manifest.attributes("Main-Class": mainClassName, - "Premain-Class": mainAgentName, "Multi-Release": "true", "Automatic-Module-Name": "GravitLauncher") } diff --git a/Launcher/src/main/java/pro/gravit/launcher/runtime/LauncherEngine.java b/Launcher/src/main/java/pro/gravit/launcher/runtime/LauncherEngine.java index 8de18308..df1e873b 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/runtime/LauncherEngine.java +++ b/Launcher/src/main/java/pro/gravit/launcher/runtime/LauncherEngine.java @@ -124,7 +124,6 @@ public static void main(String... args) throws Throwable { LogHelper.printLicense("Launcher"); LauncherEngine.checkClass(LauncherEngineWrapper.class); LauncherEngine.checkClass(LauncherEngine.class); - LauncherEngine.checkClass(LauncherAgent.class); LauncherEngine.checkClass(ClientLauncherEntryPoint.class); LauncherEngine.modulesManager = new RuntimeModuleManager(); LauncherEngine.modulesManager.loadModule(new RuntimeLauncherCoreModule()); diff --git a/Launcher/src/main/java/pro/gravit/launcher/runtime/client/ClientLauncherProcess.java b/Launcher/src/main/java/pro/gravit/launcher/runtime/client/ClientLauncherProcess.java index 22b1b843..dc1b5bcd 100644 --- a/Launcher/src/main/java/pro/gravit/launcher/runtime/client/ClientLauncherProcess.java +++ b/Launcher/src/main/java/pro/gravit/launcher/runtime/client/ClientLauncherProcess.java @@ -142,9 +142,7 @@ public void start(boolean pipeOutput) throws IOException, InterruptedException { } //ADD CLASSPATH processArgs.add(JVMHelper.jvmProperty("java.library.path", this.params.nativesDir)); - if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.AGENT) { - processArgs.add("-javaagent:".concat(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString())); - } else if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) { + if (params.profile.getClassLoaderConfig() == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) { Set ignorePath = new HashSet<>(); var moduleConf = params.profile.getModuleConf(); if(moduleConf != null) { @@ -159,6 +157,24 @@ public void start(boolean pipeOutput) throws IOException, InterruptedException { processArgs.add("--add-modules"); processArgs.add(String.join(",", moduleConf.modules)); } + if(moduleConf.exports != null && !moduleConf.exports.isEmpty()) { + for(var e : moduleConf.exports.entrySet()) { + processArgs.add("--add-exports"); + processArgs.add(String.format("%s=%s", e.getKey(), e.getValue())); + } + } + if(moduleConf.opens != null && !moduleConf.opens.isEmpty()) { + for(var e : moduleConf.opens.entrySet()) { + processArgs.add("--add-opens"); + processArgs.add(String.format("%s=%s", e.getKey(), e.getValue())); + } + } + if(moduleConf.reads != null && !moduleConf.reads.isEmpty()) { + for(var e : moduleConf.reads.entrySet()) { + processArgs.add("--add-reads"); + processArgs.add(String.format("%s=%s", e.getKey(), e.getValue())); + } + } } systemClassPath.addAll(ClientLauncherEntryPoint.resolveClassPath(ignorePath, workDir, params.actions, params.profile) .map(Path::toString) diff --git a/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java b/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java index 0e4bab59..74390d36 100644 --- a/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java +++ b/LauncherAPI/src/main/java/pro/gravit/launcher/base/profiles/ClientProfile.java @@ -392,7 +392,7 @@ public List getFlags() { } public enum ClassLoaderConfig { - AGENT, LAUNCHER, MODULE, SYSTEM_ARGS + LAUNCHER, MODULE, SYSTEM_ARGS } public enum CompatibilityFlags { diff --git a/LauncherClient/build.gradle b/LauncherClient/build.gradle index 9a59ce29..78ad4310 100644 --- a/LauncherClient/build.gradle +++ b/LauncherClient/build.gradle @@ -1,7 +1,6 @@ apply plugin: 'org.openjfx.javafxplugin' -String mainClassName = "pro.gravit.launcher.ClientLauncherWrapper" -String mainAgentName = "pro.gravit.launcher.LauncherAgent" +String mainClassName = "pro.gravit.launcher.start.ClientLauncherWrapper" repositories { maven { @@ -14,7 +13,6 @@ jar { archiveClassifier.set('clean') manifest.attributes("Main-Class": mainClassName, - "Premain-Class": mainAgentName, "Multi-Release": "true") } diff --git a/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java index d084f9d5..f767206f 100644 --- a/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java +++ b/LauncherClient/src/main/java/pro/gravit/launcher/client/ClientLauncherEntryPoint.java @@ -86,9 +86,7 @@ private static void realMain(String[] args) throws Throwable { modulesManager.invokeEvent(new PreConfigPhase()); LogHelper.debug("Reading ClientLauncher params"); ClientParams params = readParams(new InetSocketAddress("127.0.0.1", Launcher.getConfig().clientPort)); - if (params.profile.getClassLoaderConfig() != ClientProfile.ClassLoaderConfig.AGENT) { - ClientLauncherMethods.verifyNoAgent(); - } + ClientLauncherMethods.verifyNoAgent(); if(params.timestamp > System.currentTimeMillis() || params.timestamp + 30*1000 < System.currentTimeMillis() ) { LogHelper.error("Timestamp failed. Exit"); ClientLauncherMethods.exitLauncher(-662); @@ -160,7 +158,7 @@ private static void realMain(String[] args) throws Throwable { System.load(Paths.get(params.nativesDir).resolve(ClientService.findLibrary(e)).toAbsolutePath().toString()); } } - if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER) { + if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER || classLoaderConfig == ClientProfile.ClassLoaderConfig.MODULE) { if(JVMHelper.JVM_VERSION <= 11) { launch = new LegacyLaunch(); } else { @@ -170,20 +168,12 @@ private static void realMain(String[] args) throws Throwable { System.setProperty("java.class.path", classpath.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator))); modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(launch, classLoaderControl, profile)); ClientService.baseURLs = classLoaderControl.getURLs(); - } else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.AGENT) { - launch = new BasicLaunch(LauncherAgent.inst); - classpathURLs.add(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toUri().toURL()); - classLoaderControl = launch.init(classpath, params.nativesDir, options); - for (URL url : classpathURLs) { - LauncherAgent.addJVMClassPath(Paths.get(url.toURI())); - } - ClientService.instrumentation = LauncherAgent.inst; - 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]); + } else { + throw new UnsupportedOperationException(String.format("Unknown classLoaderConfig %s", classLoaderConfig)); } if(profile.hasFlag(ClientProfile.CompatibilityFlags.CLASS_CONTROL_API)) { ClientService.classLoaderControl = classLoaderControl; diff --git a/LauncherClient/src/main/java/pro/gravit/launcher/client/LauncherAgent.java b/LauncherClient/src/main/java/pro/gravit/launcher/client/LauncherAgent.java deleted file mode 100644 index 0683af97..00000000 --- a/LauncherClient/src/main/java/pro/gravit/launcher/client/LauncherAgent.java +++ /dev/null @@ -1,59 +0,0 @@ -package pro.gravit.launcher.client; - -import pro.gravit.launcher.client.utils.NativeJVMHalt; -import pro.gravit.utils.helper.LogHelper; - -import java.io.File; -import java.io.IOException; -import java.lang.instrument.Instrumentation; -import java.nio.file.Path; -import java.util.jar.JarFile; - - -public final class LauncherAgent { - public static Instrumentation inst; - private static boolean isAgentStarted = false; - - public static void addJVMClassPath(String path) throws IOException { - LogHelper.debug("Launcher Agent addJVMClassPath"); - inst.appendToSystemClassLoaderSearch(new JarFile(new File(path))); - } - - public static void addJVMClassPath(Path path) throws IOException { - LogHelper.debug("Launcher Agent addJVMClassPath"); - inst.appendToSystemClassLoaderSearch(new JarFile(path.toFile())); - } - - public static void premain(String agentArgument, Instrumentation instrumentation) { - System.out.println("Launcher Agent"); - checkAgentStacktrace(); - inst = instrumentation; - NativeJVMHalt.initFunc(); - isAgentStarted = true; - } - - public static void checkAgentStacktrace() { - RuntimeException ex = new SecurityException("Error check agent stacktrace"); - boolean isFoundNative = false; - boolean foundPreMain = false; - for (StackTraceElement e : ex.getStackTrace()) { - if (e.isNativeMethod()) { - if (!isFoundNative) isFoundNative = true; - else throw ex; - } - if (e.getMethodName().equals("premain")) { - if (!foundPreMain) foundPreMain = true; - else throw ex; - } - } - if (!isFoundNative || !foundPreMain) throw ex; - } - - public static boolean isStarted() { - return isAgentStarted; - } - - public boolean isAgentStarted() { - return isAgentStarted; - } -} From b85075c55968a1112cc6f089d60e9759d410f9f8 Mon Sep 17 00:00:00 2001 From: Gravita <12893402+gravit0@users.noreply.github.com> Date: Sun, 18 Aug 2024 23:57:00 +0700 Subject: [PATCH 31/31] [ANY] 5.6.6 Stable --- LauncherCore/src/main/java/pro/gravit/utils/Version.java | 2 +- build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LauncherCore/src/main/java/pro/gravit/utils/Version.java b/LauncherCore/src/main/java/pro/gravit/utils/Version.java index 64bbe4bd..aac03549 100644 --- a/LauncherCore/src/main/java/pro/gravit/utils/Version.java +++ b/LauncherCore/src/main/java/pro/gravit/utils/Version.java @@ -8,7 +8,7 @@ public final class Version implements Comparable { public static final int MINOR = 6; public static final int PATCH = 6; public static final int BUILD = 1; - public static final Version.Type RELEASE = Type.DEV; + public static final Version.Type RELEASE = Type.STABLE; public final int major; public final int minor; public final int patch; diff --git a/build.gradle b/build.gradle index 473b0c47..4f30a8a7 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ id 'org.openjfx.javafxplugin' version '0.1.0' apply false } group = 'pro.gravit.launcher' -version = '5.6.5' +version = '5.6.6' apply from: 'props.gradle'