mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-01-09 00:59:44 +03:00
[FEATURE] Перенос LauncherModuleLoader в LaunchServer. Поддержка конфигов с субклассами.
This commit is contained in:
parent
aa49c60fef
commit
f94766679c
5 changed files with 204 additions and 4 deletions
|
@ -13,6 +13,7 @@
|
|||
import pro.gravit.launchserver.binary.*;
|
||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||
import pro.gravit.launchserver.launchermodules.LauncherModuleLoader;
|
||||
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||
import pro.gravit.launchserver.manangers.MirrorManager;
|
||||
import pro.gravit.launchserver.manangers.ReconfigurableManager;
|
||||
|
@ -88,7 +89,8 @@ public final class LaunchServer implements Runnable, AutoCloseable, Reconfigurab
|
|||
public final CommandHandler commandHandler;
|
||||
public final NettyServerSocketHandler nettyServerSocketHandler;
|
||||
public final Timer taskPool;
|
||||
private final AtomicBoolean started = new AtomicBoolean(false);
|
||||
public final AtomicBoolean started = new AtomicBoolean(false);
|
||||
public final LauncherModuleLoader launcherModuleLoader;
|
||||
public LaunchServerConfig config;
|
||||
public volatile Map<String, HashedDir> updatesDirMap;
|
||||
// Updates and profiles
|
||||
|
@ -198,7 +200,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
|||
launcherBinary.init();
|
||||
launcherEXEBinary.init();
|
||||
syncLauncherBinaries();
|
||||
|
||||
launcherModuleLoader = new LauncherModuleLoader(this);
|
||||
// Sync updates dir
|
||||
if (!IOHelper.isDir(updatesDir))
|
||||
Files.createDirectory(updatesDir);
|
||||
|
@ -208,7 +210,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
|||
if (!IOHelper.isDir(profilesDir))
|
||||
Files.createDirectory(profilesDir);
|
||||
syncProfilesDir();
|
||||
|
||||
launcherModuleLoader.init();
|
||||
nettyServerSocketHandler = new NettyServerSocketHandler(this);
|
||||
// post init modules
|
||||
modulesManager.invokeEvent(new LaunchServerPostInitPhase(this));
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package pro.gravit.launchserver.launchermodules;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
public class LauncherModuleClassLoader extends URLClassLoader {
|
||||
public LauncherModuleClassLoader(ClassLoader parent) {
|
||||
super(new URL[0], parent);
|
||||
}
|
||||
|
||||
public void addURL(URL u) {
|
||||
super.addURL(u);
|
||||
}
|
||||
|
||||
public Class<?> rawDefineClass(String name, byte[] bytes) {
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
package pro.gravit.launchserver.launchermodules;
|
||||
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.modules.LauncherInitContext;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.binary.tasks.MainBuildTask;
|
||||
import pro.gravit.launchserver.modules.events.LaunchServerInitPhase;
|
||||
import pro.gravit.launchserver.modules.events.LaunchServerPostInitPhase;
|
||||
import pro.gravit.utils.Version;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.JarHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
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.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public class LauncherModuleLoader {
|
||||
public final List<ModuleEntity> launcherModules = new ArrayList<>();
|
||||
public Path modules_dir;
|
||||
private transient LaunchServer server;
|
||||
|
||||
public LauncherModuleLoader(LaunchServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
modules_dir = server.dir.resolve("launcher-modules");
|
||||
if (!IOHelper.isDir(modules_dir)) {
|
||||
try {
|
||||
Files.createDirectories(modules_dir);
|
||||
} catch (IOException e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
}
|
||||
server.commandHandler.registerCommand("syncLauncherModules", new SyncLauncherModulesCommand(this));
|
||||
MainBuildTask mainTask = server.launcherBinary.getTaskByClass(MainBuildTask.class).get();
|
||||
mainTask.preBuildHook.registerHook((buildContext) -> {
|
||||
for (ModuleEntity e : launcherModules) {
|
||||
if (e.propertyMap != null) buildContext.task.properties.putAll(e.propertyMap);
|
||||
buildContext.clientModules.add(e.moduleMainClass);
|
||||
buildContext.readerClassPath.add(new JarFile(e.path.toFile()));
|
||||
}
|
||||
});
|
||||
mainTask.postBuildHook.registerHook((buildContext) -> {
|
||||
for (ModuleEntity e : launcherModules) {
|
||||
LogHelper.debug("Put %s launcher module", e.path.toString());
|
||||
buildContext.pushJarFile(e.path, (en) -> false, (en) -> true);
|
||||
}
|
||||
});
|
||||
try {
|
||||
syncModules();
|
||||
} catch (IOException e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void syncModules() throws IOException {
|
||||
launcherModules.clear();
|
||||
IOHelper.walk(modules_dir, new ModulesVisitor(), false);
|
||||
}
|
||||
|
||||
static class ModuleEntity {
|
||||
public Path path;
|
||||
public String moduleMainClass;
|
||||
public String moduleConfigClass;
|
||||
public String moduleConfigName;
|
||||
public Map<String, Object> propertyMap;
|
||||
}
|
||||
|
||||
protected final class ModulesVisitor extends SimpleFileVisitor<Path> {
|
||||
private LauncherModuleClassLoader classLoader;
|
||||
|
||||
private ModulesVisitor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (file.toFile().getName().endsWith(".jar"))
|
||||
try (JarFile f = new JarFile(file.toFile())) {
|
||||
Attributes attributes = f.getManifest().getMainAttributes();
|
||||
String mainClass = attributes.getValue("Module-Main-Class");
|
||||
if (mainClass == null) {
|
||||
LogHelper.error("In module %s MainClass not found", file.toString());
|
||||
} else {
|
||||
ModuleEntity entity = new ModuleEntity();
|
||||
entity.path = file;
|
||||
entity.moduleMainClass = mainClass;
|
||||
entity.moduleConfigClass = attributes.getValue("Module-Config-Class");
|
||||
if (entity.moduleConfigClass != null) {
|
||||
entity.moduleConfigName = attributes.getValue("Module-Config-Name");
|
||||
if (entity.moduleConfigName == null) {
|
||||
LogHelper.warning("Module-Config-Name in module %s null. Module not configured", file.toString());
|
||||
} else {
|
||||
try {
|
||||
if (classLoader == null)
|
||||
classLoader = new LauncherModuleClassLoader(server.modulesManager.getModuleClassLoader());
|
||||
classLoader.addURL(file.toUri().toURL());
|
||||
Class<?> clazz = classLoader.loadClass(entity.moduleConfigClass);
|
||||
Path configPath = server.modulesManager.getConfigManager().getModuleConfig(entity.moduleConfigName);
|
||||
Object defaultConfig = MethodHandles.publicLookup().findStatic(clazz, "getDefault", MethodType.methodType(Object.class)).invoke();
|
||||
Object targetConfig;
|
||||
if (!Files.exists(configPath)) {
|
||||
LogHelper.debug("Write default config for module %s to %s", file.toString(), configPath.toString());
|
||||
try (Writer writer = IOHelper.newWriter(configPath)) {
|
||||
Launcher.gsonManager.configGson.toJson(defaultConfig, writer);
|
||||
}
|
||||
targetConfig = defaultConfig;
|
||||
} else {
|
||||
try (Reader reader = IOHelper.newReader(configPath)) {
|
||||
targetConfig = Launcher.gsonManager.configGson.fromJson(reader, clazz);
|
||||
}
|
||||
}
|
||||
Field[] fields = clazz.getFields();
|
||||
for (Field field : fields) {
|
||||
if ((field.getModifiers() & Modifier.STATIC) != 0) continue;
|
||||
Object obj = field.get(targetConfig);
|
||||
String configPropertyName = "modules.".concat(entity.moduleConfigName.toLowerCase()).concat(".").concat(field.getName().toLowerCase());
|
||||
if (entity.propertyMap == null) entity.propertyMap = new HashMap<>();
|
||||
LogHelper.dev("Property name %s", configPropertyName);
|
||||
entity.propertyMap.put(configPropertyName, obj);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
launcherModules.add(entity);
|
||||
}
|
||||
}
|
||||
return super.visitFile(file, attrs);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package pro.gravit.launchserver.launchermodules;
|
||||
|
||||
import pro.gravit.utils.command.Command;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public class SyncLauncherModulesCommand extends Command {
|
||||
private final LauncherModuleLoader mod;
|
||||
|
||||
public SyncLauncherModulesCommand(LauncherModuleLoader mod) {
|
||||
this.mod = mod;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getArgsDescription() {
|
||||
return "Resync launcher modules";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageDescription() {
|
||||
return "[]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(String... args) throws Exception {
|
||||
mod.syncModules();
|
||||
LogHelper.info("Launcher Modules synced");
|
||||
}
|
||||
}
|
2
modules
2
modules
|
@ -1 +1 @@
|
|||
Subproject commit afda996e39ac3ab5d20ec304d011da2a517e6000
|
||||
Subproject commit b3e50712f6a01f6ea4f0d7772371f9c01c309438
|
Loading…
Reference in a new issue