mirror of
https://github.com/xHyroM/lighteco.git
synced 2024-11-22 15:01:05 +01:00
feat: auto dependency download
This commit is contained in:
parent
341bc3eb44
commit
66bb95559c
24 changed files with 461 additions and 46 deletions
|
@ -50,8 +50,8 @@ public class BukkitLightEcoBootstrap implements LightEcoBootstrap, LoaderBootstr
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File getDataFolder() {
|
public Path getDataDirectory() {
|
||||||
return this.loader.getDataFolder();
|
return this.loader.getDataFolder().toPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -10,8 +10,7 @@ dependencies {
|
||||||
exclude(module = "annotations")
|
exclude(module = "annotations")
|
||||||
}
|
}
|
||||||
api("net.kyori:adventure-text-minimessage:4.14.0")
|
api("net.kyori:adventure-text-minimessage:4.14.0")
|
||||||
|
api("com.google.guava:guava:32.1.2-jre")
|
||||||
api("org.xerial:sqlite-jdbc:3.40.0.0")
|
|
||||||
|
|
||||||
implementation("eu.okaeri:okaeri-configs-yaml-snakeyaml:5.0.0-beta.5")
|
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("eu.okaeri:okaeri-configs-validator-okaeri:5.0.0-beta.5")
|
||||||
|
|
|
@ -6,10 +6,11 @@ import eu.okaeri.configs.annotation.Variable;
|
||||||
|
|
||||||
public class StorageConfig extends OkaeriConfig {
|
public class StorageConfig extends OkaeriConfig {
|
||||||
@Comment("Storage provider.")
|
@Comment("Storage provider.")
|
||||||
@Comment("Available providers: memory")
|
@Comment("Available providers: h2, sqlite")
|
||||||
public String provider = "memory";
|
public String provider = "h2";
|
||||||
|
|
||||||
@Comment("Data storage settings.")
|
@Comment("Data storage settings.")
|
||||||
|
@Comment("You don't need to worry about this if you're using local database.")
|
||||||
public StorageDataConfig data = new StorageDataConfig();
|
public StorageDataConfig data = new StorageDataConfig();
|
||||||
|
|
||||||
@Variable("table-prefix")
|
@Variable("table-prefix")
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package dev.xhyrom.lighteco.common.dependencies;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public enum Dependency {
|
||||||
|
H2_DRIVER(
|
||||||
|
"com.h2database",
|
||||||
|
"h2",
|
||||||
|
"2.1.214"
|
||||||
|
),
|
||||||
|
SQLITE_DRIVER(
|
||||||
|
"org.xerial",
|
||||||
|
"sqlite-jdbc",
|
||||||
|
"3.28.0"
|
||||||
|
);
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final String fullPath;
|
||||||
|
private final String groupId;
|
||||||
|
private final String artifactId;
|
||||||
|
private final String version;
|
||||||
|
|
||||||
|
private static final String MAVEN_FORMAT = "%s/%s/%s/%s-%s.jar";
|
||||||
|
|
||||||
|
Dependency(String groupId, String artifactId, String version) {
|
||||||
|
this.fullPath = String.format(MAVEN_FORMAT,
|
||||||
|
groupId.replace('.', '/'),
|
||||||
|
artifactId,
|
||||||
|
version,
|
||||||
|
artifactId,
|
||||||
|
version
|
||||||
|
);
|
||||||
|
|
||||||
|
this.groupId = groupId;
|
||||||
|
this.artifactId = artifactId;
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFileName() {
|
||||||
|
String name = name().toLowerCase().replace('_', '-');
|
||||||
|
|
||||||
|
return String.format("%s-%s.jar", name, this.version);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package dev.xhyrom.lighteco.common.dependencies;
|
||||||
|
|
||||||
|
import dev.xhyrom.lighteco.common.storage.StorageType;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface DependencyManager extends AutoCloseable {
|
||||||
|
void loadDependencies(Set<Dependency> dependencies);
|
||||||
|
|
||||||
|
void loadStorageDependencies(Set<StorageType> types);
|
||||||
|
|
||||||
|
ClassLoader obtainClassLoaderWith(Set<Dependency> dependencies);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void close() throws Exception;
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
package dev.xhyrom.lighteco.common.dependencies;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.io.MoreFiles;
|
||||||
|
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||||
|
import dev.xhyrom.lighteco.common.storage.StorageType;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
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.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
public class DependencyManagerImpl implements DependencyManager {
|
||||||
|
private final EnumMap<Dependency, Path> loaded = new EnumMap<>(Dependency.class);
|
||||||
|
private final Map<ImmutableSet<Dependency>, IsolatedClassLoader> loaders = new HashMap<>();
|
||||||
|
|
||||||
|
private final DependencyRegistry registry;
|
||||||
|
private final Path cacheDirectory;
|
||||||
|
|
||||||
|
public DependencyManagerImpl(LightEcoPlugin plugin) {
|
||||||
|
this.registry = new DependencyRegistry();
|
||||||
|
this.cacheDirectory = setupCacheDirectory(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadDependencies(Set<Dependency> dependencies) {
|
||||||
|
CountDownLatch latch = new CountDownLatch(dependencies.size());
|
||||||
|
|
||||||
|
for (Dependency dependency : dependencies) {
|
||||||
|
if (this.loaded.containsKey(dependency)) {
|
||||||
|
latch.countDown();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletableFuture.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
loadDependency(dependency);
|
||||||
|
} catch (Exception e) {
|
||||||
|
new RuntimeException("Failed to load dependency " + dependency, e);
|
||||||
|
} finally {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadDependency(Dependency dependency) {
|
||||||
|
if (this.loaded.containsKey(dependency)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Path file = downloadDependency(dependency);
|
||||||
|
|
||||||
|
this.loaded.put(dependency, file);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path downloadDependency(Dependency dependency) throws Exception {
|
||||||
|
Path file = this.cacheDirectory.resolve(dependency.getFileName());
|
||||||
|
|
||||||
|
if (Files.exists(file)) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
Files.createDirectories(file.getParent());
|
||||||
|
|
||||||
|
DependencyRepository.MAVEN_CENTRAL.download(dependency, file);
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadStorageDependencies(Set<StorageType> types) {
|
||||||
|
loadDependencies(this.registry.resolveStorageDependencies(types));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader obtainClassLoaderWith(Set<Dependency> dependencies) {
|
||||||
|
ImmutableSet<Dependency> set = ImmutableSet.copyOf(dependencies);
|
||||||
|
|
||||||
|
for (Dependency dependency : dependencies) {
|
||||||
|
if (!this.loaded.containsKey(dependency)) {
|
||||||
|
throw new IllegalStateException("Dependency " + dependency + " is not loaded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (this.loaders) {
|
||||||
|
IsolatedClassLoader classLoader = this.loaders.get(set);
|
||||||
|
if (classLoader != null) {
|
||||||
|
return classLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
URL[] urls = set.stream()
|
||||||
|
.map(this.loaded::get)
|
||||||
|
.map(file -> {
|
||||||
|
try {
|
||||||
|
return file.toUri().toURL();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.toArray(URL[]::new);
|
||||||
|
|
||||||
|
classLoader = new IsolatedClassLoader(urls);
|
||||||
|
this.loaders.put(set, classLoader);
|
||||||
|
return classLoader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Path setupCacheDirectory(LightEcoPlugin plugin) {
|
||||||
|
Path cacheDirectory = plugin.getBootstrap().getDataDirectory().resolve("libraries");
|
||||||
|
|
||||||
|
try {
|
||||||
|
MoreFiles.createParentDirectories(cacheDirectory);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Unable to create libraries (cache) directory", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cacheDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
IOException exception = null;
|
||||||
|
|
||||||
|
for (IsolatedClassLoader loader : this.loaders.values()) {
|
||||||
|
try {
|
||||||
|
loader.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (exception == null) {
|
||||||
|
exception = new IOException("Failed to close class loader", e);
|
||||||
|
} else {
|
||||||
|
exception.addSuppressed(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception != null) {
|
||||||
|
throw new RuntimeException(exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package dev.xhyrom.lighteco.common.dependencies;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSetMultimap;
|
||||||
|
import com.google.common.collect.SetMultimap;
|
||||||
|
import dev.xhyrom.lighteco.common.storage.StorageType;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
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)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public Set<Dependency> resolveStorageDependencies(Set<StorageType> types) {
|
||||||
|
Set<Dependency> dependencies = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
for (StorageType type : types) {
|
||||||
|
dependencies.addAll(STORAGE_DEPENDENCIES.get(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package dev.xhyrom.lighteco.common.dependencies;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public enum DependencyRepository {
|
||||||
|
MAVEN_CENTRAL("https://repo1.maven.org/maven2/");
|
||||||
|
|
||||||
|
private final String url;
|
||||||
|
|
||||||
|
DependencyRepository(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private URLConnection openConnection(Dependency dependency) throws IOException {
|
||||||
|
URL dependencyUrl = new URL(this.url + dependency.getFullPath());
|
||||||
|
return dependencyUrl.openConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] download(Dependency dependency) throws IOException {
|
||||||
|
URLConnection connection = this.openConnection(dependency);
|
||||||
|
connection.connect();
|
||||||
|
|
||||||
|
return connection.getInputStream().readAllBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void download(Dependency dependency, Path file) throws IOException {
|
||||||
|
Files.write(file, this.download(dependency));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package dev.xhyrom.lighteco.common.dependencies;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
|
||||||
|
public class IsolatedClassLoader extends URLClassLoader {
|
||||||
|
static {
|
||||||
|
ClassLoader.registerAsParallelCapable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IsolatedClassLoader(URL[] urls) {
|
||||||
|
super(urls, ClassLoader.getSystemClassLoader().getParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Lot of implementation is from LuckPerms
|
||||||
|
// https://github.com/LuckPerms/LuckPerms/tree/71416baff214802a52f7d26521e6575f71c97fe4/common/src/main/java/me/lucko/luckperms/common/dependencies
|
||||||
|
// Copyright (c) lucko (Luck) <lucko@lucko.me>
|
||||||
|
// Copyright (c) contributors
|
||||||
|
// Under MIT License
|
||||||
|
|
||||||
|
package dev.xhyrom.lighteco.common.dependencies;
|
|
@ -4,6 +4,8 @@ import dev.xhyrom.lighteco.api.LightEco;
|
||||||
import dev.xhyrom.lighteco.api.LightEcoProvider;
|
import dev.xhyrom.lighteco.api.LightEcoProvider;
|
||||||
import dev.xhyrom.lighteco.common.api.LightEcoApi;
|
import dev.xhyrom.lighteco.common.api.LightEcoApi;
|
||||||
import dev.xhyrom.lighteco.common.config.Config;
|
import dev.xhyrom.lighteco.common.config.Config;
|
||||||
|
import dev.xhyrom.lighteco.common.dependencies.DependencyManager;
|
||||||
|
import dev.xhyrom.lighteco.common.dependencies.DependencyManagerImpl;
|
||||||
import dev.xhyrom.lighteco.common.storage.Storage;
|
import dev.xhyrom.lighteco.common.storage.Storage;
|
||||||
import dev.xhyrom.lighteco.common.storage.StorageFactory;
|
import dev.xhyrom.lighteco.common.storage.StorageFactory;
|
||||||
import eu.okaeri.configs.ConfigManager;
|
import eu.okaeri.configs.ConfigManager;
|
||||||
|
@ -14,18 +16,20 @@ import java.io.File;
|
||||||
|
|
||||||
public abstract class AbstractLightEcoPlugin implements LightEcoPlugin {
|
public abstract class AbstractLightEcoPlugin implements LightEcoPlugin {
|
||||||
@Getter
|
@Getter
|
||||||
private Storage storage;
|
private DependencyManager dependencyManager;
|
||||||
private LightEcoApi api;
|
|
||||||
@Getter
|
@Getter
|
||||||
private Config config;
|
private Config config;
|
||||||
|
|
||||||
public final void load() {
|
@Getter
|
||||||
this.config = ConfigManager.create(Config.class, (it) -> {
|
private Storage storage;
|
||||||
File path = new File(this.getBootstrap().getDataFolder(), "config.yml");
|
private LightEcoApi api;
|
||||||
path.mkdir();
|
|
||||||
|
|
||||||
|
public final void load() {
|
||||||
|
this.dependencyManager = new DependencyManagerImpl(this);
|
||||||
|
|
||||||
|
this.config = ConfigManager.create(Config.class, (it) -> {
|
||||||
it.withConfigurer(new YamlSnakeYamlConfigurer());
|
it.withConfigurer(new YamlSnakeYamlConfigurer());
|
||||||
it.withBindFile(path);
|
it.withBindFile(this.getBootstrap().getDataDirectory().resolve("config.yml"));
|
||||||
it.withRemoveOrphans(true);
|
it.withRemoveOrphans(true);
|
||||||
it.saveDefaults();
|
it.saveDefaults();
|
||||||
it.load(true);
|
it.load(true);
|
||||||
|
@ -35,6 +39,8 @@ public abstract class AbstractLightEcoPlugin implements LightEcoPlugin {
|
||||||
public final void enable() {
|
public final void enable() {
|
||||||
// setup storage
|
// setup storage
|
||||||
StorageFactory factory = new StorageFactory(this);
|
StorageFactory factory = new StorageFactory(this);
|
||||||
|
this.dependencyManager.loadStorageDependencies(factory.getRequiredTypes());
|
||||||
|
|
||||||
this.storage = factory.get();
|
this.storage = factory.get();
|
||||||
|
|
||||||
// register listeners
|
// register listeners
|
||||||
|
|
|
@ -3,6 +3,7 @@ package dev.xhyrom.lighteco.common.plugin;
|
||||||
import dev.xhyrom.lighteco.api.manager.ContextManager;
|
import dev.xhyrom.lighteco.api.manager.ContextManager;
|
||||||
import dev.xhyrom.lighteco.api.platform.Platform;
|
import dev.xhyrom.lighteco.api.platform.Platform;
|
||||||
import dev.xhyrom.lighteco.common.config.Config;
|
import dev.xhyrom.lighteco.common.config.Config;
|
||||||
|
import dev.xhyrom.lighteco.common.dependencies.DependencyManager;
|
||||||
import dev.xhyrom.lighteco.common.manager.command.CommandManager;
|
import dev.xhyrom.lighteco.common.manager.command.CommandManager;
|
||||||
import dev.xhyrom.lighteco.common.manager.currency.CurrencyManager;
|
import dev.xhyrom.lighteco.common.manager.currency.CurrencyManager;
|
||||||
import dev.xhyrom.lighteco.common.manager.user.UserManager;
|
import dev.xhyrom.lighteco.common.manager.user.UserManager;
|
||||||
|
@ -21,5 +22,7 @@ public interface LightEcoPlugin {
|
||||||
@NonNull CommandManager getCommandManager();
|
@NonNull CommandManager getCommandManager();
|
||||||
@NonNull ContextManager<?> getContextManager();
|
@NonNull ContextManager<?> getContextManager();
|
||||||
|
|
||||||
|
@NonNull DependencyManager getDependencyManager();
|
||||||
|
|
||||||
@NonNull Storage getStorage();
|
@NonNull Storage getStorage();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package dev.xhyrom.lighteco.common.plugin.bootstrap;
|
||||||
|
|
||||||
import dev.xhyrom.lighteco.common.plugin.logger.PluginLogger;
|
import dev.xhyrom.lighteco.common.plugin.logger.PluginLogger;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -11,7 +10,7 @@ import java.util.UUID;
|
||||||
public interface LightEcoBootstrap {
|
public interface LightEcoBootstrap {
|
||||||
Object getLoader();
|
Object getLoader();
|
||||||
PluginLogger getLogger();
|
PluginLogger getLogger();
|
||||||
File getDataFolder();
|
Path getDataDirectory();
|
||||||
List<UUID> getOnlinePlayers();
|
List<UUID> getOnlinePlayers();
|
||||||
InputStream getResourceStream(String filename);
|
InputStream getResourceStream(String filename);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package dev.xhyrom.lighteco.common.storage;
|
package dev.xhyrom.lighteco.common.storage;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import dev.xhyrom.lighteco.api.storage.StorageProvider;
|
import dev.xhyrom.lighteco.api.storage.StorageProvider;
|
||||||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||||
import dev.xhyrom.lighteco.common.storage.provider.memory.MemoryStorageProvider;
|
import dev.xhyrom.lighteco.common.storage.provider.memory.MemoryStorageProvider;
|
||||||
import dev.xhyrom.lighteco.common.storage.provider.sql.SqlStorageProvider;
|
import dev.xhyrom.lighteco.common.storage.provider.sql.SqlStorageProvider;
|
||||||
|
import dev.xhyrom.lighteco.common.storage.provider.sql.connection.file.H2ConnectionFactory;
|
||||||
import dev.xhyrom.lighteco.common.storage.provider.sql.connection.file.SqliteConnectionFactory;
|
import dev.xhyrom.lighteco.common.storage.provider.sql.connection.file.SqliteConnectionFactory;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class StorageFactory {
|
public class StorageFactory {
|
||||||
private final LightEcoPlugin plugin;
|
private final LightEcoPlugin plugin;
|
||||||
|
|
||||||
|
@ -13,6 +17,10 @@ public class StorageFactory {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<StorageType> getRequiredTypes() {
|
||||||
|
return ImmutableSet.of(StorageType.parse(this.plugin.getConfig().storage.provider));
|
||||||
|
}
|
||||||
|
|
||||||
public Storage get() {
|
public Storage get() {
|
||||||
// todo: use config
|
// todo: use config
|
||||||
String provider = this.plugin.getConfig().storage.provider;
|
String provider = this.plugin.getConfig().storage.provider;
|
||||||
|
@ -27,10 +35,15 @@ public class StorageFactory {
|
||||||
switch (provider.toLowerCase()) {
|
switch (provider.toLowerCase()) {
|
||||||
case "memory":
|
case "memory":
|
||||||
return new MemoryStorageProvider(this.plugin);
|
return new MemoryStorageProvider(this.plugin);
|
||||||
|
case "h2":
|
||||||
|
return new SqlStorageProvider(
|
||||||
|
this.plugin,
|
||||||
|
new H2ConnectionFactory(this.plugin.getBootstrap().getDataDirectory().resolve("lighteco-h2").toAbsolutePath())
|
||||||
|
);
|
||||||
case "sqlite":
|
case "sqlite":
|
||||||
return new SqlStorageProvider(
|
return new SqlStorageProvider(
|
||||||
this.plugin,
|
this.plugin,
|
||||||
new SqliteConnectionFactory(this.plugin.getBootstrap().getDataFolder().toPath().resolve("data.db"))
|
new SqliteConnectionFactory(this.plugin.getBootstrap().getDataDirectory().resolve("lighteco-sqlite.db"))
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown storage provider: " + provider);
|
throw new IllegalArgumentException("Unknown storage provider: " + provider);
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package dev.xhyrom.lighteco.common.storage;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public enum StorageType {
|
||||||
|
MARIADB("MariaDB", "mariadb"),
|
||||||
|
MYSQL("MySQL", "mysql"),
|
||||||
|
|
||||||
|
SQLITE("SQLite", "sqlite"),
|
||||||
|
H2("H2", "h2");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final List<String> identifiers;
|
||||||
|
|
||||||
|
StorageType(String name, String... identifiers) {
|
||||||
|
this.name = name;
|
||||||
|
this.identifiers = List.of(identifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StorageType parse(String name) {
|
||||||
|
return Stream.of(values())
|
||||||
|
.filter(type -> type.identifiers.contains(name.toLowerCase()))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException("Unknown storage type: " + name));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Lot of implementation is from LuckPerms
|
||||||
|
// https://github.com/LuckPerms/LuckPerms/tree/71416baff214802a52f7d26521e6575f71c97fe4/common/src/main/java/me/lucko/luckperms/common/storage
|
||||||
|
// Copyright (c) lucko (Luck) <lucko@lucko.me>
|
||||||
|
// Copyright (c) contributors
|
||||||
|
// Under MIT License
|
||||||
|
|
||||||
|
package dev.xhyrom.lighteco.common.storage.provider;
|
|
@ -1,7 +0,0 @@
|
||||||
package dev.xhyrom.lighteco.common.storage.provider.sql;
|
|
||||||
|
|
||||||
public enum SqlImplementation {
|
|
||||||
H2,
|
|
||||||
SQLITE,
|
|
||||||
MYSQL;
|
|
||||||
}
|
|
|
@ -1,9 +1,11 @@
|
||||||
package dev.xhyrom.lighteco.common.storage.provider.sql;
|
package dev.xhyrom.lighteco.common.storage.provider.sql;
|
||||||
|
|
||||||
|
import dev.xhyrom.lighteco.common.storage.StorageType;
|
||||||
|
|
||||||
public enum SqlStatements {
|
public enum SqlStatements {
|
||||||
SAVE_USER_LOCAL_CURRENCY(
|
SAVE_USER_LOCAL_CURRENCY(
|
||||||
"INSERT INTO {prefix}_users (uuid, currency_identifier, balance) VALUES (?1, ?2, ?3) ON CONFLICT (uuid, currency_identifier) DO UPDATE SET balance=?3;",
|
"INSERT INTO {prefix}_users (uuid, currency_identifier, balance) VALUES (?1, ?2, ?3) ON CONFLICT (uuid, currency_identifier) DO UPDATE SET balance=?3;",
|
||||||
"INSERT INTO {prefix}_{context}_users (uuid, currency_identifier, balance) VALUES (?1, ?2, ?3) ON DUPLICATE KEY UPDATE balance=?3;"
|
"INSERT INTO {prefix}_users (uuid, currency_identifier, balance) VALUES (?1, ?2, ?3) ON DUPLICATE KEY UPDATE balance=?3;"
|
||||||
),
|
),
|
||||||
SAVE_USER_GLOBAL_CURRENCY(
|
SAVE_USER_GLOBAL_CURRENCY(
|
||||||
"INSERT INTO {prefix}_users (uuid, currency_identifier, balance) VALUES (?1, ?2, ?3) ON CONFLICT (uuid, currency_identifier) DO UPDATE SET balance=?3;",
|
"INSERT INTO {prefix}_users (uuid, currency_identifier, balance) VALUES (?1, ?2, ?3) ON CONFLICT (uuid, currency_identifier) DO UPDATE SET balance=?3;",
|
||||||
|
@ -18,12 +20,12 @@ public enum SqlStatements {
|
||||||
this.mysql = mysql;
|
this.mysql = mysql;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String get(SqlImplementation implementationName) {
|
public String get(StorageType implementationName) {
|
||||||
switch (implementationName) {
|
switch (implementationName) {
|
||||||
case SQLITE -> {
|
case SQLITE -> {
|
||||||
return this.sqlite;
|
return this.sqlite;
|
||||||
}
|
}
|
||||||
case MYSQL -> {
|
case H2, MYSQL -> {
|
||||||
return this.mysql;
|
return this.mysql;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import dev.xhyrom.lighteco.api.model.user.User;
|
||||||
import dev.xhyrom.lighteco.api.storage.StorageProvider;
|
import dev.xhyrom.lighteco.api.storage.StorageProvider;
|
||||||
import dev.xhyrom.lighteco.common.model.currency.Currency;
|
import dev.xhyrom.lighteco.common.model.currency.Currency;
|
||||||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||||
|
import dev.xhyrom.lighteco.common.storage.StorageType;
|
||||||
import dev.xhyrom.lighteco.common.storage.provider.sql.connection.ConnectionFactory;
|
import dev.xhyrom.lighteco.common.storage.provider.sql.connection.ConnectionFactory;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ public class SqlStorageProvider implements StorageProvider {
|
||||||
.replace("{context}", plugin.getConfig().server)
|
.replace("{context}", plugin.getConfig().server)
|
||||||
);
|
);
|
||||||
|
|
||||||
final SqlImplementation implementationName = this.connectionFactory.getImplementationName();
|
final StorageType implementationName = this.connectionFactory.getImplementationName();
|
||||||
this.SAVE_USER_LOCAL_CURRENCY = SqlStatements.SAVE_USER_LOCAL_CURRENCY.get(implementationName);
|
this.SAVE_USER_LOCAL_CURRENCY = SqlStatements.SAVE_USER_LOCAL_CURRENCY.get(implementationName);
|
||||||
this.SAVE_USER_GLOBAL_CURRENCY = SqlStatements.SAVE_USER_GLOBAL_CURRENCY.get(implementationName);
|
this.SAVE_USER_GLOBAL_CURRENCY = SqlStatements.SAVE_USER_GLOBAL_CURRENCY.get(implementationName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package dev.xhyrom.lighteco.common.storage.provider.sql.connection;
|
package dev.xhyrom.lighteco.common.storage.provider.sql.connection;
|
||||||
|
|
||||||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||||
import dev.xhyrom.lighteco.common.storage.provider.sql.SqlImplementation;
|
import dev.xhyrom.lighteco.common.storage.StorageType;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public interface ConnectionFactory {
|
public interface ConnectionFactory {
|
||||||
SqlImplementation getImplementationName();
|
StorageType getImplementationName();
|
||||||
|
|
||||||
void init(LightEcoPlugin plugin);
|
void init(LightEcoPlugin plugin);
|
||||||
void shutdown() throws Exception;
|
void shutdown() throws Exception;
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
package dev.xhyrom.lighteco.common.storage.provider.sql.connection.file;
|
package dev.xhyrom.lighteco.common.storage.provider.sql.connection.file;
|
||||||
|
|
||||||
|
import dev.xhyrom.lighteco.common.dependencies.Dependency;
|
||||||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||||
import dev.xhyrom.lighteco.common.storage.provider.sql.SqlImplementation;
|
import dev.xhyrom.lighteco.common.storage.StorageType;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
@ -19,21 +20,27 @@ public class H2ConnectionFactory extends FileConnectionFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqlImplementation getImplementationName() {
|
public StorageType getImplementationName() {
|
||||||
return SqlImplementation.H2;
|
return StorageType.H2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(LightEcoPlugin plugin) {
|
public void init(LightEcoPlugin plugin) {
|
||||||
// TODO: implement
|
ClassLoader classLoader = plugin.getDependencyManager().obtainClassLoaderWith(EnumSet.of(Dependency.H2_DRIVER));
|
||||||
//ClassLoader classLoader = plugin
|
|
||||||
|
try {
|
||||||
|
Class<?> connectionClass = classLoader.loadClass("org.h2.jdbc.JdbcConnection");
|
||||||
|
this.connectionConstructor = connectionClass.getConstructor(String.class, Properties.class, String.class, Object.class, boolean.class);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Connection createConnection(Path file) throws SQLException {
|
protected Connection createConnection(Path file) throws SQLException {
|
||||||
try {
|
try {
|
||||||
return (Connection) this.connectionConstructor.newInstance(
|
return (Connection) this.connectionConstructor.newInstance(
|
||||||
"jdbc:h2:" + file,
|
"jdbc:h2:" + file.toString() + ";MODE=MySQL;DATABASE_TO_LOWER=TRUE",
|
||||||
new Properties(),
|
new Properties(),
|
||||||
null, null, false
|
null, null, false
|
||||||
);
|
);
|
||||||
|
@ -45,4 +52,13 @@ public class H2ConnectionFactory extends FileConnectionFactory {
|
||||||
throw new SQLException("Failed to create connection", e);
|
throw new SQLException("Failed to create connection", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Function<String, String> getStatementProcessor() {
|
||||||
|
return s -> s
|
||||||
|
.replace('\'', '`')
|
||||||
|
.replace("LIKE", "ILIKE")
|
||||||
|
.replace("value", "`value`")
|
||||||
|
.replace("``value``", "`value`");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
package dev.xhyrom.lighteco.common.storage.provider.sql.connection.file;
|
package dev.xhyrom.lighteco.common.storage.provider.sql.connection.file;
|
||||||
|
|
||||||
|
import dev.xhyrom.lighteco.common.dependencies.Dependency;
|
||||||
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||||
import dev.xhyrom.lighteco.common.storage.provider.sql.SqlImplementation;
|
import dev.xhyrom.lighteco.common.storage.StorageType;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
public class SqliteConnectionFactory extends FileConnectionFactory {
|
public class SqliteConnectionFactory extends FileConnectionFactory {
|
||||||
private Constructor<?> connectionConstructor;
|
private Constructor<?> connectionConstructor;
|
||||||
|
@ -17,31 +20,30 @@ public class SqliteConnectionFactory extends FileConnectionFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqlImplementation getImplementationName() {
|
public StorageType getImplementationName() {
|
||||||
return SqlImplementation.SQLITE;
|
return StorageType.SQLITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(LightEcoPlugin plugin) {
|
public void init(LightEcoPlugin plugin) {
|
||||||
/*ClassLoader classLoader = ClassLoader.getSystemClassLoader();
|
ClassLoader classLoader = plugin.getDependencyManager().obtainClassLoaderWith(EnumSet.of(Dependency.SQLITE_DRIVER));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Class<?> connectionClass = classLoader.loadClass("org.sqlite.jdbc4.JDBC4Connection");
|
Class<?> connectionClass = classLoader.loadClass("org.sqlite.jdbc4.JDBC4Connection");
|
||||||
this.connectionConstructor = connectionClass.getConstructor(String.class, String.class, Properties.class);
|
this.connectionConstructor = connectionClass.getConstructor(String.class, String.class, Properties.class);
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (ReflectiveOperationException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Connection createConnection(Path file) throws SQLException {
|
protected Connection createConnection(Path file) throws SQLException {
|
||||||
try {
|
try {
|
||||||
/*return (Connection) this.connectionConstructor.newInstance(
|
return (Connection) this.connectionConstructor.newInstance(
|
||||||
"jdbc:sqlite:" + file,
|
"jdbc:sqlite:" + file,
|
||||||
new Properties(),
|
file.toString(),
|
||||||
null, null, false
|
new Properties()
|
||||||
);*/
|
);
|
||||||
return DriverManager.getConnection("jdbc:sqlite:" + file);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e.getCause() instanceof SQLException) {
|
if (e.getCause() instanceof SQLException) {
|
||||||
throw (SQLException) e.getCause();
|
throw (SQLException) e.getCause();
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package dev.xhyrom.lighteco.common.storage.provider.sql.connection.hikari;
|
||||||
|
|
||||||
|
import dev.xhyrom.lighteco.common.plugin.LightEcoPlugin;
|
||||||
|
import dev.xhyrom.lighteco.common.storage.StorageType;
|
||||||
|
import dev.xhyrom.lighteco.common.storage.provider.sql.connection.ConnectionFactory;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class HikariConnectionFactory implements ConnectionFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StorageType getImplementationName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(LightEcoPlugin plugin) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown() throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Function<String, String> getStatementProcessor() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Connection getConnection() throws Exception {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
13
common/src/main/resources/schema/h2.sql
Normal file
13
common/src/main/resources/schema/h2.sql
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS `{prefix}_users` (
|
||||||
|
`uuid` VARCHAR(36) NOT NULL,
|
||||||
|
`currency_identifier` VARCHAR(255) NOT NULL,
|
||||||
|
`balance` DECIMAL(10, 2) NOT NULL,
|
||||||
|
PRIMARY KEY (`uuid`, `currency_identifier`)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `{prefix}_{context}_users` (
|
||||||
|
`uuid` VARCHAR(36) NOT NULL,
|
||||||
|
`currency_identifier` VARCHAR(255) NOT NULL,
|
||||||
|
`balance` DECIMAL(10, 2) NOT NULL,
|
||||||
|
PRIMARY KEY (`uuid`, `currency_identifier`)
|
||||||
|
);
|
Loading…
Reference in a new issue