mirror of
https://github.com/xHyroM/lighteco.git
synced 2024-11-21 22:41:06 +01:00
feat: make jar even more small, dependency relocation
This commit is contained in:
parent
3802dba410
commit
1ae9a2e5bc
11 changed files with 224 additions and 36 deletions
|
@ -37,5 +37,8 @@ tasks.shadowJar {
|
|||
|
||||
relocate("org.yaml.snakeyaml", "dev.xhyrom.lighteco.libraries.org.yaml.snakeyaml")
|
||||
|
||||
relocate("com.zaxxer.hikari", "dev.xhyrom.lighteco.libraries.com.zaxxer.hikari")
|
||||
relocate("org.mariadb.jdbc", "dev.xhyrom.lighteco.libraries.mariadb")
|
||||
relocate("com.mysql", "dev.xhyrom.lighteco.libraries.mysql")
|
||||
relocate("org.postgresql", "dev.xhyrom.lighteco.libraries.postgresql")
|
||||
relocate("com.zaxxer.hikari", "dev.xhyrom.lighteco.libraries.hikari")
|
||||
}
|
|
@ -52,7 +52,7 @@ public class BukkitLightEcoPlugin extends AbstractLightEcoPlugin {
|
|||
|
||||
@Override
|
||||
protected void registerPlatformHooks() {
|
||||
Hooks.register();
|
||||
Hooks.register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,18 +2,28 @@ package dev.xhyrom.lighteco.bukkit;
|
|||
|
||||
import dev.xhyrom.lighteco.common.plugin.scheduler.SchedulerAdapter;
|
||||
import dev.xhyrom.lighteco.common.plugin.scheduler.SchedulerTask;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BukkitSchedulerAdapter implements SchedulerAdapter {
|
||||
private final Executor async;
|
||||
|
||||
private final BukkitLightEcoBootstrap bootstrap;
|
||||
private final BukkitScheduler scheduler;
|
||||
|
||||
public BukkitSchedulerAdapter(BukkitLightEcoBootstrap bootstrap) {
|
||||
this.bootstrap = bootstrap;
|
||||
this.scheduler = bootstrap.getServer().getScheduler();
|
||||
|
||||
this.async = runnable -> this.scheduler.runTaskAsynchronously(this.bootstrap.getLoader(), runnable);
|
||||
}
|
||||
|
||||
public Executor async() {
|
||||
return this.async;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
package dev.xhyrom.lighteco.bukkit.hooks;
|
||||
|
||||
import dev.xhyrom.lighteco.bukkit.BukkitLightEcoPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class Hooks {
|
||||
private static PlaceholderAPIExpansion placeholderAPIExpansion;
|
||||
|
||||
public static void register() {
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null)
|
||||
public static void register(BukkitLightEcoPlugin plugin) {
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
||||
placeholderAPIExpansion = new PlaceholderAPIExpansion(plugin);
|
||||
placeholderAPIExpansion.register();
|
||||
}
|
||||
}
|
||||
|
||||
public static void unregister() {
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null)
|
||||
|
|
|
@ -9,13 +9,16 @@ dependencies {
|
|||
exclude(module = "checker-qual")
|
||||
exclude(module = "annotations")
|
||||
}
|
||||
api("net.kyori:adventure-text-minimessage:4.14.0")
|
||||
api("net.kyori:adventure-text-minimessage:4.14.0") {
|
||||
exclude(module = "adventure-bom")
|
||||
exclude(module = "adventure-api")
|
||||
}
|
||||
api("com.google.guava:guava:32.1.2-jre")
|
||||
|
||||
implementation("eu.okaeri:okaeri-configs-yaml-snakeyaml:5.0.0-beta.5")
|
||||
implementation("eu.okaeri:okaeri-configs-validator-okaeri:5.0.0-beta.5")
|
||||
|
||||
implementation("com.zaxxer:HikariCP:5.0.1")
|
||||
compileOnly("com.zaxxer:HikariCP:5.0.1")
|
||||
|
||||
compileOnly("org.projectlombok:lombok:1.18.28")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.28")
|
||||
|
|
|
@ -1,9 +1,39 @@
|
|||
package dev.xhyrom.lighteco.common.dependencies;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import dev.xhyrom.lighteco.common.dependencies.relocation.Relocation;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public enum Dependency {
|
||||
/**
|
||||
* Somewhere we use brackets instad of dots, so we need to rewrite them
|
||||
* This is because gradle's shadow plugin relocates using replacing full paths (dots)
|
||||
*/
|
||||
|
||||
ASM(
|
||||
"org.ow2.asm",
|
||||
"asm",
|
||||
"9.1"
|
||||
),
|
||||
ASM_COMMONS(
|
||||
"org.ow2.asm",
|
||||
"asm-commons",
|
||||
"9.1"
|
||||
),
|
||||
JAR_RELOCATOR(
|
||||
"me.lucko",
|
||||
"jar-relocator",
|
||||
"1.7"
|
||||
),
|
||||
HIKARI(
|
||||
"com{}zaxxer",
|
||||
"HikariCP",
|
||||
"5.0.1",
|
||||
Relocation.of("hikari", "com{}zaxxer{}hikari")
|
||||
),
|
||||
H2_DRIVER(
|
||||
"com.h2database",
|
||||
"h2",
|
||||
|
@ -15,41 +45,60 @@ public enum Dependency {
|
|||
"3.28.0"
|
||||
),
|
||||
MARIADB_DRIVER(
|
||||
"org.mariadb.jdbc",
|
||||
"org{}mariadb{}jdbc",
|
||||
"mariadb-java-client",
|
||||
"3.1.3"
|
||||
"3.1.3",
|
||||
Relocation.of("mariadb", "org{}mariadb{}jdbc")
|
||||
),
|
||||
MYSQL_DRIVER(
|
||||
"mysql",
|
||||
"mysql-connector-java",
|
||||
"8.0.23"
|
||||
"8.0.23",
|
||||
Relocation.of("mysql", "com{}mysql")
|
||||
),
|
||||
POSTGRESQL_DRIVER(
|
||||
"org.postgresql",
|
||||
"org{}postgresql",
|
||||
"postgresql",
|
||||
"42.6.0"
|
||||
"42.6.0",
|
||||
Relocation.of("postgresql", "org{}postgresql")
|
||||
);
|
||||
|
||||
private final String fullPath;
|
||||
private final String version;
|
||||
@Getter
|
||||
private final List<Relocation> relocations;
|
||||
|
||||
private static final String MAVEN_FORMAT = "%s/%s/%s/%s-%s.jar";
|
||||
|
||||
Dependency(String groupId, String artifactId, String version) {
|
||||
this(groupId, artifactId, version, new Relocation[0]);
|
||||
}
|
||||
|
||||
Dependency(String groupId, String artifactId, String version, Relocation... relocations) {
|
||||
this.fullPath = String.format(MAVEN_FORMAT,
|
||||
groupId.replace('.', '/'),
|
||||
artifactId,
|
||||
rewriteEscape(groupId).replace('.', '/'),
|
||||
rewriteEscape(artifactId),
|
||||
version,
|
||||
artifactId,
|
||||
rewriteEscape(artifactId),
|
||||
version
|
||||
);
|
||||
|
||||
this.version = version;
|
||||
this.relocations = ImmutableList.copyOf(relocations);
|
||||
}
|
||||
|
||||
private static String rewriteEscape(String path) {
|
||||
return path.replace("{}", ".");
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
String name = name().toLowerCase().replace('_', '-');
|
||||
return getFileName(null);
|
||||
}
|
||||
|
||||
return String.format("%s-%s.jar", name, this.version);
|
||||
public String getFileName(String classifier) {
|
||||
String name = name().toLowerCase().replace('_', '-');
|
||||
String extra = classifier == null ? "" : "-" + classifier;
|
||||
|
||||
return String.format("%s-%s.jar", name, this.version + extra);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,22 +2,23 @@ package dev.xhyrom.lighteco.common.dependencies;
|
|||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.io.MoreFiles;
|
||||
import dev.xhyrom.lighteco.common.dependencies.relocation.Relocation;
|
||||
import dev.xhyrom.lighteco.common.dependencies.relocation.RelocationHandler;
|
||||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||
import dev.xhyrom.lighteco.common.plugin.logger.PluginLogger;
|
||||
import dev.xhyrom.lighteco.common.util.URLClassLoaderAccess;
|
||||
import dev.xhyrom.lighteco.common.storage.StorageType;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class DependencyManagerImpl implements DependencyManager {
|
||||
private final EnumMap<Dependency, Path> loaded = new EnumMap<>(Dependency.class);
|
||||
|
@ -27,6 +28,7 @@ public class DependencyManagerImpl implements DependencyManager {
|
|||
private final DependencyRegistry registry;
|
||||
private final Path cacheDirectory;
|
||||
private final URLClassLoaderAccess classLoader;
|
||||
private @MonotonicNonNull RelocationHandler relocationHandler;
|
||||
|
||||
public DependencyManagerImpl(LightEcoPlugin plugin) {
|
||||
this.logger = plugin.getBootstrap().getLogger();
|
||||
|
@ -35,9 +37,18 @@ public class DependencyManagerImpl implements DependencyManager {
|
|||
this.classLoader = URLClassLoaderAccess.create((URLClassLoader) plugin.getBootstrap().getClass().getClassLoader());
|
||||
}
|
||||
|
||||
private synchronized RelocationHandler getRelocationHandler() {
|
||||
if (this.relocationHandler == null) {
|
||||
this.relocationHandler = new RelocationHandler(this);
|
||||
}
|
||||
|
||||
return this.relocationHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadDependencies(Set<Dependency> dependencies) {
|
||||
CountDownLatch latch = new CountDownLatch(dependencies.size());
|
||||
this.logger.info("Loading dependencies: " + dependencies);
|
||||
|
||||
for (Dependency dependency : dependencies) {
|
||||
if (this.loaded.containsKey(dependency)) {
|
||||
|
@ -46,18 +57,22 @@ public class DependencyManagerImpl implements DependencyManager {
|
|||
}
|
||||
|
||||
CompletableFuture.runAsync(() -> {
|
||||
System.out.println("Loading dependency " + dependency);
|
||||
try {
|
||||
loadDependency(dependency);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to load dependency " + dependency, e);
|
||||
} finally {
|
||||
latch.countDown();
|
||||
System.out.println("Loaded dependency " + dependency);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
latch.await();
|
||||
|
||||
this.logger.info("Loaded dependencies: " + dependencies);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -68,7 +83,7 @@ public class DependencyManagerImpl implements DependencyManager {
|
|||
return;
|
||||
}
|
||||
|
||||
Path file = downloadDependency(dependency);
|
||||
Path file = remapDependency(dependency, downloadDependency(dependency));
|
||||
|
||||
this.loaded.put(dependency, file);
|
||||
|
||||
|
@ -95,6 +110,24 @@ public class DependencyManagerImpl implements DependencyManager {
|
|||
return file;
|
||||
}
|
||||
|
||||
private Path remapDependency(Dependency dependency, Path normalFile) throws Exception {
|
||||
List<Relocation> rules = new ArrayList<>(dependency.getRelocations());
|
||||
|
||||
if (rules.isEmpty()) {
|
||||
return normalFile;
|
||||
}
|
||||
|
||||
Path remappedFile = this.cacheDirectory.resolve(dependency.getFileName("remapped"));
|
||||
|
||||
// if the remapped source exists already, just use that.
|
||||
if (Files.exists(remappedFile)) {
|
||||
return remappedFile;
|
||||
}
|
||||
|
||||
this.getRelocationHandler().remap(normalFile, remappedFile, rules);
|
||||
return remappedFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadStorageDependencies(Set<StorageType> types) {
|
||||
loadDependencies(this.registry.resolveStorageDependencies(types));
|
||||
|
|
|
@ -11,9 +11,9 @@ public class DependencyRegistry {
|
|||
private static final SetMultimap<StorageType, Dependency> STORAGE_DEPENDENCIES = ImmutableSetMultimap.<StorageType, Dependency>builder()
|
||||
.putAll(StorageType.SQLITE, Dependency.SQLITE_DRIVER)
|
||||
.putAll(StorageType.H2, Dependency.H2_DRIVER)
|
||||
.putAll(StorageType.MYSQL, Dependency.MYSQL_DRIVER)
|
||||
.putAll(StorageType.MARIADB, Dependency.MARIADB_DRIVER)
|
||||
.putAll(StorageType.POSTGRESQL, Dependency.POSTGRESQL_DRIVER)
|
||||
.putAll(StorageType.MYSQL, Dependency.MYSQL_DRIVER, Dependency.HIKARI)
|
||||
.putAll(StorageType.MARIADB, Dependency.MARIADB_DRIVER, Dependency.HIKARI)
|
||||
.putAll(StorageType.POSTGRESQL, Dependency.POSTGRESQL_DRIVER, Dependency.HIKARI)
|
||||
.build();
|
||||
|
||||
public Set<Dependency> resolveStorageDependencies(Set<StorageType> types) {
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package dev.xhyrom.lighteco.common.dependencies.relocation;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class Relocation {
|
||||
private static final String RELOCATION_PREFIX = "dev.xhyrom.lighteco.libraries.";
|
||||
|
||||
public static Relocation of(String id, String pattern) {
|
||||
return new Relocation(pattern.replace("{}", "."), RELOCATION_PREFIX + id);
|
||||
}
|
||||
|
||||
private final String pattern;
|
||||
private final String relocatedPattern;
|
||||
|
||||
private Relocation(String pattern, String relocatedPattern) {
|
||||
this.pattern = pattern;
|
||||
this.relocatedPattern = relocatedPattern;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package dev.xhyrom.lighteco.common.dependencies.relocation;
|
||||
|
||||
import dev.xhyrom.lighteco.common.dependencies.Dependency;
|
||||
import dev.xhyrom.lighteco.common.dependencies.DependencyManager;
|
||||
import dev.xhyrom.lighteco.common.dependencies.IsolatedClassLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public class RelocationHandler {
|
||||
public static final Set<Dependency> DEPENDENCIES = EnumSet.of(Dependency.ASM, Dependency.ASM_COMMONS, Dependency.JAR_RELOCATOR);
|
||||
private static final String JAR_RELOCATOR_CLASS = "me.lucko.jarrelocator.JarRelocator";
|
||||
private static final String JAR_RELOCATOR_RUN_METHOD = "run";
|
||||
|
||||
private final Constructor<?> jarRelocatorConstructor;
|
||||
private final Method jarRelocatorRunMethod;
|
||||
|
||||
public RelocationHandler(DependencyManager dependencyManager) {
|
||||
ClassLoader classLoader = null;
|
||||
try {
|
||||
// download the required dependencies for remapping
|
||||
dependencyManager.loadDependencies(DEPENDENCIES);
|
||||
// get a classloader containing the required dependencies as sources
|
||||
classLoader = dependencyManager.obtainClassLoaderWith(DEPENDENCIES);
|
||||
|
||||
// load the relocator class
|
||||
Class<?> jarRelocatorClass = classLoader.loadClass(JAR_RELOCATOR_CLASS);
|
||||
|
||||
// prepare the reflected constructor & method instances
|
||||
this.jarRelocatorConstructor = jarRelocatorClass.getDeclaredConstructor(File.class, File.class, Map.class);
|
||||
this.jarRelocatorConstructor.setAccessible(true);
|
||||
|
||||
this.jarRelocatorRunMethod = jarRelocatorClass.getDeclaredMethod(JAR_RELOCATOR_RUN_METHOD);
|
||||
this.jarRelocatorRunMethod.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
if (classLoader instanceof IsolatedClassLoader) {
|
||||
((IsolatedClassLoader) classLoader).close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
e.addSuppressed(ex);
|
||||
}
|
||||
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void remap(Path input, Path output, List<Relocation> relocations) throws Exception {
|
||||
Map<String, String> mappings = new HashMap<>();
|
||||
for (Relocation relocation : relocations) {
|
||||
mappings.put(relocation.getPattern(), relocation.getRelocatedPattern());
|
||||
}
|
||||
|
||||
// create and invoke a new relocator
|
||||
Object relocator = this.jarRelocatorConstructor.newInstance(input.toFile(), output.toFile(), mappings);
|
||||
this.jarRelocatorRunMethod.invoke(relocator);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +1,11 @@
|
|||
package dev.xhyrom.lighteco.common.plugin.scheduler;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public interface SchedulerAdapter {
|
||||
Executor async();
|
||||
|
||||
SchedulerTask asyncLater(Runnable runnable, long delay, TimeUnit unit);
|
||||
|
||||
SchedulerTask asyncRepeating(Runnable runnable, long interval, TimeUnit unit);
|
||||
|
|
Loading…
Reference in a new issue